@woosh/meep-engine 3.5.0 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/core/geom/3d/gjk/gjk_epa_penetration.d.ts +30 -3
- package/src/core/geom/3d/gjk/gjk_epa_penetration.d.ts.map +1 -1
- package/src/core/geom/3d/gjk/gjk_epa_penetration.js +83 -10
- package/src/core/geom/3d/gjk/mpr.d.ts +7 -1
- package/src/core/geom/3d/gjk/mpr.d.ts.map +1 -1
- package/src/core/geom/3d/gjk/mpr.js +76 -13
- package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/narrowphase_step.js +20 -2
- package/src/shade/renderer/scene/bvh/StaticSceneBVH.js +4 -4
- package/src/engine/graphics/sh3/build_injected_shader.d.ts +0 -51
- package/src/engine/graphics/sh3/build_injected_shader.d.ts.map +0 -1
- package/src/engine/graphics/sh3/build_injected_shader.js +0 -56
- package/src/engine/graphics/sh3/fromCubeRenderTarget.d.ts +0 -9
- package/src/engine/graphics/sh3/fromCubeRenderTarget.d.ts.map +0 -1
- package/src/engine/graphics/sh3/fromCubeRenderTarget.js +0 -142
- package/src/engine/graphics/sh3/shader/visualize.frag.d.ts +0 -3
- package/src/engine/graphics/sh3/shader/visualize.frag.d.ts.map +0 -1
- package/src/engine/graphics/sh3/shader/visualize.frag.js +0 -51
- package/src/engine/graphics/sh3/shader/visualize.vert.d.ts +0 -3
- package/src/engine/graphics/sh3/shader/visualize.vert.d.ts.map +0 -1
- package/src/engine/graphics/sh3/shader/visualize.vert.js +0 -12
package/package.json
CHANGED
|
@@ -3,15 +3,42 @@
|
|
|
3
3
|
* Writes the unit separation normal (A→B: the direction A must move along
|
|
4
4
|
* NEGATED to separate — equivalently, negate `out` for the B→A push axis;
|
|
5
5
|
* the narrowphase sign-check sites canonicalise it against the body centres)
|
|
6
|
-
* into `out` and returns the depth
|
|
7
|
-
*
|
|
6
|
+
* into `out` and returns the depth. `out` is untouched unless the return is
|
|
7
|
+
* positive.
|
|
8
8
|
*
|
|
9
9
|
* @param {Float64Array|number[]} out destination for the unit normal, length ≥ 3
|
|
10
10
|
* @param {SupportProvider} A world-space support provider (e.g. PosedShape3D)
|
|
11
11
|
* @param {SupportProvider} B world-space support provider (e.g. PosedShape3D)
|
|
12
|
-
* @returns {number} penetration depth
|
|
12
|
+
* @returns {number} the penetration depth (> 0) on overlap;
|
|
13
|
+
* {@link GJK_SEPARATED} when GJK PROVED the shapes apart; `0` for no usable
|
|
14
|
+
* axis — EPA degenerated on an established overlap, or GJK reached no
|
|
15
|
+
* verdict at all. `0` is not a separation and callers with a fallback
|
|
16
|
+
* should still run it
|
|
13
17
|
*/
|
|
14
18
|
export function gjk_epa_penetration(out: Float64Array | number[], A: SupportProvider, B: SupportProvider): number;
|
|
19
|
+
/**
|
|
20
|
+
* Sentinel returned by {@link gjk_epa_penetration} when GJK PROVED the shapes
|
|
21
|
+
* apart — {@link GJK_APART}, a support plane with the whole Minkowski
|
|
22
|
+
* difference on the far side of the origin — as distinct from `0`, "no usable
|
|
23
|
+
* axis": a degenerate EPA, or a GJK that reached no verdict at all.
|
|
24
|
+
*
|
|
25
|
+
* The two need separate values because callers act on them differently. A
|
|
26
|
+
* proof of separation is the final answer and the pair is done; the rest is a
|
|
27
|
+
* gap in this query that a fallback (MPR) may still be able to fill. Note the
|
|
28
|
+
* asymmetry — this is claimed ONLY from the proof, never from GJK's other two
|
|
29
|
+
* non-overlap exits, which are inconclusive rather than negative.
|
|
30
|
+
* Collapsing both to `0`, as this function used to, sent every non-touching
|
|
31
|
+
* pair the broadphase produced into that fallback — where MPR, whose portal
|
|
32
|
+
* argument assumes an overlap it was never told to doubt, answered a question
|
|
33
|
+
* GJK had already settled and reported the gap as a penetration of its own
|
|
34
|
+
* size (see the separating-plane certificate in {@link mpr}).
|
|
35
|
+
*
|
|
36
|
+
* Negative so that the existing `depth > 0` guard at every call site keeps
|
|
37
|
+
* rejecting it unchanged.
|
|
38
|
+
*
|
|
39
|
+
* @type {number}
|
|
40
|
+
*/
|
|
41
|
+
export const GJK_SEPARATED: number;
|
|
15
42
|
/**
|
|
16
43
|
* A convex shape exposing a world-space support mapping: `support(out, off, dx,
|
|
17
44
|
* dy, dz)` writes the farthest point of the shape in direction `(dx, dy, dz)`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gjk_epa_penetration.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/3d/gjk/gjk_epa_penetration.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"gjk_epa_penetration.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/3d/gjk/gjk_epa_penetration.js"],"names":[],"mappings":"AA2iBA;;;;;;;;;;;;;;;;GAgBG;AACH,yCATW,YAAY,GAAC,MAAM,EAAE,KACrB,eAAe,KACf,eAAe,GACb,MAAM,CA0BlB;AA7DD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,4BAFU,MAAM,CAEgB;;;;;;8BAzdnB;IAAE,OAAO,SAAW,YAAY,QAAE,MAAM,QAAE,MAAM,QAAE,MAAM,QAAE,MAAM,KAAG,IAAI,CAAA;CAAE"}
|
|
@@ -81,14 +81,45 @@ const CEN = new Float64Array(3); // polytope centroid (for outward orientation)
|
|
|
81
81
|
* @typedef {{ support: function(Float64Array, number, number, number, number): void }} SupportProvider
|
|
82
82
|
*/
|
|
83
83
|
|
|
84
|
+
/**
|
|
85
|
+
* {@link gjk} enclosed the origin: the shapes overlap and {@link SIMPLEX} holds
|
|
86
|
+
* a rank-4 simplex EPA can expand from.
|
|
87
|
+
* @type {number}
|
|
88
|
+
*/
|
|
89
|
+
const GJK_ENCLOSED = 4;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* {@link gjk} found a support plane with the whole Minkowski difference on the
|
|
93
|
+
* far side of the origin. That is a proof of separation, and the only one of
|
|
94
|
+
* this function's non-overlap exits that is.
|
|
95
|
+
* @type {number}
|
|
96
|
+
*/
|
|
97
|
+
const GJK_APART = -1;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* {@link gjk} ran out of road: the search direction collapsed, or the iteration
|
|
101
|
+
* cap hit. Neither says the shapes are apart — the direction collapses when the
|
|
102
|
+
* origin lands exactly ON a simplex feature, which is a TOUCH (two spheres at
|
|
103
|
+
* exactly 2r do this), and the cap is just non-convergence on a smooth support.
|
|
104
|
+
* Callers must treat it as "no answer" and keep whatever fallback they have.
|
|
105
|
+
* @type {number}
|
|
106
|
+
*/
|
|
107
|
+
const GJK_INCONCLUSIVE = 0;
|
|
108
|
+
|
|
84
109
|
/**
|
|
85
110
|
* GJK intersection. Fills {@link SIMPLEX} with a rank-4 simplex enclosing the
|
|
86
|
-
* origin and returns
|
|
111
|
+
* origin and returns {@link GJK_ENCLOSED} on overlap.
|
|
87
112
|
* `SIMPLEX` slot 0 is the most-recent point throughout (Muratori convention).
|
|
88
113
|
*
|
|
114
|
+
* The two non-overlap verdicts are deliberately distinct: only
|
|
115
|
+
* {@link GJK_APART} is a proof, and collapsing it together with
|
|
116
|
+
* {@link GJK_INCONCLUSIVE} silently converts "I could not tell" into "they are
|
|
117
|
+
* not touching" — which drops touching contacts.
|
|
118
|
+
*
|
|
89
119
|
* @param {SupportProvider} A first support provider
|
|
90
120
|
* @param {SupportProvider} B second support provider
|
|
91
|
-
* @returns {number}
|
|
121
|
+
* @returns {number} {@link GJK_ENCLOSED}, {@link GJK_APART}, or
|
|
122
|
+
* {@link GJK_INCONCLUSIVE}
|
|
92
123
|
*/
|
|
93
124
|
function gjk(A, B) {
|
|
94
125
|
minkowski_support(SIMPLEX, 0, A, B, 1, 0, 0);
|
|
@@ -102,11 +133,11 @@ function gjk(A, B) {
|
|
|
102
133
|
|
|
103
134
|
for (let iter = 0; iter < GJK_MAX_ITER; iter++) {
|
|
104
135
|
if (v3_length_sqr(DIR[0], DIR[1], DIR[2]) < DIR_EPS) {
|
|
105
|
-
return
|
|
136
|
+
return GJK_INCONCLUSIVE; // direction collapsed → touching, or apart; unknown
|
|
106
137
|
}
|
|
107
138
|
minkowski_support(_w, 0, A, B, DIR[0], DIR[1], DIR[2]);
|
|
108
139
|
if (v3_dot(_w[0], _w[1], _w[2], DIR[0], DIR[1], DIR[2]) < 0) {
|
|
109
|
-
return
|
|
140
|
+
return GJK_APART; // farthest point short of the origin → proven separated
|
|
110
141
|
}
|
|
111
142
|
// push the new point to slot 0, shifting the existing points down one slot
|
|
112
143
|
// (copyWithin is memmove-style: the overlapping forward copy is well-defined)
|
|
@@ -118,10 +149,10 @@ function gjk(A, B) {
|
|
|
118
149
|
|
|
119
150
|
count = do_simplex(count);
|
|
120
151
|
if (count === 0) {
|
|
121
|
-
return
|
|
152
|
+
return GJK_ENCLOSED; // origin enclosed by the tetrahedron
|
|
122
153
|
}
|
|
123
154
|
}
|
|
124
|
-
return
|
|
155
|
+
return GJK_INCONCLUSIVE; // iteration cap → non-convergent, not a separation
|
|
125
156
|
}
|
|
126
157
|
|
|
127
158
|
/**
|
|
@@ -498,23 +529,65 @@ function epa(A, B, out) {
|
|
|
498
529
|
return FACE_DIST[best];
|
|
499
530
|
}
|
|
500
531
|
|
|
532
|
+
/**
|
|
533
|
+
* Sentinel returned by {@link gjk_epa_penetration} when GJK PROVED the shapes
|
|
534
|
+
* apart — {@link GJK_APART}, a support plane with the whole Minkowski
|
|
535
|
+
* difference on the far side of the origin — as distinct from `0`, "no usable
|
|
536
|
+
* axis": a degenerate EPA, or a GJK that reached no verdict at all.
|
|
537
|
+
*
|
|
538
|
+
* The two need separate values because callers act on them differently. A
|
|
539
|
+
* proof of separation is the final answer and the pair is done; the rest is a
|
|
540
|
+
* gap in this query that a fallback (MPR) may still be able to fill. Note the
|
|
541
|
+
* asymmetry — this is claimed ONLY from the proof, never from GJK's other two
|
|
542
|
+
* non-overlap exits, which are inconclusive rather than negative.
|
|
543
|
+
* Collapsing both to `0`, as this function used to, sent every non-touching
|
|
544
|
+
* pair the broadphase produced into that fallback — where MPR, whose portal
|
|
545
|
+
* argument assumes an overlap it was never told to doubt, answered a question
|
|
546
|
+
* GJK had already settled and reported the gap as a penetration of its own
|
|
547
|
+
* size (see the separating-plane certificate in {@link mpr}).
|
|
548
|
+
*
|
|
549
|
+
* Negative so that the existing `depth > 0` guard at every call site keeps
|
|
550
|
+
* rejecting it unchanged.
|
|
551
|
+
*
|
|
552
|
+
* @type {number}
|
|
553
|
+
*/
|
|
554
|
+
export const GJK_SEPARATED = -1;
|
|
555
|
+
|
|
501
556
|
/**
|
|
502
557
|
* Penetration depth + normal between two convex support providers at world pose.
|
|
503
558
|
* Writes the unit separation normal (A→B: the direction A must move along
|
|
504
559
|
* NEGATED to separate — equivalently, negate `out` for the B→A push axis;
|
|
505
560
|
* the narrowphase sign-check sites canonicalise it against the body centres)
|
|
506
|
-
* into `out` and returns the depth
|
|
507
|
-
*
|
|
561
|
+
* into `out` and returns the depth. `out` is untouched unless the return is
|
|
562
|
+
* positive.
|
|
508
563
|
*
|
|
509
564
|
* @param {Float64Array|number[]} out destination for the unit normal, length ≥ 3
|
|
510
565
|
* @param {SupportProvider} A world-space support provider (e.g. PosedShape3D)
|
|
511
566
|
* @param {SupportProvider} B world-space support provider (e.g. PosedShape3D)
|
|
512
|
-
* @returns {number} penetration depth
|
|
567
|
+
* @returns {number} the penetration depth (> 0) on overlap;
|
|
568
|
+
* {@link GJK_SEPARATED} when GJK PROVED the shapes apart; `0` for no usable
|
|
569
|
+
* axis — EPA degenerated on an established overlap, or GJK reached no
|
|
570
|
+
* verdict at all. `0` is not a separation and callers with a fallback
|
|
571
|
+
* should still run it
|
|
513
572
|
*/
|
|
514
573
|
export function gjk_epa_penetration(out, A, B) {
|
|
515
|
-
|
|
574
|
+
const verdict = gjk(A, B);
|
|
575
|
+
|
|
576
|
+
if (verdict === GJK_APART) {
|
|
577
|
+
return GJK_SEPARATED;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
if (verdict !== GJK_ENCLOSED) {
|
|
581
|
+
// GJK_INCONCLUSIVE — no simplex to expand and no proof of separation
|
|
582
|
+
// either, so this reports the same "no usable axis" as a degenerate
|
|
583
|
+
// EPA and leaves the caller's fallback in play. Reporting it as
|
|
584
|
+
// GJK_SEPARATED would be an overclaim, and an expensive one: the
|
|
585
|
+
// collapse exit fires on EXACTLY touching pairs (two spheres at 2r),
|
|
586
|
+
// whose resting contact would then be dropped without anything ever
|
|
587
|
+
// looking at the geometry.
|
|
516
588
|
return 0;
|
|
517
589
|
}
|
|
590
|
+
|
|
518
591
|
const depth = epa(A, B, out);
|
|
519
592
|
return depth > 0 && Number.isFinite(depth) ? depth : 0;
|
|
520
593
|
}
|
|
@@ -39,7 +39,13 @@
|
|
|
39
39
|
* any narrowphase call site.
|
|
40
40
|
*
|
|
41
41
|
* On failure modes:
|
|
42
|
-
* - Returns `false` if the shapes don't overlap
|
|
42
|
+
* - Returns `false` if the shapes don't overlap, decided by a
|
|
43
|
+
* separating-plane certificate — the support of the Mink-diff along
|
|
44
|
+
* the portal normal fails to reach the origin — which is one exact
|
|
45
|
+
* evaluation carrying none of the refinement's error. A miss leaves
|
|
46
|
+
* `result` untouched: the separation distance is deliberately NOT
|
|
47
|
+
* written, because every caller reads the depth as |MTV| and cannot
|
|
48
|
+
* tell a gap from a penetration once the sign is gone.
|
|
43
49
|
* - On a degenerate Mink-diff (shapes touching at a point, perfectly
|
|
44
50
|
* coincident centres with collinear support points), returns
|
|
45
51
|
* `true` with a small fallback MTV — same approach as EPA's
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mpr.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/3d/gjk/mpr.js"],"names":[],"mappings":"AAsDA
|
|
1
|
+
{"version":3,"file":"mpr.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/3d/gjk/mpr.js"],"names":[],"mappings":"AAsDA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AACH,4BANW,YAAY,iBACZ,MAAM,iDAGJ,OAAO,CA8TnB"}
|
|
@@ -93,7 +93,13 @@ const V4 = new Float64Array(3);
|
|
|
93
93
|
* any narrowphase call site.
|
|
94
94
|
*
|
|
95
95
|
* On failure modes:
|
|
96
|
-
* - Returns `false` if the shapes don't overlap
|
|
96
|
+
* - Returns `false` if the shapes don't overlap, decided by a
|
|
97
|
+
* separating-plane certificate — the support of the Mink-diff along
|
|
98
|
+
* the portal normal fails to reach the origin — which is one exact
|
|
99
|
+
* evaluation carrying none of the refinement's error. A miss leaves
|
|
100
|
+
* `result` untouched: the separation distance is deliberately NOT
|
|
101
|
+
* written, because every caller reads the depth as |MTV| and cannot
|
|
102
|
+
* tell a gap from a penetration once the sign is gone.
|
|
97
103
|
* - On a degenerate Mink-diff (shapes touching at a point, perfectly
|
|
98
104
|
* coincident centres with collinear support points), returns
|
|
99
105
|
* `true` with a small fallback MTV — same approach as EPA's
|
|
@@ -116,6 +122,17 @@ export function mpr(result, result_offset, shape_a, shape_b) {
|
|
|
116
122
|
// origins are interior to their geometry — true for spheres,
|
|
117
123
|
// boxes, capsules, and any closed mesh whose bounding box contains
|
|
118
124
|
// its centroid.
|
|
125
|
+
//
|
|
126
|
+
// This is a PRECONDITION, not a preference, and nothing here can
|
|
127
|
+
// check it: every argument below assumes the ray V0→origin starts
|
|
128
|
+
// inside. An authored ConvexHullShape3D whose vertices sit far from
|
|
129
|
+
// its own local origin (a level brush keeping map coordinates under
|
|
130
|
+
// an identity collider transform, say) violates it, and MPR then
|
|
131
|
+
// returns a confidently wrong MTV — measured at 17.8 m, the slab's
|
|
132
|
+
// half-width, for a 0.05 m overlap. Callers that can answer overlap
|
|
133
|
+
// some other way should do so and reach for MPR only when that
|
|
134
|
+
// answer is genuinely unavailable; {@link narrowphase_step} keeps it
|
|
135
|
+
// behind a GJK verdict for exactly this reason.
|
|
119
136
|
V0[0] = shape_a.px - shape_b.px;
|
|
120
137
|
V0[1] = shape_a.py - shape_b.py;
|
|
121
138
|
V0[2] = shape_a.pz - shape_b.pz;
|
|
@@ -281,10 +298,22 @@ export function mpr(result, result_offset, shape_a, shape_b) {
|
|
|
281
298
|
const inv_pn = 1 / Math.sqrt(pn_len_sqr);
|
|
282
299
|
pn_x *= inv_pn; pn_y *= inv_pn; pn_z *= inv_pn;
|
|
283
300
|
|
|
284
|
-
//
|
|
285
|
-
// = dot(V1, portal_normal)
|
|
286
|
-
//
|
|
287
|
-
//
|
|
301
|
+
// Signed offset of the portal plane from the origin along the
|
|
302
|
+
// outward normal, = dot(V1, portal_normal), and the depth this
|
|
303
|
+
// returns once the portal settles. In exact arithmetic its sign
|
|
304
|
+
// would also BE the overlap test — V0 is interior and the ray
|
|
305
|
+
// V0→origin pierces the portal, so the origin is inside the
|
|
306
|
+
// Mink-diff exactly when it lies on V0's side of that plane —
|
|
307
|
+
// and a negative value would mean the ray left the Mink-diff
|
|
308
|
+
// before reaching the origin, making |portal_dist| a SEPARATION
|
|
309
|
+
// rather than a depth.
|
|
310
|
+
//
|
|
311
|
+
// It is not the test used, because this is an iterate: near zero
|
|
312
|
+
// its sign is refinement noise, not geometry. The certificate
|
|
313
|
+
// below decides instead, and getting a magnitude out of a
|
|
314
|
+
// separated pair — which every caller then reads as a depth,
|
|
315
|
+
// |MTV| having thrown the sign away — is the failure that made
|
|
316
|
+
// this loop worth re-deriving.
|
|
288
317
|
const portal_dist = V1[0] * pn_x + V1[1] * pn_y + V1[2] * pn_z;
|
|
289
318
|
|
|
290
319
|
// New support V4 in the portal normal direction.
|
|
@@ -292,8 +321,41 @@ export function mpr(result, result_offset, shape_a, shape_b) {
|
|
|
292
321
|
|
|
293
322
|
const v4_dist = V4[0] * pn_x + V4[1] * pn_y + V4[2] * pn_z;
|
|
294
323
|
|
|
324
|
+
// Separating-plane certificate — and it has to be tested BEFORE
|
|
325
|
+
// the convergence branch below. If the farthest point of the
|
|
326
|
+
// Mink-diff along pn does not reach the origin, the plane
|
|
327
|
+
// through the origin with normal pn separates the two shapes,
|
|
328
|
+
// which is a proof of a miss. It can never reject a true
|
|
329
|
+
// overlap: the origin is then inside the Mink-diff, whose
|
|
330
|
+
// support is ≥ 0 in EVERY direction.
|
|
331
|
+
//
|
|
332
|
+
// The order is the whole point. A small shape near a large flat
|
|
333
|
+
// face seeds a portal already within MPR_TOLERANCE of the
|
|
334
|
+
// support plane, so the convergence test succeeds on the first
|
|
335
|
+
// iteration and this proof was never reached — the old order
|
|
336
|
+
// returned `true` with a negative portal_dist, and callers
|
|
337
|
+
// (which read the depth as |MTV|) saw the gap as a penetration
|
|
338
|
+
// of exactly its own size.
|
|
339
|
+
if (v4_dist < 0) {
|
|
340
|
+
return false;
|
|
341
|
+
}
|
|
342
|
+
|
|
295
343
|
// Convergence: V4 doesn't extend the portal beyond the current
|
|
296
|
-
// face (within tolerance)
|
|
344
|
+
// face (within tolerance), so the portal face is the closest
|
|
345
|
+
// face of the Mink-diff and its offset is the depth.
|
|
346
|
+
//
|
|
347
|
+
// Note what does NOT appear here: a `portal_dist <= 0` gate. It
|
|
348
|
+
// is tempting — a negative offset is exactly what a miss looks
|
|
349
|
+
// like — but portal_dist is the one quantity in this loop that
|
|
350
|
+
// carries the refinement's error, and near zero that error is
|
|
351
|
+
// the whole signal. A capsule resting exactly on a floor
|
|
352
|
+
// converges at portal_dist ≈ −3e-6 with v4_dist ≈ +2.5e-6: a
|
|
353
|
+
// real touching contact whose sign is pure noise, which such a
|
|
354
|
+
// gate drops, taking the resting contact with it. The certificate
|
|
355
|
+
// above is error-free (one exact support evaluation) and is the
|
|
356
|
+
// right arbiter; by the time it passes, convergence bounds
|
|
357
|
+
// portal_dist below at −MPR_TOLERANCE, which is the same
|
|
358
|
+
// accuracy the depth itself is quoted to.
|
|
297
359
|
if (v4_dist - portal_dist < MPR_TOLERANCE) {
|
|
298
360
|
result[result_offset] = pn_x * portal_dist;
|
|
299
361
|
result[result_offset + 1] = pn_y * portal_dist;
|
|
@@ -301,13 +363,6 @@ export function mpr(result, result_offset, shape_a, shape_b) {
|
|
|
301
363
|
return true;
|
|
302
364
|
}
|
|
303
365
|
|
|
304
|
-
// V4 didn't pass the origin along the portal normal — the
|
|
305
|
-
// shapes aren't actually overlapping (shouldn't happen after
|
|
306
|
-
// successful portal discovery, but defensive).
|
|
307
|
-
if (v4_dist < 0) {
|
|
308
|
-
return false;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
366
|
// Replace one of V1, V2, V3 with V4 such that the new portal
|
|
312
367
|
// still contains the V0→origin ray. The split is determined by
|
|
313
368
|
// three cross-product / dot tests against V4 × V0: signs of
|
|
@@ -360,6 +415,14 @@ export function mpr(result, result_offset, shape_a, shape_b) {
|
|
|
360
415
|
}
|
|
361
416
|
const inv_pn = 1 / Math.sqrt(pn_len_sqr);
|
|
362
417
|
pn_x *= inv_pn; pn_y *= inv_pn; pn_z *= inv_pn;
|
|
418
|
+
// The portal never settled, so this face is a guess — but the
|
|
419
|
+
// separating-plane certificate costs one support call and holds
|
|
420
|
+
// regardless of how the refinement terminated. Apply the same rule
|
|
421
|
+
// both exits use rather than emitting an unexamined MTV.
|
|
422
|
+
minkowski_support(V4, 0, shape_a, shape_b, pn_x, pn_y, pn_z);
|
|
423
|
+
if (V4[0] * pn_x + V4[1] * pn_y + V4[2] * pn_z < 0) {
|
|
424
|
+
return false;
|
|
425
|
+
}
|
|
363
426
|
const portal_dist = V1[0] * pn_x + V1[1] * pn_y + V1[2] * pn_z;
|
|
364
427
|
result[result_offset] = pn_x * portal_dist;
|
|
365
428
|
result[result_offset + 1] = pn_y * portal_dist;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"narrowphase_step.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/narrowphase/narrowphase_step.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"narrowphase_step.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/narrowphase/narrowphase_step.js"],"names":[],"mappings":"AA2zCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,qDAVW,YAAY,GAAC,MAAM,EAAE,iCAGrB;IAAC,CAAC,EAAC,MAAM,CAAC;IAAA,CAAC,EAAC,MAAM,CAAC;IAAA,CAAC,EAAC,MAAM,CAAA;CAAC,QAC5B;IAAC,CAAC,EAAC,MAAM,CAAC;IAAA,CAAC,EAAC,MAAM,CAAC;IAAA,CAAC,EAAC,MAAM,CAAC;IAAA,CAAC,EAAC,MAAM,CAAA;CAAC,iCAErC;IAAC,CAAC,EAAC,MAAM,CAAC;IAAA,CAAC,EAAC,MAAM,CAAC;IAAA,CAAC,EAAC,MAAM,CAAA;CAAC,QAC5B;IAAC,CAAC,EAAC,MAAM,CAAC;IAAA,CAAC,EAAC,MAAM,CAAC;IAAA,CAAC,EAAC,MAAM,CAAC;IAAA,CAAC,EAAC,MAAM,CAAA;CAAC,GACnC,MAAM,CAuClB;AAED;;;;;;;;;;;GAWG;AACH,uFALW,MAAM,MAAM;IAAC,QAAQ,WAAW;IAAC,SAAS,YAAW;CAAC,CAAC,CAAC,QA4LlE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,uEAJW,MAAM,UACN,MAAM;IAAC,QAAQ,WAAW;IAAC,SAAS,YAAW;CAAC,CAAC,UACjD,MAAM;IAAC,QAAQ,WAAW;IAAC,SAAS,YAAW;CAAC,CAAC,QA2H3D"}
|
|
@@ -3,7 +3,7 @@ import { Triangle3D } from "../../../core/geom/3d/shape/Triangle3D.js";
|
|
|
3
3
|
import { body_id_index } from "../body/BodyStorage.js";
|
|
4
4
|
import { combine_friction, combine_restitution } from "../contact/combine_material.js";
|
|
5
5
|
import { CONTACT_STRIDE, MAX_CONTACTS_PER_MANIFOLD } from "../contact/ManifoldStore.js";
|
|
6
|
-
import { gjk_epa_penetration } from "../../../core/geom/3d/gjk/gjk_epa_penetration.js";
|
|
6
|
+
import { GJK_SEPARATED, gjk_epa_penetration } from "../../../core/geom/3d/gjk/gjk_epa_penetration.js";
|
|
7
7
|
import { reduce_manifold_contacts } from "./reduce_manifold_contacts.js";
|
|
8
8
|
import { mpr } from "../../../core/geom/3d/gjk/mpr.js";
|
|
9
9
|
import { box_box_manifold, BOX_BOX_OUT_LENGTH } from "./box_box_manifold.js";
|
|
@@ -1124,12 +1124,15 @@ function dispatch_pair(count, colA, trA, colB, trB) {
|
|
|
1124
1124
|
// expanding_polytope_algorithm pair was replaced because it returned
|
|
1125
1125
|
// a non-minimal axis on degenerate simplices (see memory:
|
|
1126
1126
|
// feedback_epa_unreliable_polytopes); MPR is kept as a secondary
|
|
1127
|
-
// safety net for the
|
|
1127
|
+
// safety net for the case EPA degenerates on a real overlap, or
|
|
1128
|
+
// GJK reaches no verdict — never for a triangle GJK proved clear.
|
|
1128
1129
|
let ex, ey, ez, depth;
|
|
1129
1130
|
const pen_depth = gjk_epa_penetration(epa_result, posed_a, posed_b);
|
|
1130
1131
|
if (pen_depth > 0 && Number.isFinite(pen_depth)) {
|
|
1131
1132
|
ex = epa_result[0] * pen_depth; ey = epa_result[1] * pen_depth; ez = epa_result[2] * pen_depth;
|
|
1132
1133
|
depth = pen_depth;
|
|
1134
|
+
} else if (pen_depth === GJK_SEPARATED) {
|
|
1135
|
+
continue;
|
|
1133
1136
|
} else {
|
|
1134
1137
|
if (!mpr(epa_result, 0, posed_a, posed_b)) continue;
|
|
1135
1138
|
ex = epa_result[0]; ey = epa_result[1]; ez = epa_result[2];
|
|
@@ -1247,7 +1250,22 @@ function dispatch_pair(count, colA, trA, colB, trB) {
|
|
|
1247
1250
|
if (pen_depth > 0 && Number.isFinite(pen_depth)) {
|
|
1248
1251
|
ex = epa_result[0] * pen_depth; ey = epa_result[1] * pen_depth; ez = epa_result[2] * pen_depth;
|
|
1249
1252
|
depth = pen_depth;
|
|
1253
|
+
} else if (pen_depth === GJK_SEPARATED) {
|
|
1254
|
+
// GJK proved the pair apart — the answer, not a gap in the query, so
|
|
1255
|
+
// the safety net below has nothing to add and must not be consulted.
|
|
1256
|
+
// This branch is the common case on this path, not an edge: the
|
|
1257
|
+
// broadphase hands over every pair whose fat AABBs touch, and most of
|
|
1258
|
+
// them are near misses. Asking MPR about them is what turned a clear
|
|
1259
|
+
// gap into a ContactBegin carrying a positive depth equal to the gap
|
|
1260
|
+
// — for a sphere near a large ConvexHullShape3D face, which is every
|
|
1261
|
+
// projectile in a brush-built level (mpr.js's separating-plane
|
|
1262
|
+
// certificate now refuses that answer at the source too).
|
|
1263
|
+
return count;
|
|
1250
1264
|
} else {
|
|
1265
|
+
// No usable axis: EPA degenerated on a real overlap, or GJK itself
|
|
1266
|
+
// reached no verdict (its search direction collapses on an EXACTLY
|
|
1267
|
+
// touching pair). Neither is a separation, so the net still gets to
|
|
1268
|
+
// look. THIS is what it is for.
|
|
1251
1269
|
if (!mpr(epa_result, 0, posed_a, posed_b)) return count;
|
|
1252
1270
|
ex = epa_result[0]; ey = epa_result[1]; ez = epa_result[2];
|
|
1253
1271
|
depth = Math.sqrt(ex * ex + ey * ey + ez * ez);
|
|
@@ -390,10 +390,10 @@ export class StaticSceneBVH {
|
|
|
390
390
|
let nearest_distance = ray.tMax;
|
|
391
391
|
|
|
392
392
|
const hit_count = bvh_query_user_data_ray(
|
|
393
|
-
bvh,
|
|
394
|
-
bvh.root,
|
|
395
393
|
scratch_instance_hits,
|
|
396
394
|
0,
|
|
395
|
+
bvh,
|
|
396
|
+
bvh.root,
|
|
397
397
|
ray.origin_x, ray.origin_y, ray.origin_z,
|
|
398
398
|
ray.direction_x, ray.direction_y, ray.direction_z
|
|
399
399
|
);
|
|
@@ -501,10 +501,10 @@ export class StaticSceneBVH {
|
|
|
501
501
|
const bvh = this.instance_bvh;
|
|
502
502
|
|
|
503
503
|
const hit_count = bvh_query_user_data_ray(
|
|
504
|
-
bvh,
|
|
505
|
-
bvh.root,
|
|
506
504
|
scratch_instance_hits,
|
|
507
505
|
0,
|
|
506
|
+
bvh,
|
|
507
|
+
bvh.root,
|
|
508
508
|
ray.origin_x, ray.origin_y, ray.origin_z,
|
|
509
509
|
ray.direction_x, ray.direction_y, ray.direction_z
|
|
510
510
|
);
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Prepend a preamble to a three.js-generated shader and splice a chunk in after
|
|
3
|
-
* a named anchor.
|
|
4
|
-
*
|
|
5
|
-
* WHY THIS EXISTS
|
|
6
|
-
*
|
|
7
|
-
* The LPV/GI and LPG material paths have eight shader builders between them
|
|
8
|
-
* (`space_fragment` and `space_vertex`, vertex and fragment, times two
|
|
9
|
-
* subsystems) and every one of them was the same three statements: concatenate
|
|
10
|
-
* the preambles ahead of the source, `insert_after` an anchor, return. What
|
|
11
|
-
* actually differs is data — which preamble, which anchor, which chunk.
|
|
12
|
-
*
|
|
13
|
-
* More importantly the two anchors were spelled out in eight separate string
|
|
14
|
-
* literals. They are three.js's own chunk include lines, and a mismatch fails
|
|
15
|
-
* *quietly* (a console warning and an unmodified shader), so having one
|
|
16
|
-
* definition each is worth more than the lines it saves.
|
|
17
|
-
*
|
|
18
|
-
* Shader assembly happens once per material compile, not per frame.
|
|
19
|
-
*
|
|
20
|
-
* @param {string} source shader source three.js handed to `onBeforeCompile`
|
|
21
|
-
* @param {string} preamble prepended verbatim, ahead of the source
|
|
22
|
-
* @param {string} anchor see {@link GLSL_ANCHOR_LIGHTS_FRAGMENT_BEGIN} / {@link GLSL_ANCHOR_FOG_VERTEX}
|
|
23
|
-
* @param {string} chunk GLSL spliced in directly after `anchor`
|
|
24
|
-
* @returns {string}
|
|
25
|
-
*/
|
|
26
|
-
export function build_injected_shader(source: string, preamble: string, anchor: string, chunk: string): string;
|
|
27
|
-
/**
|
|
28
|
-
* three.js chunk marker after which a probe-field contribution is added to
|
|
29
|
-
* `irradiance` in the fragment stage.
|
|
30
|
-
*
|
|
31
|
-
* `<lights_fragment_begin>` is where three declares `irradiance` and has not yet
|
|
32
|
-
* consumed it, so anything added immediately after it participates in the
|
|
33
|
-
* lighting equations normally. The literal must match three's include line
|
|
34
|
-
* exactly — `insert_after` warns and silently returns the source unchanged when
|
|
35
|
-
* it does not find the term, which shows up as GI simply not appearing.
|
|
36
|
-
*
|
|
37
|
-
* @type {string}
|
|
38
|
-
*/
|
|
39
|
-
export const GLSL_ANCHOR_LIGHTS_FRAGMENT_BEGIN: string;
|
|
40
|
-
/**
|
|
41
|
-
* three.js chunk marker after which per-vertex probe work is injected.
|
|
42
|
-
*
|
|
43
|
-
* `<fog_vertex>` is the last chunk in the standard vertex `main()`, so by that
|
|
44
|
-
* point `worldPosition` (when declared), `position` and `normal` are all
|
|
45
|
-
* available. Same exact-match requirement as
|
|
46
|
-
* {@link GLSL_ANCHOR_LIGHTS_FRAGMENT_BEGIN}.
|
|
47
|
-
*
|
|
48
|
-
* @type {string}
|
|
49
|
-
*/
|
|
50
|
-
export const GLSL_ANCHOR_FOG_VERTEX: string;
|
|
51
|
-
//# sourceMappingURL=build_injected_shader.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"build_injected_shader.d.ts","sourceRoot":"","sources":["../../../../../src/engine/graphics/sh3/build_injected_shader.js"],"names":[],"mappings":"AA4BA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,8CANW,MAAM,YACN,MAAM,UACN,MAAM,SACN,MAAM,GACJ,MAAM,CAIlB;AArDD;;;;;;;;;;;GAWG;AACH,gDAFU,MAAM,CAEoE;AAEpF;;;;;;;;;GASG;AACH,qCAFU,MAAM,CAE8C"}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { insert_after } from "../../../core/primitives/strings/insert_after.js";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* three.js chunk marker after which a probe-field contribution is added to
|
|
5
|
-
* `irradiance` in the fragment stage.
|
|
6
|
-
*
|
|
7
|
-
* `<lights_fragment_begin>` is where three declares `irradiance` and has not yet
|
|
8
|
-
* consumed it, so anything added immediately after it participates in the
|
|
9
|
-
* lighting equations normally. The literal must match three's include line
|
|
10
|
-
* exactly — `insert_after` warns and silently returns the source unchanged when
|
|
11
|
-
* it does not find the term, which shows up as GI simply not appearing.
|
|
12
|
-
*
|
|
13
|
-
* @type {string}
|
|
14
|
-
*/
|
|
15
|
-
export const GLSL_ANCHOR_LIGHTS_FRAGMENT_BEGIN = '#include <lights_fragment_begin>';
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* three.js chunk marker after which per-vertex probe work is injected.
|
|
19
|
-
*
|
|
20
|
-
* `<fog_vertex>` is the last chunk in the standard vertex `main()`, so by that
|
|
21
|
-
* point `worldPosition` (when declared), `position` and `normal` are all
|
|
22
|
-
* available. Same exact-match requirement as
|
|
23
|
-
* {@link GLSL_ANCHOR_LIGHTS_FRAGMENT_BEGIN}.
|
|
24
|
-
*
|
|
25
|
-
* @type {string}
|
|
26
|
-
*/
|
|
27
|
-
export const GLSL_ANCHOR_FOG_VERTEX = '#include <fog_vertex>';
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Prepend a preamble to a three.js-generated shader and splice a chunk in after
|
|
31
|
-
* a named anchor.
|
|
32
|
-
*
|
|
33
|
-
* WHY THIS EXISTS
|
|
34
|
-
*
|
|
35
|
-
* The LPV/GI and LPG material paths have eight shader builders between them
|
|
36
|
-
* (`space_fragment` and `space_vertex`, vertex and fragment, times two
|
|
37
|
-
* subsystems) and every one of them was the same three statements: concatenate
|
|
38
|
-
* the preambles ahead of the source, `insert_after` an anchor, return. What
|
|
39
|
-
* actually differs is data — which preamble, which anchor, which chunk.
|
|
40
|
-
*
|
|
41
|
-
* More importantly the two anchors were spelled out in eight separate string
|
|
42
|
-
* literals. They are three.js's own chunk include lines, and a mismatch fails
|
|
43
|
-
* *quietly* (a console warning and an unmodified shader), so having one
|
|
44
|
-
* definition each is worth more than the lines it saves.
|
|
45
|
-
*
|
|
46
|
-
* Shader assembly happens once per material compile, not per frame.
|
|
47
|
-
*
|
|
48
|
-
* @param {string} source shader source three.js handed to `onBeforeCompile`
|
|
49
|
-
* @param {string} preamble prepended verbatim, ahead of the source
|
|
50
|
-
* @param {string} anchor see {@link GLSL_ANCHOR_LIGHTS_FRAGMENT_BEGIN} / {@link GLSL_ANCHOR_FOG_VERTEX}
|
|
51
|
-
* @param {string} chunk GLSL spliced in directly after `anchor`
|
|
52
|
-
* @returns {string}
|
|
53
|
-
*/
|
|
54
|
-
export function build_injected_shader(source, preamble, anchor, chunk) {
|
|
55
|
-
return insert_after(preamble + source, anchor, chunk);
|
|
56
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
* @param {Uint8Array} data
|
|
4
|
-
* @param {THREE.WebGLRenderer} renderer
|
|
5
|
-
* @param {THREE.WebGLCubeRenderTarget} cubeRenderTarget
|
|
6
|
-
* @return {Float64Array}
|
|
7
|
-
*/
|
|
8
|
-
export function fromCubeRenderTarget(data: Uint8Array, renderer: THREE.WebGLRenderer, cubeRenderTarget: THREE.WebGLCubeRenderTarget): Float64Array;
|
|
9
|
-
//# sourceMappingURL=fromCubeRenderTarget.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fromCubeRenderTarget.d.ts","sourceRoot":"","sources":["../../../../../src/engine/graphics/sh3/fromCubeRenderTarget.js"],"names":[],"mappings":"AAQA;;;;;;GAMG;AACH,2CALW,UAAU,iFAGT,YAAY,CAgIvB"}
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import { sh3_basis_at } from "../../../core/geom/3d/sphere/harmonics/sh3_basis_at.js";
|
|
2
|
-
import { sh3_dering_optimize_positive } from "../../../core/geom/3d/sphere/harmonics/sh3_dering_optimize_positive.js";
|
|
3
|
-
import { sh3_vector_accumulate } from "../../../core/geom/3d/sphere/harmonics/sh3_vector_accumulate.js";
|
|
4
|
-
import { vector_scale_offset } from "../../../core/geom/vec/vector_scale_offset.js";
|
|
5
|
-
import { v3_length_sqr } from "../../../core/geom/vec3/v3_length_sqr.js";
|
|
6
|
-
|
|
7
|
-
const scratch_color = new Float32Array(3);
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
*
|
|
11
|
-
* @param {Uint8Array} data
|
|
12
|
-
* @param {THREE.WebGLRenderer} renderer
|
|
13
|
-
* @param {THREE.WebGLCubeRenderTarget} cubeRenderTarget
|
|
14
|
-
* @return {Float64Array}
|
|
15
|
-
*/
|
|
16
|
-
export function fromCubeRenderTarget(
|
|
17
|
-
data,
|
|
18
|
-
renderer,
|
|
19
|
-
cubeRenderTarget
|
|
20
|
-
) {
|
|
21
|
-
|
|
22
|
-
// The renderTarget must be set to RGBA in order to make readRenderTargetPixels works
|
|
23
|
-
let total_weight = 0;
|
|
24
|
-
|
|
25
|
-
const __shared_buffer = new ArrayBuffer((27 + 9) * 8);
|
|
26
|
-
|
|
27
|
-
const sh_basis = new Float64Array(__shared_buffer, 0, 9);
|
|
28
|
-
const coefficients = new Float64Array(__shared_buffer, 9 * 8, 27);
|
|
29
|
-
|
|
30
|
-
const image_size = cubeRenderTarget.width;
|
|
31
|
-
|
|
32
|
-
const pixel_size = 2 / image_size;
|
|
33
|
-
|
|
34
|
-
let normal_x = 0, normal_y = 0, normal_z = 0;
|
|
35
|
-
|
|
36
|
-
for (let faceIndex = 0; faceIndex < 6; faceIndex++) {
|
|
37
|
-
|
|
38
|
-
renderer.readRenderTargetPixels(cubeRenderTarget, 0, 0, image_size, image_size, data, faceIndex);
|
|
39
|
-
|
|
40
|
-
// RGBA assumed
|
|
41
|
-
|
|
42
|
-
for (let i = 0, il = data.length; i < il; i += 4) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
// pixel coordinate on unit cube
|
|
46
|
-
|
|
47
|
-
const pixelIndex = i / 4;
|
|
48
|
-
|
|
49
|
-
const col = -1 + (pixelIndex % image_size + 0.5) * pixel_size;
|
|
50
|
-
|
|
51
|
-
const row = 1 - (Math.floor(pixelIndex / image_size) + 0.5) * pixel_size;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
switch (faceIndex) {
|
|
55
|
-
|
|
56
|
-
case 0:
|
|
57
|
-
normal_x = 1;
|
|
58
|
-
normal_y = row;
|
|
59
|
-
normal_z = -col;
|
|
60
|
-
break;
|
|
61
|
-
|
|
62
|
-
case 1:
|
|
63
|
-
normal_x = -1;
|
|
64
|
-
normal_y = row;
|
|
65
|
-
normal_z = col;
|
|
66
|
-
break;
|
|
67
|
-
|
|
68
|
-
case 2:
|
|
69
|
-
normal_x = col;
|
|
70
|
-
normal_y = 1;
|
|
71
|
-
normal_z = -row;
|
|
72
|
-
break;
|
|
73
|
-
|
|
74
|
-
case 3:
|
|
75
|
-
normal_x = col;
|
|
76
|
-
normal_y = -1;
|
|
77
|
-
normal_z = row;
|
|
78
|
-
break;
|
|
79
|
-
|
|
80
|
-
case 4:
|
|
81
|
-
normal_x = col;
|
|
82
|
-
normal_y = row;
|
|
83
|
-
normal_z = 1;
|
|
84
|
-
break;
|
|
85
|
-
|
|
86
|
-
case 5:
|
|
87
|
-
normal_x = -col;
|
|
88
|
-
normal_y = row;
|
|
89
|
-
normal_z = -1;
|
|
90
|
-
break;
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// weight assigned to this pixel
|
|
95
|
-
|
|
96
|
-
const length_squared = v3_length_sqr(normal_x, normal_y, normal_z);
|
|
97
|
-
|
|
98
|
-
const length = Math.sqrt(length_squared);
|
|
99
|
-
|
|
100
|
-
const weight = 4 / (length * length_squared);
|
|
101
|
-
|
|
102
|
-
total_weight += weight;
|
|
103
|
-
|
|
104
|
-
// direction vector to this pixel
|
|
105
|
-
normal_x /= length;
|
|
106
|
-
normal_y /= length;
|
|
107
|
-
normal_z /= length;
|
|
108
|
-
|
|
109
|
-
// evaluate SH basis functions in direction dir
|
|
110
|
-
sh3_basis_at(normal_x, normal_y, normal_z, sh_basis);
|
|
111
|
-
|
|
112
|
-
// pixel color, already in linear space so no sRGB->Linear conversion necessary
|
|
113
|
-
|
|
114
|
-
// 0.003921 constant value is 1/255, a conversion value from UINT8 to normalized float
|
|
115
|
-
const weight_conv = weight * 0.00392156862745098;
|
|
116
|
-
|
|
117
|
-
scratch_color[0] = data[i] * weight_conv;
|
|
118
|
-
scratch_color[1] = data[i + 1] * weight_conv;
|
|
119
|
-
scratch_color[2] = data[i + 2] * weight_conv;
|
|
120
|
-
|
|
121
|
-
// accumulate
|
|
122
|
-
sh3_vector_accumulate(
|
|
123
|
-
coefficients, 0,
|
|
124
|
-
sh_basis, 0,
|
|
125
|
-
scratch_color, 0,
|
|
126
|
-
3
|
|
127
|
-
);
|
|
128
|
-
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// normalize
|
|
134
|
-
const norm = (4 * Math.PI) / total_weight;
|
|
135
|
-
|
|
136
|
-
vector_scale_offset(coefficients, 0, coefficients, 0, 27, norm);
|
|
137
|
-
|
|
138
|
-
sh3_dering_optimize_positive(coefficients, 0, coefficients, 0, 3);
|
|
139
|
-
|
|
140
|
-
return coefficients;
|
|
141
|
-
|
|
142
|
-
}
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
declare const _default: "\n#define RECIPROCAL_PI 0.318309886\n\nvec3 inverseTransformDirection( in vec3 normal, in mat4 matrix ) {\n // matrix is assumed to be orthogonal\n return normalize( ( vec4( normal, 0.0 ) * matrix ).xyz );\n}\n\n// source: https://graphics.stanford.edu/papers/envmap/envmap.pdf\n//\n// SIGN CONVENTION: coefficients 1, 3, 5 and 7 are SUBTRACTED here, matching\n// three.js's SphericalHarmonics3 and the JS reference\n// core/geom/3d/sphere/harmonics/sh3_sample_irradiance_by_direction.js. The LPV\n// and LPG shader chunks (sh3/{gi,lpg}/material/chunk_*_get_irradiance_at.js)\n// ADD them instead — see the note in chunk_lpv_get_irradiance_at.js. The\n// constants are the same in all four; only these signs differ.\nvec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {\n // normal is assumed to have unit length\n float x = normal.x, y = normal.y, z = normal.z;\n\n // band 0\n vec3 result = shCoefficients[ 0 ] * 0.8862269254527579;\n\n // band 1\n result -= shCoefficients[ 1 ] * 1.0233267079464885 * y;\n result += shCoefficients[ 2 ] * 1.0233267079464885 * z;\n result -= shCoefficients[ 3 ] * 1.0233267079464885 * x;\n\n // band 2\n result += shCoefficients[ 4 ] * 0.8580855308097834 * x * y;\n result -= shCoefficients[ 5 ] * 0.8580855308097834 * y * z;\n result += shCoefficients[ 6 ] * ( 0.7431238683011272 * z * z - 0.24770795610037571 );\n result -= shCoefficients[ 7 ] * 0.8580855308097834 * x * z;\n result += shCoefficients[ 8 ] * 0.4290427654048917 * ( x * x - y * y );\n\n return result;\n}\n\nuniform vec3 sh[ 9 ]; // sh coefficients\nuniform float intensity; // light probe intensity\nvarying vec3 vNormal;\n\nvoid main() {\n vec3 normal = normalize( vNormal );\n vec3 worldNormal = normalize(inverseTransformDirection( normal, viewMatrix ));\n vec3 irradiance = shGetIrradianceAt( worldNormal, sh );\n vec3 outgoingLight = 1.0 * irradiance * intensity;\n gl_FragColor = linearToOutputTexel( vec4( outgoingLight, 1.0 ) );\n}\n";
|
|
2
|
-
export default _default;
|
|
3
|
-
//# sourceMappingURL=visualize.frag.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"visualize.frag.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/sh3/shader/visualize.frag.js"],"names":[],"mappings":""}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
// language=GLSL
|
|
2
|
-
export default `
|
|
3
|
-
#define RECIPROCAL_PI 0.318309886
|
|
4
|
-
|
|
5
|
-
vec3 inverseTransformDirection( in vec3 normal, in mat4 matrix ) {
|
|
6
|
-
// matrix is assumed to be orthogonal
|
|
7
|
-
return normalize( ( vec4( normal, 0.0 ) * matrix ).xyz );
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
// source: https://graphics.stanford.edu/papers/envmap/envmap.pdf
|
|
11
|
-
//
|
|
12
|
-
// SIGN CONVENTION: coefficients 1, 3, 5 and 7 are SUBTRACTED here, matching
|
|
13
|
-
// three.js's SphericalHarmonics3 and the JS reference
|
|
14
|
-
// core/geom/3d/sphere/harmonics/sh3_sample_irradiance_by_direction.js. The LPV
|
|
15
|
-
// and LPG shader chunks (sh3/{gi,lpg}/material/chunk_*_get_irradiance_at.js)
|
|
16
|
-
// ADD them instead — see the note in chunk_lpv_get_irradiance_at.js. The
|
|
17
|
-
// constants are the same in all four; only these signs differ.
|
|
18
|
-
vec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {
|
|
19
|
-
// normal is assumed to have unit length
|
|
20
|
-
float x = normal.x, y = normal.y, z = normal.z;
|
|
21
|
-
|
|
22
|
-
// band 0
|
|
23
|
-
vec3 result = shCoefficients[ 0 ] * 0.8862269254527579;
|
|
24
|
-
|
|
25
|
-
// band 1
|
|
26
|
-
result -= shCoefficients[ 1 ] * 1.0233267079464885 * y;
|
|
27
|
-
result += shCoefficients[ 2 ] * 1.0233267079464885 * z;
|
|
28
|
-
result -= shCoefficients[ 3 ] * 1.0233267079464885 * x;
|
|
29
|
-
|
|
30
|
-
// band 2
|
|
31
|
-
result += shCoefficients[ 4 ] * 0.8580855308097834 * x * y;
|
|
32
|
-
result -= shCoefficients[ 5 ] * 0.8580855308097834 * y * z;
|
|
33
|
-
result += shCoefficients[ 6 ] * ( 0.7431238683011272 * z * z - 0.24770795610037571 );
|
|
34
|
-
result -= shCoefficients[ 7 ] * 0.8580855308097834 * x * z;
|
|
35
|
-
result += shCoefficients[ 8 ] * 0.4290427654048917 * ( x * x - y * y );
|
|
36
|
-
|
|
37
|
-
return result;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
uniform vec3 sh[ 9 ]; // sh coefficients
|
|
41
|
-
uniform float intensity; // light probe intensity
|
|
42
|
-
varying vec3 vNormal;
|
|
43
|
-
|
|
44
|
-
void main() {
|
|
45
|
-
vec3 normal = normalize( vNormal );
|
|
46
|
-
vec3 worldNormal = normalize(inverseTransformDirection( normal, viewMatrix ));
|
|
47
|
-
vec3 irradiance = shGetIrradianceAt( worldNormal, sh );
|
|
48
|
-
vec3 outgoingLight = 1.0 * irradiance * intensity;
|
|
49
|
-
gl_FragColor = linearToOutputTexel( vec4( outgoingLight, 1.0 ) );
|
|
50
|
-
}
|
|
51
|
-
`
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
declare const _default: "\nvarying vec3 vNormal;\n\nvoid main() {\n\n vNormal = normalize( normalMatrix * normal );\n\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\n}\n";
|
|
2
|
-
export default _default;
|
|
3
|
-
//# sourceMappingURL=visualize.vert.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"visualize.vert.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/sh3/shader/visualize.vert.js"],"names":[],"mappings":""}
|