@woosh/meep-engine 2.138.4 → 2.138.5

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.
Files changed (32) hide show
  1. package/package.json +1 -1
  2. package/src/core/bvh2/bvh3/query/bvh_query_depth_range_in_frustum.d.ts +31 -0
  3. package/src/core/bvh2/bvh3/query/bvh_query_depth_range_in_frustum.d.ts.map +1 -0
  4. package/src/core/bvh2/bvh3/query/bvh_query_depth_range_in_frustum.js +101 -0
  5. package/src/engine/EngineHarness.js +2 -2
  6. package/src/engine/ecs/renderable/RenderSystem.d.ts.map +1 -1
  7. package/src/engine/ecs/renderable/RenderSystem.js +6 -0
  8. package/src/engine/ecs/terrain/ecs/TerrainSystem.d.ts.map +1 -1
  9. package/src/engine/ecs/terrain/ecs/TerrainSystem.js +19 -0
  10. package/src/engine/graphics/ecs/camera/auto_set_camera_clipping_planes.d.ts +4 -1
  11. package/src/engine/graphics/ecs/camera/auto_set_camera_clipping_planes.d.ts.map +1 -1
  12. package/src/engine/graphics/ecs/camera/auto_set_camera_clipping_planes.js +121 -12
  13. package/src/engine/graphics/ecs/light/LightSystem.d.ts.map +1 -1
  14. package/src/engine/graphics/ecs/light/LightSystem.js +16 -2
  15. package/src/engine/graphics/ecs/light/shadow/extend_shadow_camera_near_for_casters.d.ts +30 -0
  16. package/src/engine/graphics/ecs/light/shadow/extend_shadow_camera_near_for_casters.d.ts.map +1 -0
  17. package/src/engine/graphics/ecs/light/shadow/extend_shadow_camera_near_for_casters.js +97 -0
  18. package/src/engine/graphics/ecs/mesh/MeshSystem.d.ts.map +1 -1
  19. package/src/engine/graphics/ecs/mesh/MeshSystem.js +6 -0
  20. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.d.ts.map +1 -1
  21. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js +6 -0
  22. package/src/engine/graphics/ecs/trail2d/Trail2DSystem.d.ts.map +1 -1
  23. package/src/engine/graphics/ecs/trail2d/Trail2DSystem.js +6 -0
  24. package/src/engine/graphics/ecs/water/WaterSystem.d.ts.map +1 -1
  25. package/src/engine/graphics/ecs/water/WaterSystem.js +6 -0
  26. package/src/engine/graphics/impostors/octahedral/prototypeBaker.js +1 -0
  27. package/src/engine/graphics/particles/ecs/ParticleEmitterSystem.d.ts.map +1 -1
  28. package/src/engine/graphics/particles/ecs/ParticleEmitterSystem.js +6 -0
  29. package/src/engine/graphics/render/layers/RenderLayer.d.ts +2 -0
  30. package/src/engine/graphics/render/layers/RenderLayer.d.ts.map +1 -1
  31. package/src/engine/graphics/render/layers/RenderLayer.js +14 -0
  32. package/src/engine/intelligence/mcts/MonteCarlo.js +1 -1
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "description": "Pure JavaScript game engine. Fully featured and production ready.",
6
6
  "type": "module",
7
7
  "author": "Alexander Goldring",
8
- "version": "2.138.4",
8
+ "version": "2.138.5",
9
9
  "main": "build/meep.module.js",
10
10
  "module": "build/meep.module.js",
11
11
  "exports": {
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Walk a BVH and, for each node-AABB overlapping the frustum, update the
3
+ * running (min, max) distance from those AABBs to a plane. Used to compute the
4
+ * tight near/far range a camera needs to contain all visible content along its
5
+ * view direction.
6
+ *
7
+ * Distances are measured along the plane normal: positive when the AABB sits
8
+ * on the side the normal points to. Range starts wide and shrinks per AABB —
9
+ * caller may pre-seed `result` (e.g. to chain BVHs) and read back the
10
+ * accumulated range.
11
+ *
12
+ * Resolves at AABB granularity. Nodes fully inside the frustum take a fast
13
+ * path (no further recursion) and contribute their full AABB extent, which
14
+ * may overstate the range slightly when the AABB extends past the frustum
15
+ * walls; for clipping plane fitting that's the right (conservative) tradeoff.
16
+ *
17
+ * @param {{near:number, far:number}} result accumulator — mutated in place.
18
+ * Initialize {near: +Infinity, far: -Infinity} on first call.
19
+ * @param {BVH} bvh
20
+ * @param {ArrayLike<number>} frustum 6 inward-facing planes, layout matching
21
+ * {@link frustum_from_projection_matrix_array}
22
+ * @param {number} plane_normal_x
23
+ * @param {number} plane_normal_y
24
+ * @param {number} plane_normal_z
25
+ * @param {number} plane_constant
26
+ */
27
+ export function bvh_query_depth_range_in_frustum(result: {
28
+ near: number;
29
+ far: number;
30
+ }, bvh: BVH, frustum: ArrayLike<number>, plane_normal_x: number, plane_normal_y: number, plane_normal_z: number, plane_constant: number): void;
31
+ //# sourceMappingURL=bvh_query_depth_range_in_frustum.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bvh_query_depth_range_in_frustum.d.ts","sourceRoot":"","sources":["../../../../../../src/core/bvh2/bvh3/query/bvh_query_depth_range_in_frustum.js"],"names":[],"mappings":"AAUA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,yDAVW;IAAC,IAAI,EAAC,MAAM,CAAC;IAAC,GAAG,EAAC,MAAM,CAAA;CAAC,qBAGzB,UAAU,MAAM,CAAC,kBAEjB,MAAM,kBACN,MAAM,kBACN,MAAM,kBACN,MAAM,QAkEhB"}
@@ -0,0 +1,101 @@
1
+ import { SCRATCH_UINT32_TRAVERSAL_STACK } from "../../../collection/SCRATCH_UINT32_TRAVERSAL_STACK.js";
2
+ import { aabb3_array_intersects_frustum_degree } from "../../../geom/3d/aabb/aabb3_array_intersects_frustum_degree.js";
3
+ import { aabb3_compute_distance_above_plane_max } from "../../../geom/3d/aabb/aabb3_compute_distance_above_plane_max.js";
4
+ import { aabb3_compute_distance_above_plane_min } from "../../../geom/3d/aabb/aabb3_compute_distance_above_plane_min.js";
5
+ import { NULL_NODE } from "../BVH.js";
6
+
7
+ const stack = SCRATCH_UINT32_TRAVERSAL_STACK;
8
+
9
+ const scratch_aabb = new Float32Array(6);
10
+
11
+ /**
12
+ * Walk a BVH and, for each node-AABB overlapping the frustum, update the
13
+ * running (min, max) distance from those AABBs to a plane. Used to compute the
14
+ * tight near/far range a camera needs to contain all visible content along its
15
+ * view direction.
16
+ *
17
+ * Distances are measured along the plane normal: positive when the AABB sits
18
+ * on the side the normal points to. Range starts wide and shrinks per AABB —
19
+ * caller may pre-seed `result` (e.g. to chain BVHs) and read back the
20
+ * accumulated range.
21
+ *
22
+ * Resolves at AABB granularity. Nodes fully inside the frustum take a fast
23
+ * path (no further recursion) and contribute their full AABB extent, which
24
+ * may overstate the range slightly when the AABB extends past the frustum
25
+ * walls; for clipping plane fitting that's the right (conservative) tradeoff.
26
+ *
27
+ * @param {{near:number, far:number}} result accumulator — mutated in place.
28
+ * Initialize {near: +Infinity, far: -Infinity} on first call.
29
+ * @param {BVH} bvh
30
+ * @param {ArrayLike<number>} frustum 6 inward-facing planes, layout matching
31
+ * {@link frustum_from_projection_matrix_array}
32
+ * @param {number} plane_normal_x
33
+ * @param {number} plane_normal_y
34
+ * @param {number} plane_normal_z
35
+ * @param {number} plane_constant
36
+ */
37
+ export function bvh_query_depth_range_in_frustum(
38
+ result,
39
+ bvh,
40
+ frustum,
41
+ plane_normal_x, plane_normal_y, plane_normal_z, plane_constant
42
+ ) {
43
+ const root = bvh.root;
44
+
45
+ if (root === NULL_NODE) {
46
+ return;
47
+ }
48
+
49
+ const stack_top = stack.pointer++;
50
+
51
+ stack[stack_top] = root;
52
+
53
+ while (stack.pointer > stack_top) {
54
+ stack.pointer--;
55
+
56
+ const node = stack[stack.pointer];
57
+
58
+ bvh.node_get_aabb(node, scratch_aabb);
59
+
60
+ const x0 = scratch_aabb[0];
61
+ const y0 = scratch_aabb[1];
62
+ const z0 = scratch_aabb[2];
63
+ const x1 = scratch_aabb[3];
64
+ const y1 = scratch_aabb[4];
65
+ const z1 = scratch_aabb[5];
66
+
67
+ const intersection = aabb3_array_intersects_frustum_degree(scratch_aabb, 0, frustum);
68
+
69
+ if (intersection === 0) {
70
+ continue;
71
+ }
72
+
73
+ const node_is_leaf = bvh.node_is_leaf(node);
74
+
75
+ if (node_is_leaf || intersection === 2) {
76
+ // leaf or fully-inside subtree — contribute this AABB and stop descending
77
+ const d_min = aabb3_compute_distance_above_plane_min(
78
+ plane_normal_x, plane_normal_y, plane_normal_z, plane_constant,
79
+ x0, y0, z0, x1, y1, z1
80
+ );
81
+ const d_max = aabb3_compute_distance_above_plane_max(
82
+ plane_normal_x, plane_normal_y, plane_normal_z, plane_constant,
83
+ x0, y0, z0, x1, y1, z1
84
+ );
85
+
86
+ if (d_min < result.near) {
87
+ result.near = d_min;
88
+ }
89
+ if (d_max > result.far) {
90
+ result.far = d_max;
91
+ }
92
+ } else {
93
+ // partially inside — descend
94
+ const child1 = bvh.node_get_child1(node);
95
+ const child2 = bvh.node_get_child2(node);
96
+
97
+ stack[stack.pointer++] = child1;
98
+ stack[stack.pointer++] = child2;
99
+ }
100
+ }
101
+ }
@@ -192,7 +192,7 @@ export class EngineHarness {
192
192
  distance = 10,
193
193
  pitch = 1.4,
194
194
  yaw = 0,
195
- autoClip = false,
195
+ autoClip = true,
196
196
  distanceMin = 0.01,
197
197
  distanceMax = 1000,
198
198
  fieldOfView = 45
@@ -286,7 +286,7 @@ export class EngineHarness {
286
286
  cameraFieldOfView,
287
287
  cameraFarDistance,
288
288
  cameraController = true,
289
- cameraAutoClip = false,
289
+ cameraAutoClip = true,
290
290
  shadowmapResolution,
291
291
  showFps = true
292
292
  }) {
@@ -1 +1 @@
1
- {"version":3,"file":"RenderSystem.d.ts","sourceRoot":"","sources":["../../../../../src/engine/ecs/renderable/RenderSystem.js"],"names":[],"mappings":";AAcA;;GAEG;AACH;IAqBI;;;;OAIG;IACH,4CAOC;IAhCD,uDAAuC;IAEvC,kEAEE;IAEF,kBAAgB;IAEhB;;;OAGG;IACH,aAFU,cAAY,IAAI,CAEP;IAEnB;;;OAGG;IACH,KAFU,GAAG,CAEG;IAUZ;;OAEG;IACH,yBAA8B;IAGlC,2CA8CC;IAED,4CAEC;IAED;;;;;OAKG;IACH,iBAJW,UAAU,aACV,SAAS,qBAwCnB;IAED;;;;;OAKG;IACH,mBAJW,UAAU,aACV,SAAS,qBAiBnB;IAED;;;;;;;;;;;;OAYG;IACH,gEAVW,MAAM,YACN,MAAM,YACN,MAAM,eACN,MAAM,eACN,MAAM,eACN,MAAM,kBACG,MAAM,QAAE,UAAU,mCAA0B,OAAO,wBAE1D,MAAM,CAelB;CACJ;uBA9LsB,cAAc;0BACX,2BAA2B;uBAC9B,iBAAiB;4CAPI,oDAAoD;oBAH5E,gCAAgC"}
1
+ {"version":3,"file":"RenderSystem.d.ts","sourceRoot":"","sources":["../../../../../src/engine/ecs/renderable/RenderSystem.js"],"names":[],"mappings":";AAeA;;GAEG;AACH;IAqBI;;;;OAIG;IACH,4CAOC;IAhCD,uDAAuC;IAEvC,kEAEE;IAEF,kBAAgB;IAEhB;;;OAGG;IACH,aAFU,cAAY,IAAI,CAEP;IAEnB;;;OAGG;IACH,KAFU,GAAG,CAEG;IAUZ;;OAEG;IACH,yBAA8B;IAGlC,2CAmDC;IAED,4CAEC;IAED;;;;;OAKG;IACH,iBAJW,UAAU,aACV,SAAS,qBAwCnB;IAED;;;;;OAKG;IACH,mBAJW,UAAU,aACV,SAAS,qBAiBnB;IAED;;;;;;;;;;;;OAYG;IACH,gEAVW,MAAM,YACN,MAAM,YACN,MAAM,eACN,MAAM,eACN,MAAM,eACN,MAAM,kBACG,MAAM,QAAE,UAAU,mCAA0B,OAAO,wBAE1D,MAAM,CAelB;CACJ;uBAnMsB,cAAc;0BACX,2BAA2B;uBAC9B,iBAAiB;4CAPI,oDAAoD;oBAJ5E,gCAAgC"}
@@ -1,4 +1,5 @@
1
1
  import { BVH } from "../../../core/bvh2/bvh3/BVH.js";
2
+ import { bvh_query_depth_range_in_frustum } from "../../../core/bvh2/bvh3/query/bvh_query_depth_range_in_frustum.js";
2
3
  import { SignalBinding } from "../../../core/events/signal/SignalBinding.js";
3
4
  import { ResourceAccessKind } from "../../../core/model/ResourceAccessKind.js";
4
5
  import { ResourceAccessSpecification } from "../../../core/model/ResourceAccessSpecification.js";
@@ -69,6 +70,11 @@ class RenderSystem extends System {
69
70
  }
70
71
  )
71
72
 
73
+ const bvh = this.bvh;
74
+ this.renderLayer.compute_depth_range = (result, frustum, nx, ny, nz, c) => {
75
+ bvh_query_depth_range_in_frustum(result, bvh, frustum, nx, ny, nz, c);
76
+ };
77
+
72
78
  const visibleSet = this.renderLayer.visibleSet;
73
79
 
74
80
  visibleSet.onAdded.add(m => {
@@ -1 +1 @@
1
- {"version":3,"file":"TerrainSystem.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/ecs/terrain/ecs/TerrainSystem.js"],"names":[],"mappings":";AA+BA;IAwMI;;;;;OAKG;IACH,kEAHW,OAAO,uBAwCjB;IA1ND;;;;;OAKG;IACH,kEAeC;IA7CD,iCAAyB;IAEzB,mBAAe;IACf,mBAAe;IAEf;;;;OAIG;IACH,qBAAiB;IAEjB;;;OAGG;IACH,aAFU,cAAY,IAAI,CAEP;IAEnB;;;OAGG;IACH,KAFU,GAAG,CAEG;IAoBZ,yBAAwB;IAExB,2BAAgC;IAGpC,kDAMC;IAED,2CAwDC;IAED,4CAEC;IAED;;;;OAIG;IACH,gBAHW,OAAO,qBAqBjB;IAED;;;;OAIG;IACH,kBAHW,OAAO,qBAKjB;IAED,6BAaC;IAED;;;;;OAKG;IACH,gCAwBC;CA+CJ;uBAvQsB,iBAAiB;oBAEpB,cAAc;oBAbd,mCAAmC"}
1
+ {"version":3,"file":"TerrainSystem.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/ecs/terrain/ecs/TerrainSystem.js"],"names":[],"mappings":";AAgCA;IA0NI;;;;;OAKG;IACH,kEAHW,OAAO,uBAwCjB;IA5OD;;;;;OAKG;IACH,kEAeC;IA7CD,iCAAyB;IAEzB,mBAAe;IACf,mBAAe;IAEf;;;;OAIG;IACH,qBAAiB;IAEjB;;;OAGG;IACH,aAFU,cAAY,IAAI,CAEP;IAEnB;;;OAGG;IACH,KAFU,GAAG,CAEG;IAoBZ,yBAAwB;IAExB,2BAAgC;IAGpC,kDAMC;IAED,2CA0EC;IAED,4CAEC;IAED;;;;OAIG;IACH,gBAHW,OAAO,qBAqBjB;IAED;;;;OAIG;IACH,kBAHW,OAAO,qBAKjB;IAED,6BAaC;IAED;;;;;OAKG;IACH,gCAwBC;CA+CJ;uBAzRsB,iBAAiB;oBAEpB,cAAc;oBAdd,mCAAmC"}
@@ -1,5 +1,6 @@
1
1
  import { assert } from "../../../../core/assert.js";
2
2
  import { BVH } from "../../../../core/bvh2/bvh3/BVH.js";
3
+ import { bvh_query_depth_range_in_frustum } from "../../../../core/bvh2/bvh3/query/bvh_query_depth_range_in_frustum.js";
3
4
  import {
4
5
  bvh_query_user_data_overlaps_frustum
5
6
  } from "../../../../core/bvh2/bvh3/query/bvh_query_user_data_overlaps_frustum.js";
@@ -136,6 +137,24 @@ class TerrainSystem extends System {
136
137
  return match_count;
137
138
  };
138
139
 
140
+ this.renderLayer.compute_depth_range = (result, frustum, nx, ny, nz, c) => {
141
+ const em = this.entityManager;
142
+
143
+ if (em === null) {
144
+ return;
145
+ }
146
+
147
+ const ecd = em.dataset;
148
+
149
+ if (ecd === null) {
150
+ return;
151
+ }
152
+
153
+ ecd.traverseComponents(Terrain, (component) => {
154
+ bvh_query_depth_range_in_frustum(result, component.tiles.bvh, frustum, nx, ny, nz, c);
155
+ });
156
+ };
157
+
139
158
  const am = this.assetManager;
140
159
 
141
160
  await am.tryRegisterLoader('image', new ImageRGBADataLoader());
@@ -1,6 +1,9 @@
1
1
  /**
2
+ * Tighten the camera's near/far planes to the world-space depth range of all
3
+ * BVH-backed render layers' content visible inside the camera's frustum. Falls
4
+ * back to (clip_near, clip_far) when no layer contributes content.
2
5
  *
3
- * @param {Camera} c
6
+ * @param {Camera} c camera ECS component (its `object` is the THREE.Camera)
4
7
  * @param {RenderLayerManager} layers
5
8
  */
6
9
  export function auto_set_camera_clipping_planes(c: Camera, layers: RenderLayerManager): void;
@@ -1 +1 @@
1
- {"version":3,"file":"auto_set_camera_clipping_planes.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/camera/auto_set_camera_clipping_planes.js"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,6FAMC"}
1
+ {"version":3,"file":"auto_set_camera_clipping_planes.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/camera/auto_set_camera_clipping_planes.js"],"names":[],"mappings":"AAyBA;;;;;;;GAOG;AACH,6FAsFC"}
@@ -1,12 +1,121 @@
1
- /**
2
- *
3
- * @param {Camera} c
4
- * @param {RenderLayerManager} layers
5
- */
6
- export function auto_set_camera_clipping_planes(c, layers) {
7
- // TODO implement
8
-
9
- c.object.far = c.clip_far;
10
- c.object.near = c.clip_near;
11
-
12
- }
1
+ import { Frustum as ThreeFrustum } from "three";
2
+ import { read_three_planes_to_array } from "../../../../core/geom/3d/frustum/read_three_planes_to_array.js";
3
+ import { frustum_from_camera } from "./frustum_from_camera.js";
4
+
5
+ const CLIPPING_EPSILON = 0.001;
6
+ const CLIPPING_NEAR_MIN = 0.5;
7
+ const CLIPPING_FAR_DEFAULT = 100;
8
+
9
+ const scratch_three_frustum = new ThreeFrustum();
10
+ const scratch_frustum_planes = new Float32Array(24);
11
+ const scratch_range = { near: 0, far: 0 };
12
+
13
+ /**
14
+ * Hysteresis prevents the clipping planes from thrashing as content moves
15
+ * slightly. A shrink is only honored when it's at least this fraction of the
16
+ * current near-to-far span; smaller shrinks are ignored, so an object briefly
17
+ * crossing the frustum boundary doesn't trigger a re-projection.
18
+ *
19
+ * Loosenings (when content moves further away or closer) always apply
20
+ * immediately — never delay including content.
21
+ *
22
+ * @type {number}
23
+ */
24
+ const HYSTERESIS = 0.33;
25
+
26
+ /**
27
+ * Tighten the camera's near/far planes to the world-space depth range of all
28
+ * BVH-backed render layers' content visible inside the camera's frustum. Falls
29
+ * back to (clip_near, clip_far) when no layer contributes content.
30
+ *
31
+ * @param {Camera} c camera ECS component (its `object` is the THREE.Camera)
32
+ * @param {RenderLayerManager} layers
33
+ */
34
+ export function auto_set_camera_clipping_planes(c, layers) {
35
+ const camera = c.object;
36
+
37
+ if (camera === null) {
38
+ return;
39
+ }
40
+
41
+ // Run visibility against the user-specified outer bounds, not the previous
42
+ // frame's tightened range — otherwise objects could be culled before we
43
+ // ever see them and the autoClip would shrink toward nothing.
44
+ camera.near = c.clip_near;
45
+ camera.far = c.clip_far;
46
+
47
+ frustum_from_camera(camera, scratch_three_frustum, true);
48
+ read_three_planes_to_array(scratch_three_frustum.planes, scratch_frustum_planes);
49
+
50
+ // Depth plane: passes through camera position, normal pointing along the
51
+ // view direction (-Z in camera local). A world-space point's distance to
52
+ // this plane equals its signed depth in front of the camera.
53
+ const m = camera.matrixWorld.elements;
54
+ const nx = -m[8];
55
+ const ny = -m[9];
56
+ const nz = -m[10];
57
+ const cam_x = m[12];
58
+ const cam_y = m[13];
59
+ const cam_z = m[14];
60
+ const plane_constant = -(nx * cam_x + ny * cam_y + nz * cam_z);
61
+
62
+ scratch_range.near = Number.POSITIVE_INFINITY;
63
+ scratch_range.far = Number.NEGATIVE_INFINITY;
64
+
65
+ layers.traverse((layer) => {
66
+ if (!layer.state.visible) {
67
+ return;
68
+ }
69
+
70
+ const compute = layer.compute_depth_range;
71
+
72
+ if (compute === null) {
73
+ return;
74
+ }
75
+
76
+ compute(scratch_range, scratch_frustum_planes, nx, ny, nz, plane_constant);
77
+ });
78
+
79
+ let new_near = scratch_range.near - CLIPPING_EPSILON;
80
+ let new_far = scratch_range.far + CLIPPING_EPSILON;
81
+
82
+ if (!isFinite(new_near) || new_near < CLIPPING_NEAR_MIN) {
83
+ new_near = CLIPPING_NEAR_MIN;
84
+ }
85
+ if (!isFinite(new_far) || new_far <= new_near) {
86
+ new_far = Math.max(new_near + CLIPPING_EPSILON, CLIPPING_FAR_DEFAULT);
87
+ }
88
+
89
+ // Clamp inside the user-specified outer bounds so the tightened range
90
+ // never expands past what the camera is configured to render.
91
+ if (new_near < c.clip_near) {
92
+ new_near = c.clip_near;
93
+ }
94
+ if (new_far > c.clip_far) {
95
+ new_far = c.clip_far;
96
+ }
97
+
98
+ // Hysteresis: only shrink each plane if the shrink is meaningful relative
99
+ // to the current span. Loosening always applies immediately.
100
+ const old_near = camera.near;
101
+ const old_far = camera.far;
102
+ const old_span = old_far - old_near;
103
+ const shrink_threshold = HYSTERESIS * old_span;
104
+
105
+ if (new_near > old_near && new_near - old_near < shrink_threshold) {
106
+ new_near = old_near;
107
+ }
108
+ if (new_far < old_far && old_far - new_far < shrink_threshold) {
109
+ new_far = old_far;
110
+ }
111
+
112
+ camera.near = new_near;
113
+ camera.far = new_far;
114
+
115
+ // Rebuild the projection matrix from the tightened range — CameraView
116
+ // reads camera.projectionMatrix directly when capturing the frame's
117
+ // frustum, and the wide-range matrix from the depth-query step above is
118
+ // now stale.
119
+ camera.updateProjectionMatrix();
120
+ }
121
+
@@ -1 +1 @@
1
- {"version":3,"file":"LightSystem.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/light/LightSystem.js"],"names":[],"mappings":"AAuQA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,2DANW,YAAY,SACZ,WAAW,oBACX,MAAM,QAmEhB;;uBAvVsB,qBAAqB;sBAEtB,YAAY;AAQlC;IACI;;;;;OAKG;IACH,2CAsFC;IA1EG,kDAAsC;IAGtC,6DAEC;IAGD,eAAoB;IACpB,WAA2B;IAC3B,aAAwB;IAExB;;;;OAIG;IACH,mBAA0B;IAE1B;;;;OAIG;IACH,wBAA2B;IAE3B,gBAAkB;IAElB;;;;OAIG;IACH,kBAAoC;IAGpC;;;;OAIG;IACH,2BAA8B;IAC9B;;;;OAIG;IACH,iBAAoB;IAGpB;;;;OAIG;IACH,4BAAgD;IAqBpD,mCAEC;IAED;;;;OAIG;IACH,uBAHW,MAAM,SACN,MAAM,GAAC,MAAM,GAAC,OAAO,QAkB/B;IAED;;;;OAIG;IACH,4BAHW,KAAK,UACL,MAAM,QAMhB;IAED,2CAOC;IAED,4CASC;IAGD,4CAOC;IAED;;;;;OAKG;IACH,wCAmCC;IAED;;;;;;OAMG;IACH,sCAwBC;CACJ;sCA3PqC,8CAA8C;0BAC1D,qCAAqC;4CAFnB,uDAAuD"}
1
+ {"version":3,"file":"LightSystem.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/light/LightSystem.js"],"names":[],"mappings":"AAwQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,2DARW,YAAY,SACZ,WAAW,oBACX,MAAM,qCA0EhB;;uBArWsB,qBAAqB;sBAEtB,YAAY;AASlC;IACI;;;;;OAKG;IACH,2CAsFC;IA1EG,kDAAsC;IAGtC,6DAEC;IAGD,eAAoB;IACpB,WAA2B;IAC3B,aAAwB;IAExB;;;;OAIG;IACH,mBAA0B;IAE1B;;;;OAIG;IACH,wBAA2B;IAE3B,gBAAkB;IAElB;;;;OAIG;IACH,kBAAoC;IAGpC;;;;OAIG;IACH,2BAA8B;IAC9B;;;;OAIG;IACH,iBAAoB;IAGpB;;;;OAIG;IACH,4BAAgD;IAqBpD,mCAEC;IAED;;;;OAIG;IACH,uBAHW,MAAM,SACN,MAAM,GAAC,MAAM,GAAC,OAAO,QAkB/B;IAED;;;;OAIG;IACH,4BAHW,KAAK,UACL,MAAM,QAMhB;IAED,2CAOC;IAED,4CASC;IAGD,4CAOC;IAED;;;;;OAKG;IACH,wCAmCC;IAED;;;;;;OAMG;IACH,sCAwBC;CACJ;sCA5PqC,8CAA8C;0BAC1D,qCAAqC;4CAFnB,uDAAuD"}
@@ -12,6 +12,7 @@ import { Light } from './Light.js';
12
12
  import { LightContext } from "./LightContext.js";
13
13
  import { LightType } from "./LightType.js";
14
14
  import { compute_view_frustum_aabb_in_space } from "./shadow/compute_view_frustum_aabb_in_space.js";
15
+ import { extend_shadow_camera_near_for_casters } from "./shadow/extend_shadow_camera_near_for_casters.js";
15
16
  import { setShadowCameraDimensionsDiscrete } from "./shadow/setShadowCameraDimensionsDiscrete.js";
16
17
  import { ShadowManager } from "./shadow/ShadowManager.js";
17
18
  import { ThreeLightCache } from "./three/ThreeLightCache.js";
@@ -212,7 +213,7 @@ class LightSystem extends AbstractContextSystem {
212
213
 
213
214
  l.castShadow = true;
214
215
 
215
- three_update_shadow_camera_extents(this.__camera_object, l, this.settings.shadowDistance);
216
+ three_update_shadow_camera_extents(this.__camera_object, l, this.settings.shadowDistance, this.__graphics.layers);
216
217
 
217
218
  } else {
218
219
 
@@ -275,6 +276,12 @@ const DEFAULT_SHADOW_DISTANCE = 100;
275
276
  * across hundreds of world units). `shadow_distance` caps the depth of the view
276
277
  * frustum we fit against, trading visible-shadow distance for sharpness.
277
278
  *
279
+ * The receiver-only fit misses any occluder above the view frustum: a brick
280
+ * hanging in the air just above the camera's view casts no visible shadow on
281
+ * the ground below because it's clipped out of the shadow map. When `layers`
282
+ * is provided we walk every render layer's BVH for AABBs in the column above
283
+ * the receivers and pull `near` back to the closest caster found.
284
+ *
278
285
  * three.js leaves shadow.camera positioned wherever it last was — the renderer
279
286
  * doesn't call updateMatrices() until render time. updateMatrices is forced
280
287
  * here so matrixWorldInverse reflects the light's current pose; ShadowMapRenderer
@@ -285,8 +292,10 @@ const DEFAULT_SHADOW_DISTANCE = 100;
285
292
  * @param {number} [shadow_distance] max world-space view depth to cover with
286
293
  * shadow; defaults to {@link DEFAULT_SHADOW_DISTANCE}. Use Infinity to fit
287
294
  * the entire view frustum (sharp shadows close up become unaffordable).
295
+ * @param {RenderLayerManager} [layers] render layers, used to find shadow
296
+ * casters outside the view frustum. Omit to use receiver-only fit.
288
297
  */
289
- export function three_update_shadow_camera_extents(camera, light, shadow_distance = DEFAULT_SHADOW_DISTANCE) {
298
+ export function three_update_shadow_camera_extents(camera, light, shadow_distance = DEFAULT_SHADOW_DISTANCE, layers = null) {
290
299
 
291
300
  const shadow = light.shadow;
292
301
  if (shadow === undefined) {
@@ -345,6 +354,11 @@ export function three_update_shadow_camera_extents(camera, light, shadow_distanc
345
354
  shadow_camera.near = -scratch_aabb3.z1;
346
355
  shadow_camera.far = -scratch_aabb3.z0;
347
356
 
357
+ // Pull near back to include occluders above the view frustum so they cast
358
+ // visible shadows. Far stays at the receiver fit — occluders behind
359
+ // receivers can't shadow into the view.
360
+ extend_shadow_camera_near_for_casters(shadow_camera, layers);
361
+
348
362
  shadow_camera.updateProjectionMatrix();
349
363
 
350
364
  // small bias to prevent shadow acne
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Push the shadow camera's near plane back toward the light to include any
3
+ * occluder whose shadow would fall within the camera's x/y bounds, even when
4
+ * the occluder itself sits outside the main view frustum.
5
+ *
6
+ * Without this step the textbook "fit shadow camera to view frustum" leaves
7
+ * the near plane at the closest receiver — a brick floating just above the
8
+ * view frustum gets clipped out of the shadow map and casts no shadow on the
9
+ * ground below.
10
+ *
11
+ * Algorithm:
12
+ * 1. Take the shadow camera's existing left/right/top/bottom (already fit
13
+ * to receivers) as the x/y extents of a light-local query box. Extend z
14
+ * to a wide range so any caster along the light direction is captured.
15
+ * 2. Transform the 6 box planes to world space via the shadow camera's
16
+ * matrixWorld.
17
+ * 3. Walk every render layer's BVH through `compute_depth_range` against
18
+ * this world-space volume, measured along the shadow camera's view
19
+ * direction.
20
+ * 4. If the closest depth found is smaller than the camera's current near,
21
+ * replace near with it.
22
+ *
23
+ * Far is intentionally left alone: casters behind the farthest receiver (in
24
+ * light direction) can't shadow anything in the view.
25
+ *
26
+ * @param {THREE.OrthographicCamera} shadow_camera
27
+ * @param {RenderLayerManager} layers
28
+ */
29
+ export function extend_shadow_camera_near_for_casters(shadow_camera: THREE.OrthographicCamera, layers: RenderLayerManager): void;
30
+ //# sourceMappingURL=extend_shadow_camera_near_for_casters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extend_shadow_camera_near_for_casters.d.ts","sourceRoot":"","sources":["../../../../../../../src/engine/graphics/ecs/light/shadow/extend_shadow_camera_near_for_casters.js"],"names":[],"mappings":"AAgBA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qEAHW,MAAM,kBAAkB,oCAuDlC"}
@@ -0,0 +1,97 @@
1
+ import {
2
+ clipping_volume_matrix4_project
3
+ } from "../../../../../core/geom/3d/frustum/clipping_volume_matrix4_project.js";
4
+ import { hexahedron_from_aabb } from "../../../../../core/geom/3d/frustum/hexahedron_from_aabb.js";
5
+
6
+ const scratch_local_planes = new Float32Array(24);
7
+ const scratch_world_planes = new Float32Array(24);
8
+ const scratch_range = { near: 0, far: 0 };
9
+
10
+ // Half-extent of the z range used for the caster query. We want any object in
11
+ // the column above the receivers regardless of how far it sits along the light
12
+ // direction, so the query volume is effectively unbounded in z; the BVH walk's
13
+ // AABB-vs-frustum test is happy with a wide-but-finite range and avoids
14
+ // infinities propagating through plane math.
15
+ const CASTER_QUERY_HALF_RANGE = 1e7;
16
+
17
+ /**
18
+ * Push the shadow camera's near plane back toward the light to include any
19
+ * occluder whose shadow would fall within the camera's x/y bounds, even when
20
+ * the occluder itself sits outside the main view frustum.
21
+ *
22
+ * Without this step the textbook "fit shadow camera to view frustum" leaves
23
+ * the near plane at the closest receiver — a brick floating just above the
24
+ * view frustum gets clipped out of the shadow map and casts no shadow on the
25
+ * ground below.
26
+ *
27
+ * Algorithm:
28
+ * 1. Take the shadow camera's existing left/right/top/bottom (already fit
29
+ * to receivers) as the x/y extents of a light-local query box. Extend z
30
+ * to a wide range so any caster along the light direction is captured.
31
+ * 2. Transform the 6 box planes to world space via the shadow camera's
32
+ * matrixWorld.
33
+ * 3. Walk every render layer's BVH through `compute_depth_range` against
34
+ * this world-space volume, measured along the shadow camera's view
35
+ * direction.
36
+ * 4. If the closest depth found is smaller than the camera's current near,
37
+ * replace near with it.
38
+ *
39
+ * Far is intentionally left alone: casters behind the farthest receiver (in
40
+ * light direction) can't shadow anything in the view.
41
+ *
42
+ * @param {THREE.OrthographicCamera} shadow_camera
43
+ * @param {RenderLayerManager} layers
44
+ */
45
+ export function extend_shadow_camera_near_for_casters(shadow_camera, layers) {
46
+ if (layers === null) {
47
+ return;
48
+ }
49
+
50
+ const x0 = shadow_camera.left;
51
+ const x1 = shadow_camera.right;
52
+ const y0 = shadow_camera.bottom;
53
+ const y1 = shadow_camera.top;
54
+
55
+ hexahedron_from_aabb(
56
+ scratch_local_planes, 0,
57
+ x0, y0, -CASTER_QUERY_HALF_RANGE,
58
+ x1, y1, CASTER_QUERY_HALF_RANGE
59
+ );
60
+
61
+ clipping_volume_matrix4_project(
62
+ scratch_world_planes, 0,
63
+ scratch_local_planes, 0,
64
+ 6,
65
+ shadow_camera.matrixWorld.elements
66
+ );
67
+
68
+ // Depth plane: world-space, normal along the shadow camera's view direction
69
+ // (-Z column of matrixWorld), passing through the camera position. A point's
70
+ // distance to this plane equals its depth in front of the camera.
71
+ const m = shadow_camera.matrixWorld.elements;
72
+ const nx = -m[8];
73
+ const ny = -m[9];
74
+ const nz = -m[10];
75
+ const plane_constant = -(nx * m[12] + ny * m[13] + nz * m[14]);
76
+
77
+ scratch_range.near = Number.POSITIVE_INFINITY;
78
+ scratch_range.far = Number.NEGATIVE_INFINITY;
79
+
80
+ layers.traverse((layer) => {
81
+ if (!layer.state.visible) {
82
+ return;
83
+ }
84
+
85
+ const compute = layer.compute_depth_range;
86
+
87
+ if (compute === null) {
88
+ return;
89
+ }
90
+
91
+ compute(scratch_range, scratch_world_planes, nx, ny, nz, plane_constant);
92
+ });
93
+
94
+ if (isFinite(scratch_range.near) && scratch_range.near < shadow_camera.near) {
95
+ shadow_camera.near = scratch_range.near;
96
+ }
97
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"MeshSystem.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/mesh/MeshSystem.js"],"names":[],"mappings":"AA6BA;IAiZI;;;;;;;OAOG;IACH,kCANW,IAAI,uCAEJ,OAAO,GACL,OAAO,CAQnB;IA7ZD;;;;;OAKG;IACH,4BAwDC;IAjDG;;;;OAIG;IACH,iBAAsB;IAEtB,iDAAqC;IAErC,4DAEC;IAGD;;;OAGG;IACH,2BAAgC;IAEhC,sBAAwB;IAExB;;;OAGG;IACH,YAFU,MAAO,MAAO,aAAa,CAAC,CAAC,CAEnB;IAEpB,cAAwB;IAExB;;;OAGG;IACH,aAFU,cAAY,IAAI,CAEH;IAEvB;;;;OAIG;IACH,+BAAmC;IAEnC;;;;OAIG;IACH,qBAA6B;IAGjC;;;;;;OAMG;IACH,8BALW,MAAM,4DAGN,IAAI,QA+Bd;IAED,2CAuDC;IAED;;;;OAIG;IACH,gCAHoB,IAAI,QAAE,MAAM,+BA8C/B;IAED,4CAEC;IAED;;;;;OAKG;IACH,YAHW,IAAI,aADJ,SAAS,UAET,MAAM,QAkChB;IAED;;;;;OAKG;IACH,cAHW,IAAI,aADJ,SAAS,YAET,MAAM,QAmChB;IAED;;;;OAIG;IACH,gCAFW,IAAI,QA+Ed;IAED,6BAoBC;CAgBJ;uBAnbsB,wBAAwB;0BACrB,qCAAqC;iBAO/B,WAAW;4CAVC,uDAAuD;8BAJrE,iDAAiD;oBAE3D,kCAAkC"}
1
+ {"version":3,"file":"MeshSystem.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/mesh/MeshSystem.js"],"names":[],"mappings":"AA8BA;IAsZI;;;;;;;OAOG;IACH,kCANW,IAAI,uCAEJ,OAAO,GACL,OAAO,CAQnB;IAlaD;;;;;OAKG;IACH,4BAwDC;IAjDG;;;;OAIG;IACH,iBAAsB;IAEtB,iDAAqC;IAErC,4DAEC;IAGD;;;OAGG;IACH,2BAAgC;IAEhC,sBAAwB;IAExB;;;OAGG;IACH,YAFU,MAAO,MAAO,aAAa,CAAC,CAAC,CAEnB;IAEpB,cAAwB;IAExB;;;OAGG;IACH,aAFU,cAAY,IAAI,CAEH;IAEvB;;;;OAIG;IACH,+BAAmC;IAEnC;;;;OAIG;IACH,qBAA6B;IAGjC;;;;;;OAMG;IACH,8BALW,MAAM,4DAGN,IAAI,QA+Bd;IAED,2CA4DC;IAED;;;;OAIG;IACH,gCAHoB,IAAI,QAAE,MAAM,+BA8C/B;IAED,4CAEC;IAED;;;;;OAKG;IACH,YAHW,IAAI,aADJ,SAAS,UAET,MAAM,QAkChB;IAED;;;;;OAKG;IACH,cAHW,IAAI,aADJ,SAAS,YAET,MAAM,QAmChB;IAED;;;;OAIG;IACH,gCAFW,IAAI,QA+Ed;IAED,6BAoBC;CAgBJ;uBAxbsB,wBAAwB;0BACrB,qCAAqC;iBAO/B,WAAW;4CAVC,uDAAuD;8BAJrE,iDAAiD;oBAE3D,kCAAkC"}
@@ -1,6 +1,7 @@
1
1
  import { BoxBufferGeometry, MeshLambertMaterial } from "three";
2
2
  import { assert } from "../../../../core/assert.js";
3
3
  import { BVH } from "../../../../core/bvh2/bvh3/BVH.js";
4
+ import { bvh_query_depth_range_in_frustum } from "../../../../core/bvh2/bvh3/query/bvh_query_depth_range_in_frustum.js";
4
5
  import { SignalBinding } from "../../../../core/events/signal/SignalBinding.js";
5
6
 
6
7
  import Vector3 from "../../../../core/geom/Vector3.js";
@@ -157,6 +158,11 @@ export class MeshSystem extends System {
157
158
  }
158
159
  )
159
160
 
161
+ const bvh = this.__bvh_binary;
162
+ this.renderLayer.compute_depth_range = (result, frustum, nx, ny, nz, c) => {
163
+ bvh_query_depth_range_in_frustum(result, bvh, frustum, nx, ny, nz, c);
164
+ };
165
+
160
166
  const visibleSet = this.renderLayer.visibleSet;
161
167
 
162
168
  visibleSet.onAdded.add(m => {
@@ -1 +1 @@
1
- {"version":3,"file":"ShadedGeometrySystem.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js"],"names":[],"mappings":"AA6DA;IACI;;;OAGG;IACH,4BAmEC;IAjEG,2DAA+C;IAE/C;;;;OAIG;IACH,iBAAsB;IAEtB;;;;OAIG;IACH,uBAA0B;IAE1B;;;;OAIG;IACH,wBAAgC;IAEhC;;;;OAIG;IACH,4BAAoC;IAEpC;;;;OAIG;IACH,kCAA0C;IAE1C;;;;OAIG;IACH,qBAA6B;IAI7B,0BAYE;IAEF,yBAIC;IAIL;;;OAGG;IACH,eAEC;IAED;;;OAGG;IACH,4BAFa,IAAI,MAAM,EAAC,MAAM,CAAC,CAI9B;IAED;;;;OAIG;IACH,+BAHW,MAAM,+CAsBhB;IAED;;;;OAIG;IACH,iCAHW,MAAM,GACL,OAAO,CAmBlB;IAED;;;;OAIG;IACH,4BASC;IAED;;;;OAIG;IACH,8BAMC;IAED,2CAgCC;IAED,4CAcC;IAED;;;;;OAKG;IACH,SAJW,cAAc,KACd,SAAS,UACT,MAAM,QAqBhB;IAED;;;;;OAKG;IACH,WAJW,cAAc,KACd,SAAS,UACT,MAAM,QAsBhB;IAED;;;;;;OAMG;IACH,4BALW,MAAM,EAAE,iBACR,MAAM,UACN,MAAM,EAAE,GAAC,UAAU,MAAM,CAAC,GACxB,MAAM,CAQlB;IAED;;;;;;;;;;;OAWG;IACH,kBAVW,MAAM,YACN,MAAM,YACN,MAAM,eACN,MAAM,eACN,MAAM,eACN,MAAM,uEAGJ;QAAC,MAAM,EAAC,MAAM,CAAC;QAAC,IAAI,EAAC,cAAc,CAAC;QAAC,OAAO,EAAE,aAAa,CAAA;KAAC,EAAE,CA8D1E;IAGD;;;;;;;;;;;;OAYG;IACH,wBAXW,aAAa,YACb,MAAM,YACN,MAAM,YACN,MAAM,eACN,MAAM,eACN,MAAM,eACN,MAAM,uEAGJ;QAAC,MAAM,EAAC,MAAM,CAAC;QAAC,IAAI,EAAC,cAAc,CAAA;KAAC,GAAC,SAAS,CAmF1D;CACJ;uBAxfsB,wBAAwB;0BACrB,qCAAqC;+BAGhC,qBAAqB;iBARnC,uCAAuC;oBAXpC,mCAAmC;2BAO5B,yCAAyC;8BAEtC,2CAA2C"}
1
+ {"version":3,"file":"ShadedGeometrySystem.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js"],"names":[],"mappings":"AA8DA;IACI;;;OAGG;IACH,4BAmEC;IAjEG,2DAA+C;IAE/C;;;;OAIG;IACH,iBAAsB;IAEtB;;;;OAIG;IACH,uBAA0B;IAE1B;;;;OAIG;IACH,wBAAgC;IAEhC;;;;OAIG;IACH,4BAAoC;IAEpC;;;;OAIG;IACH,kCAA0C;IAE1C;;;;OAIG;IACH,qBAA6B;IAI7B,0BAYE;IAEF,yBAIC;IAIL;;;OAGG;IACH,eAEC;IAED;;;OAGG;IACH,4BAFa,IAAI,MAAM,EAAC,MAAM,CAAC,CAI9B;IAED;;;;OAIG;IACH,+BAHW,MAAM,+CAsBhB;IAED;;;;OAIG;IACH,iCAHW,MAAM,GACL,OAAO,CAmBlB;IAED;;;;OAIG;IACH,4BASC;IAED;;;;OAIG;IACH,8BAMC;IAED,2CAqCC;IAED,4CAcC;IAED;;;;;OAKG;IACH,SAJW,cAAc,KACd,SAAS,UACT,MAAM,QAqBhB;IAED;;;;;OAKG;IACH,WAJW,cAAc,KACd,SAAS,UACT,MAAM,QAsBhB;IAED;;;;;;OAMG;IACH,4BALW,MAAM,EAAE,iBACR,MAAM,UACN,MAAM,EAAE,GAAC,UAAU,MAAM,CAAC,GACxB,MAAM,CAQlB;IAED;;;;;;;;;;;OAWG;IACH,kBAVW,MAAM,YACN,MAAM,YACN,MAAM,eACN,MAAM,eACN,MAAM,eACN,MAAM,uEAGJ;QAAC,MAAM,EAAC,MAAM,CAAC;QAAC,IAAI,EAAC,cAAc,CAAC;QAAC,OAAO,EAAE,aAAa,CAAA;KAAC,EAAE,CA8D1E;IAGD;;;;;;;;;;;;OAYG;IACH,wBAXW,aAAa,YACb,MAAM,YACN,MAAM,YACN,MAAM,eACN,MAAM,eACN,MAAM,eACN,MAAM,uEAGJ;QAAC,MAAM,EAAC,MAAM,CAAC;QAAC,IAAI,EAAC,cAAc,CAAA;KAAC,GAAC,SAAS,CAmF1D;CACJ;uBA7fsB,wBAAwB;0BACrB,qCAAqC;+BAGhC,qBAAqB;iBARnC,uCAAuC;oBAZpC,mCAAmC;2BAQ5B,yCAAyC;8BAEtC,2CAA2C"}
@@ -1,6 +1,7 @@
1
1
  import { mat4 } from "gl-matrix";
2
2
  import { assert } from "../../../../core/assert.js";
3
3
  import { BVH } from "../../../../core/bvh2/bvh3/BVH.js";
4
+ import { bvh_query_depth_range_in_frustum } from "../../../../core/bvh2/bvh3/query/bvh_query_depth_range_in_frustum.js";
4
5
  import { bvh_query_leaves_generic } from "../../../../core/bvh2/bvh3/query/bvh_query_leaves_generic.js";
5
6
  import {
6
7
  bvh_query_user_data_overlaps_frustum
@@ -256,6 +257,11 @@ export class ShadedGeometrySystem extends System {
256
257
  return ctx.collect(destination, destination_offset, graphics.renderer, view, this.__bvh_binary, ecd);
257
258
  });
258
259
 
260
+ const bvh = this.__bvh_binary;
261
+ this.__render_layer.compute_depth_range = (result, frustum, nx, ny, nz, c) => {
262
+ bvh_query_depth_range_in_frustum(result, bvh, frustum, nx, ny, nz, c);
263
+ };
264
+
259
265
  this.__optimization_task.state.set(TaskState.INITIAL);
260
266
  engine.executor.run(this.__optimization_task);
261
267
 
@@ -1 +1 @@
1
- {"version":3,"file":"Trail2DSystem.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/trail2d/Trail2DSystem.js"],"names":[],"mappings":";AAyBA;IAkCI;;;OAGG;IACH,4BA4BC;IAjED,oDAAoC;IAEpC,+DAEE;IAEF;;;OAGG;IACH,WAFU,4BAA4B,CAES;IAE/C;;;;OAIG;IACH,wBAAiC;IAGjC;;;;OAIG;IACH,oBAAgB;IAEhB;;;OAGG;IACH,YAAgB;IAcZ;;;;OAIG;IACH,iBAAsB;IAEtB;;;OAGG;IACH,UAFU,cAAc,CAEO;IAE/B;;;OAGG;IACH,aAFU,cAAY,IAAI,CAEH;IAK3B,2CAcC;IAED,4CAIC;IAED;;;;;OAKG;IACH,sBAoDC;IAED;;;;;OAKG;IACH,YAHW,OAAO,aADP,SAAS,YAET,MAAM,QAahB;IAED;;;;;OAKG;IACH,kBAJW,OAAO,aACP,SAAS,UACT,MAAM,QAShB;IAED;;;;OAIG;IACH,yBAHW,OAAO,aACP,SAAS,QAoCnB;IAED,6BAWC;CACJ;uBA/PsB,wBAAwB;0BACrB,qCAAqC;oBAY3C,cAAc;4CAdU,uDAAuD;6CAYtD,yDAAyD;+BARvE,yBAAyB"}
1
+ {"version":3,"file":"Trail2DSystem.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/trail2d/Trail2DSystem.js"],"names":[],"mappings":";AA0BA;IAkCI;;;OAGG;IACH,4BA4BC;IAjED,oDAAoC;IAEpC,+DAEE;IAEF;;;OAGG;IACH,WAFU,4BAA4B,CAES;IAE/C;;;;OAIG;IACH,wBAAiC;IAGjC;;;;OAIG;IACH,oBAAgB;IAEhB;;;OAGG;IACH,YAAgB;IAcZ;;;;OAIG;IACH,iBAAsB;IAEtB;;;OAGG;IACH,UAFU,cAAc,CAEO;IAE/B;;;OAGG;IACH,aAFU,cAAY,IAAI,CAEH;IAK3B,2CAmBC;IAED,4CAIC;IAED;;;;;OAKG;IACH,sBAoDC;IAED;;;;;OAKG;IACH,YAHW,OAAO,aADP,SAAS,YAET,MAAM,QAahB;IAED;;;;;OAKG;IACH,kBAJW,OAAO,aACP,SAAS,UACT,MAAM,QAShB;IAED;;;;OAIG;IACH,yBAHW,OAAO,aACP,SAAS,QAoCnB;IAED,6BAWC;CACJ;uBApQsB,wBAAwB;0BACrB,qCAAqC;oBAY3C,cAAc;4CAdU,uDAAuD;6CAYtD,yDAAyD;+BARvE,yBAAyB"}
@@ -1,5 +1,6 @@
1
1
  import { assert } from "../../../../core/assert.js";
2
2
  import { BVH } from "../../../../core/bvh2/bvh3/BVH.js";
3
+ import { bvh_query_depth_range_in_frustum } from "../../../../core/bvh2/bvh3/query/bvh_query_depth_range_in_frustum.js";
3
4
  import Vector3 from '../../../../core/geom/Vector3.js';
4
5
  import { clamp } from "../../../../core/math/clamp.js";
5
6
  import { max2 } from "../../../../core/math/max2.js";
@@ -104,6 +105,11 @@ class Trail2DSystem extends System {
104
105
  }
105
106
  );
106
107
 
108
+ const bvh = this.bvh;
109
+ this.renderLayer.compute_depth_range = (result, frustum, nx, ny, nz, c) => {
110
+ bvh_query_depth_range_in_frustum(result, bvh, frustum, nx, ny, nz, c);
111
+ };
112
+
107
113
  this.__ribbon_plugin = await this.__engine.plugins.acquire(RibbonXPlugin);
108
114
  }
109
115
 
@@ -1 +1 @@
1
- {"version":3,"file":"WaterSystem.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/water/WaterSystem.js"],"names":[],"mappings":";AAYA;IAyBI;;;;OAIG;IACH,sCAYC;IAzCD,+BAAuB;IAEvB;;;OAGG;IACH,cAFU,GAAG,CAEG;IAGhB,cAAY;IAEZ;;;OAGG;IACH,aAFU,KAAK,EAAE,CAEA;IAEjB;;;;OAIG;IACH,qBAAiB;IAWb,+BAA8B;IAE9B;;;OAGG;IACH,aAFU,cAAY,IAAI,CAEH;IAK3B,4CAMC;IAED,2CA4DC;IAED;;;;OAIG;IACH,gBAHW,KAAK,UACL,MAAM,QAsDhB;IAED;;;;OAIG;IACH,kBAHW,KAAK,UACL,MAAM,QAgBhB;IAED,2BAgCC;IAED;;;;;OAKG;IACH,0BAUC;IAED,6BAcC;CACJ;;;;uBA/QsB,wBAAwB;kBAM7B,YAAY;oBAPV,mCAAmC"}
1
+ {"version":3,"file":"WaterSystem.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/water/WaterSystem.js"],"names":[],"mappings":";AAaA;IAyBI;;;;OAIG;IACH,sCAYC;IAzCD,+BAAuB;IAEvB;;;OAGG;IACH,cAFU,GAAG,CAEG;IAGhB,cAAY;IAEZ;;;OAGG;IACH,aAFU,KAAK,EAAE,CAEA;IAEjB;;;;OAIG;IACH,qBAAiB;IAWb,+BAA8B;IAE9B;;;OAGG;IACH,aAFU,cAAY,IAAI,CAEH;IAK3B,4CAMC;IAED,2CAiEC;IAED;;;;OAIG;IACH,gBAHW,KAAK,UACL,MAAM,QAsDhB;IAED;;;;OAIG;IACH,kBAHW,KAAK,UACL,MAAM,QAgBhB;IAED,2BAgCC;IAED;;;;;OAKG;IACH,0BAUC;IAED,6BAcC;CACJ;;;;uBApRsB,wBAAwB;kBAM7B,YAAY;oBARV,mCAAmC"}
@@ -1,6 +1,7 @@
1
1
  import { BackSide, PlaneBufferGeometry } from 'three';
2
2
  import { assert } from "../../../../core/assert.js";
3
3
  import { BVH } from "../../../../core/bvh2/bvh3/BVH.js";
4
+ import { bvh_query_depth_range_in_frustum } from "../../../../core/bvh2/bvh3/query/bvh_query_depth_range_in_frustum.js";
4
5
  import { System } from '../../../ecs/System.js';
5
6
  import { obtainTerrain } from "../../../ecs/terrain/util/obtainTerrain.js";
6
7
  import { make_bvh_visibility_builder } from "../../render/make_bvh_visibility_builder.js";
@@ -90,6 +91,11 @@ class WaterSystem extends System {
90
91
  }
91
92
  )
92
93
 
94
+ const bvh = this.bvh;
95
+ this.renderLayer.compute_depth_range = (result, frustum, nx, ny, nz, c) => {
96
+ bvh_query_depth_range_in_frustum(result, bvh, frustum, nx, ny, nz, c);
97
+ };
98
+
93
99
 
94
100
  const self = this;
95
101
 
@@ -41,6 +41,7 @@ async function main(engine) {
41
41
  showFps: false,
42
42
  enableLights: true,
43
43
  enableShadows: true,
44
+ cameraAutoClip: true,
44
45
  });
45
46
 
46
47
 
@@ -1 +1 @@
1
- {"version":3,"file":"ParticleEmitterSystem.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/particles/ecs/ParticleEmitterSystem.js"],"names":[],"mappings":"AAYA;IAeI;;;;;OAKG;IACH,4BAwBC;IA5CD,yCAA4C;IAE5C,uEAEE;IAEF;;;OAGG;IACH,aAFU,cAAY,IAAI,CAEP;IAEnB,kBAAgB;IAcZ;;;OAGG;IACH,+BAAqC;IAErC;;;OAGG;IACH,2BAAuC;IAEvC;;;OAGG;IACH,gBAFU,gBAAgB,CAE2E;IAIzG,2CAyHC;IAED,4CAEC;IAED;;;;;OAKG;IACH,cAJW,eAAe,aACf,SAAS,qBAoCnB;IAED;;;;;OAKG;IACH,gBAJW,eAAe,aACf,SAAS,qBAenB;IAED,6BAEC;CACJ;uBAtPsB,wBAAwB;gCAIf,iDAAiD;4CANrC,uDAAuD;iCAQlE,0CAA0C;0BALjD,qCAAqC"}
1
+ {"version":3,"file":"ParticleEmitterSystem.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/particles/ecs/ParticleEmitterSystem.js"],"names":[],"mappings":"AAaA;IAeI;;;;;OAKG;IACH,4BAwBC;IA5CD,yCAA4C;IAE5C,uEAEE;IAEF;;;OAGG;IACH,aAFU,cAAY,IAAI,CAEP;IAEnB,kBAAgB;IAcZ;;;OAGG;IACH,+BAAqC;IAErC;;;OAGG;IACH,2BAAuC;IAEvC;;;OAGG;IACH,gBAFU,gBAAgB,CAE2E;IAIzG,2CA8HC;IAED,4CAEC;IAED;;;;;OAKG;IACH,cAJW,eAAe,aACf,SAAS,qBAoCnB;IAED;;;;;OAKG;IACH,gBAJW,eAAe,aACf,SAAS,qBAenB;IAED,6BAEC;CACJ;uBA3PsB,wBAAwB;gCAIf,iDAAiD;4CANrC,uDAAuD;iCAQlE,0CAA0C;0BALjD,qCAAqC"}
@@ -1,4 +1,5 @@
1
1
  import { assert } from "../../../../core/assert.js";
2
+ import { bvh_query_depth_range_in_frustum } from "../../../../core/bvh2/bvh3/query/bvh_query_depth_range_in_frustum.js";
2
3
  import { ResourceAccessKind } from "../../../../core/model/ResourceAccessKind.js";
3
4
  import { ResourceAccessSpecification } from "../../../../core/model/ResourceAccessSpecification.js";
4
5
  import { ImageRGBADataLoader } from "../../../asset/loaders/image/ImageRGBADataLoader.js";
@@ -85,6 +86,11 @@ export class ParticleEmitterSystem extends System {
85
86
  }
86
87
  );
87
88
 
89
+ const bvh = this.particleEngine.bvh;
90
+ renderLayer.compute_depth_range = (result, frustum, nx, ny, nz, c) => {
91
+ bvh_query_depth_range_in_frustum(result, bvh, frustum, nx, ny, nz, c);
92
+ };
93
+
88
94
  renderLayer.visibleSet.onAdded.add((points) => {
89
95
  /**
90
96
  *
@@ -17,4 +17,6 @@ export class RenderLayer {
17
17
  * @deprecated
18
18
  */
19
19
  visibleSet: IncrementalDeltaSet<Object3D>
20
+
21
+ compute_depth_range: ((result: { near: number; far: number }, frustum: ArrayLike<number>, plane_normal_x: number, plane_normal_y: number, plane_normal_z: number, plane_constant: number) => void) | null
20
22
  }
@@ -1 +1 @@
1
- {"version":3,"file":"RenderLayer.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/render/layers/RenderLayer.js"],"names":[],"mappings":"AAKA;IAEI;;;OAGG;IACH,OAFU,gBAAgB,CAEK;IAE/B;;;OAGG;IACH,MAFU,SAAO,IAAI,CAET;IAEZ;;;;OAIG;IACH,SAFU,OAAO,CAED;IAEhB;;;OAGG;IACH,2CAAgC;IAEhC;;;;;OAKG;IACH,YAFU,oBAAoB,MAAM,QAAQ,CAAC,CAEe;IAU5D;;;OAGG;IACH,0BAEC;IAdD;;;OAGG;IACH,uBAEC;IAUD;;;;;;;;;OASG;IACH,qDALW,MAAM,OACN,MAAM,sCAMhB;IAED;;;;;;OAMG;IACH,6BALW,MAAM,QAAQ,EAAE,sBAChB,MAAM,qBAEJ,MAAM,CAIlB;CACJ;iCA7EgC,uBAAuB;oCADpB,sCAAsC"}
1
+ {"version":3,"file":"RenderLayer.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/render/layers/RenderLayer.js"],"names":[],"mappings":"AAKA;IAEI;;;OAGG;IACH,OAFU,gBAAgB,CAEK;IAE/B;;;OAGG;IACH,MAFU,SAAO,IAAI,CAET;IAEZ;;;;OAIG;IACH,SAFU,OAAO,CAED;IAEhB;;;OAGG;IACH,2CAAgC;IAEhC;;;;;OAKG;IACH,YAFU,oBAAoB,MAAM,QAAQ,CAAC,CAEe;IAU5D;;;OAGG;IACH,0BAEC;IAdD;;;OAGG;IACH,uBAEC;IAUD;;;;;;;;;OASG;IACH,qDALW,MAAM,OACN,MAAM,sCAMhB;IAED;;;;;;OAMG;IACH,6BALW,MAAM,QAAQ,EAAE,sBAChB,MAAM,qBAEJ,MAAM,CAIlB;IAED;;;;;;;;;;;OAWG;IACH,8BAFmB;QAAC,IAAI,EAAC,MAAM,CAAC;QAAA,GAAG,EAAC,MAAM,CAAA;KAAC,WAAU,UAAU,MAAM,CAAC,kBAAiB,MAAM,kBAAiB,MAAM,kBAAiB,MAAM,kBAAiB,MAAM,KAAK,IAAI,CAEhJ;CAC9B;iCA3FgC,uBAAuB;oCADpB,sCAAsC"}
@@ -78,4 +78,18 @@ export class RenderLayer {
78
78
  buildVisibleSet(destination, destination_offset, view) {
79
79
  throw new Error('deprecated');
80
80
  }
81
+
82
+ /**
83
+ * Expand a (near, far) depth range to cover this layer's content that
84
+ * intersects a frustum. Driven by the camera's autoClip path; defaults to
85
+ * a no-op for layers that don't own a BVH or don't participate in depth
86
+ * fitting (e.g. screen-space overlays).
87
+ *
88
+ * Systems with a BVH wire this from their `startup` alongside
89
+ * `buildVisibleSet` — typically using
90
+ * {@link bvh_query_depth_range_in_frustum} against their own BVH.
91
+ *
92
+ * @type {((result:{near:number,far:number}, frustum:ArrayLike<number>, plane_normal_x:number, plane_normal_y:number, plane_normal_z:number, plane_constant:number) => void) | null}
93
+ */
94
+ compute_depth_range = null;
81
95
  }
@@ -152,7 +152,7 @@ export class MonteCarloTreeSearch {
152
152
  assert.notNaN(s, 'computed Node score');
153
153
  assert.isFinite(s, `computed Node score`);
154
154
 
155
- score = s + randomRoll;
155
+ score = s + randomRoll * 1e-5;
156
156
  } else {
157
157
 
158
158
  //use a constant value for unexplored nodes