@woosh/meep-engine 2.68.0 → 2.70.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.
Files changed (58) hide show
  1. package/build/bundle-worker-image-decoder.js +1 -1
  2. package/build/bundle-worker-terrain.js +1 -1
  3. package/build/meep.cjs +1090 -1581
  4. package/build/meep.min.js +1 -1
  5. package/build/meep.module.js +1090 -1581
  6. package/package.json +1 -1
  7. package/src/core/__module.js +1 -0
  8. package/src/core/binary/BinaryBuffer.js +37 -31
  9. package/src/core/bvh2/binary/2/BinaryUint32BVH.js +76 -52
  10. package/src/core/bvh2/binary/2/BinaryUint32BVH.spec.js +5 -7
  11. package/src/core/bvh2/binary/2/bvh32_query_user_data_overlaps_clipping_volume.js +94 -0
  12. package/src/core/bvh2/binary/2/bvh32_query_user_data_ray.js +17 -18
  13. package/src/core/bvh2/bvh3/query/BVHQueryIntersectsFrustum.js +4 -2
  14. package/src/core/geom/3d/aabb/AABB3.js +14 -14
  15. package/src/core/geom/3d/aabb/aabb3_array_intersects_clipping_volume_array.js +30 -0
  16. package/src/core/geom/3d/aabb/aabb3_intersects_clipping_volume_array.js +51 -0
  17. package/src/core/geom/3d/cone/compute_bounding_cone_of_2_cones.js +3 -2
  18. package/src/core/geom/3d/frustum/{read_frustum_planes_to_array.js → read_three_planes_to_array.js} +5 -3
  19. package/src/core/geom/3d/morton/v3_morton_encode_bounded.js +34 -0
  20. package/src/core/geom/3d/morton/v3_morton_encode_transformed.js +2 -1
  21. package/src/core/geom/3d/quaternion/quat3_createFromAxisAngle.js +11 -0
  22. package/src/core/geom/3d/quaternion/quat_decode_from_uint32.js +53 -0
  23. package/src/core/geom/3d/quaternion/quat_encode_to_uint32.js +106 -0
  24. package/src/core/geom/3d/triangle/triangle_intersects_clipping_volume.js +51 -0
  25. package/src/core/geom/Quaternion.js +8 -142
  26. package/src/core/geom/Vector2.js +6 -7
  27. package/src/core/geom/Vector3.js +15 -82
  28. package/src/core/geom/vec3/v3_binary_equality_decode.js +44 -0
  29. package/src/core/geom/vec3/v3_binary_equality_encode.js +47 -0
  30. package/src/core/primitives/numbers/computeHashFloat.js +2 -2
  31. package/src/engine/ecs/terrain/ecs/TerrainSystem.js +2 -2
  32. package/src/engine/ecs/terrain/ecs/makeTerrainWorkerProxy.js +1 -1
  33. package/src/engine/ecs/terrain/tiles/TerrainTile.js +9 -46
  34. package/src/engine/ecs/transform/Transform.js +8 -9
  35. package/src/engine/ecs/transform/TransformSerializationAdapter.js +18 -7
  36. package/src/engine/graphics/ecs/mesh/Mesh.js +11 -11
  37. package/src/engine/graphics/geometry/buffered/query/GeometrySpatialQueryAccelerator.d.ts +2 -2
  38. package/src/engine/graphics/geometry/buffered/query/GeometrySpatialQueryAccelerator.js +79 -36
  39. package/src/engine/graphics/geometry/buffered/query/bvh32_geometry_overlap_clipping_volume.js +88 -0
  40. package/src/engine/graphics/geometry/buffered/query/bvh32_geometry_raycast.js +108 -0
  41. package/src/engine/graphics/geometry/bvh/buffered/bvh32_from_indexed_geometry.js +4 -30
  42. package/src/engine/graphics/geometry/bvh/buffered/bvh32_from_unindexed_geometry.js +30 -0
  43. package/src/engine/graphics/geometry/bvh/buffered/bvh32_set_leaf_from_triangle.js +41 -0
  44. package/src/engine/graphics/render/forward_plus/LightManager.js +2 -2
  45. package/src/engine/graphics/render/forward_plus/query/query_bvh_frustum_from_texture.js +2 -2
  46. package/src/engine/graphics/render/view/CameraView.js +8 -8
  47. package/src/core/bvh2/binary/BinaryBVH.js +0 -281
  48. package/src/core/bvh2/binary/IndexedBinaryBVH.js +0 -407
  49. package/src/core/bvh2/binary/IndexedBinaryBVH.spec.js +0 -27
  50. package/src/core/bvh2/binary/IndexedBinaryBVHVisitor.js +0 -11
  51. package/src/core/bvh2/binary/NodeType.js +0 -8
  52. package/src/core/bvh2/binary/RayLeafIntersectionVisitor.js +0 -59
  53. package/src/core/geom/3d/aabb/aabb3_array_intersects_frustum_array.js +0 -20
  54. package/src/core/geom/3d/aabb/aabb3_intersects_frustum_array.js +0 -35
  55. package/src/engine/graphics/geometry/buffered/query/ClippingPlaneContainmentComputingVisitor.js +0 -195
  56. package/src/engine/graphics/geometry/buffered/query/GeometryVisitor.js +0 -87
  57. package/src/engine/graphics/geometry/buffered/query/RaycastNearestHitComputingVisitor.js +0 -206
  58. package/src/engine/graphics/geometry/bvh/buffered/BinaryBVHFromBufferGeometry.js +0 -123
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "description": "Fully featured ECS game engine written in JavaScript",
6
6
  "type": "module",
7
7
  "author": "Alexander Goldring",
8
- "version": "2.68.0",
8
+ "version": "2.70.0",
9
9
  "main": "build/meep.module.js",
10
10
  "module": "build/meep.module.js",
11
11
  "exports": {
@@ -9,3 +9,4 @@ export * from "./geom/Vector1.js";
9
9
  export * from "./events/signal/Signal.js";
10
10
  export * from "./events/signal/SignalBinding.js";
11
11
  export * from "./geom/Quaternion.js";
12
+ export { quat3_createFromAxisAngle } from "./geom/3d/quaternion/quat3_createFromAxisAngle.js";
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import { assert } from "../assert.js";
6
6
  import { array_copy } from "../collection/array/array_copy.js";
7
+ import { typed_array_copy } from "../collection/array/typed/typed_array_copy.js";
7
8
 
8
9
  /**
9
10
  *
@@ -142,8 +143,7 @@ export class BinaryBuffer {
142
143
  const newData = new Uint8Array(capacity);
143
144
 
144
145
  //copy old data
145
- const copyLength = Math.min(newData.length, oldData.length);
146
- newData.set(oldData.subarray(0, copyLength), 0);
146
+ typed_array_copy(oldData, newData);
147
147
 
148
148
  this.data = newData.buffer;
149
149
  this.__data_uint8 = newData;
@@ -152,15 +152,24 @@ export class BinaryBuffer {
152
152
  this.capacity = capacity;
153
153
  }
154
154
 
155
- ensureCapacity(minCapacity) {
156
- if (this.capacity < minCapacity) {
157
- const newCapacity = Math.ceil(Math.max(
158
- minCapacity,
159
- this.capacity * this.__growFactor,
160
- this.capacity + MIN_GROWTH_STEP
161
- ));
162
- this.setCapacity(newCapacity);
155
+ /**
156
+ *
157
+ * @param {number} min_capacity
158
+ */
159
+ ensureCapacity(min_capacity) {
160
+ const existing_capacity = this.capacity;
161
+
162
+ if (existing_capacity >= min_capacity) {
163
+ return;
163
164
  }
165
+
166
+ const new_capacity = Math.ceil(Math.max(
167
+ min_capacity,
168
+ existing_capacity * this.__growFactor,
169
+ existing_capacity + MIN_GROWTH_STEP
170
+ ));
171
+
172
+ this.setCapacity(new_capacity);
164
173
  }
165
174
 
166
175
  readFloat32() {
@@ -825,16 +834,14 @@ export class BinaryBuffer {
825
834
  //mark non-NULL
826
835
  this.writeUint32(len);
827
836
 
828
- const startPosition = this.position;
829
-
830
- let at = startPosition; // output position
831
-
832
- let tlen = Math.max(32, len + (len >> 1) + 7); // 1.5x size
837
+ let cursor = this.position; // output position
833
838
 
834
- this.ensureCapacity(tlen + at);
839
+ const expected_byte_size = Math.max(32, len + (len >> 1) + 7); // 1.5x size
835
840
 
836
- let target = this.__data_uint8; // ... but at 8 byte offset
841
+ this.ensureCapacity(expected_byte_size + cursor);
837
842
 
843
+ let target = this.__data_uint8;
844
+ let capacity = this.capacity;
838
845
 
839
846
  while (pos < len) {
840
847
  let value = string.charCodeAt(pos++);
@@ -853,37 +860,36 @@ export class BinaryBuffer {
853
860
  }
854
861
 
855
862
  // expand the buffer if we couldn't write 4 bytes
856
- if (at + 4 > this.capacity) {
857
- tlen += 8; // minimum extra
858
- tlen *= (1.0 + (pos / len) * 2); // take 2x the remaining
859
- tlen = (tlen >> 3) << 3; // 8 byte offset
863
+ if (cursor + 4 > capacity) {
860
864
 
861
- this.ensureCapacity(tlen + startPosition);
865
+ this.ensureCapacity(cursor + 4);
862
866
 
867
+ // rebind variables
868
+ capacity = this.capacity;
863
869
  target = this.__data_uint8;
864
870
  }
865
871
 
866
872
  if ((value & 0xffffff80) === 0) { // 1-byte
867
- target[at++] = value; // ASCII
873
+ target[cursor++] = value; // ASCII
868
874
  continue;
869
875
  } else if ((value & 0xfffff800) === 0) { // 2-byte
870
- target[at++] = ((value >> 6) & 0x1f) | 0xc0;
876
+ target[cursor++] = ((value >> 6) & 0x1f) | 0xc0;
871
877
  } else if ((value & 0xffff0000) === 0) { // 3-byte
872
- target[at++] = ((value >> 12) & 0x0f) | 0xe0;
873
- target[at++] = ((value >> 6) & 0x3f) | 0x80;
878
+ target[cursor++] = ((value >> 12) & 0x0f) | 0xe0;
879
+ target[cursor++] = ((value >> 6) & 0x3f) | 0x80;
874
880
  } else if ((value & 0xffe00000) === 0) { // 4-byte
875
- target[at++] = ((value >> 18) & 0x07) | 0xf0;
876
- target[at++] = ((value >> 12) & 0x3f) | 0x80;
877
- target[at++] = ((value >> 6) & 0x3f) | 0x80;
881
+ target[cursor++] = ((value >> 18) & 0x07) | 0xf0;
882
+ target[cursor++] = ((value >> 12) & 0x3f) | 0x80;
883
+ target[cursor++] = ((value >> 6) & 0x3f) | 0x80;
878
884
  } else {
879
885
  // FIXME: do we care
880
886
  continue;
881
887
  }
882
888
 
883
- target[at++] = (value & 0x3f) | 0x80;
889
+ target[cursor++] = (value & 0x3f) | 0x80;
884
890
  }
885
891
 
886
- this.position = at;
892
+ this.position = cursor;
887
893
  }
888
894
 
889
895
  /**
@@ -2,10 +2,11 @@ import { assert } from "../../../assert.js";
2
2
  import { ceilPowerOfTwo } from "../../../binary/operations/ceilPowerOfTwo.js";
3
3
  import { array_copy } from "../../../collection/array/array_copy.js";
4
4
  import { array_swap } from "../../../collection/array/array_swap.js";
5
+ import { SCRATCH_UINT32_TRAVERSAL_STACK } from "../../../collection/SCRATCH_UINT32_TRAVERSAL_STACK.js";
5
6
  import { aabb3_array_combine } from "../../../geom/3d/aabb/aabb3_array_combine.js";
6
7
  import { aabb3_array_set } from "../../../geom/3d/aabb/aabb3_array_set.js";
7
8
  import { aabb3_compute_half_surface_area } from "../../../geom/3d/aabb/aabb3_compute_half_surface_area.js";
8
- import { mortonEncode_magicbits } from "../../../geom/3d/morton/mortonEncode_magicbits.js";
9
+ import { v3_morton_encode_bounded } from "../../../geom/3d/morton/v3_morton_encode_bounded.js";
9
10
  import { max2 } from "../../../math/max2.js";
10
11
  import { max3 } from "../../../math/max3.js";
11
12
  import { min2 } from "../../../math/min2.js";
@@ -54,10 +55,10 @@ function copy_box_zero_size(data, destination, source) {
54
55
  * Assumes data will be normalized to 0...1 value range
55
56
  * @param {Float32Array} data
56
57
  * @param {number} address
57
- * @param {number[]} matrix
58
+ * @param {number[]} bounds
58
59
  * @returns {number}
59
60
  */
60
- function build_morton(data, address, matrix) {
61
+ function build_morton(data, address, bounds) {
61
62
 
62
63
  const x0 = data[address];
63
64
  const y0 = data[address + 1];
@@ -66,17 +67,15 @@ function build_morton(data, address, matrix) {
66
67
  const y1 = data[address + 4];
67
68
  const z1 = data[address + 5];
68
69
 
69
- const cx = (x0 + x1) / 2;
70
- const cy = (y0 + y1) / 2;
71
- const cz = (z0 + z1) / 2;
70
+ const cx = (x0 + x1) * 0.5;
71
+ const cy = (y0 + y1) * 0.5;
72
+ const cz = (z0 + z1) * 0.5;
72
73
 
73
- return mortonEncode_magicbits(cx, cy, cz);
74
- // return v3_morton_encode_transformed(cx, cy, cz, matrix);
74
+ return v3_morton_encode_bounded(cx, cy, cz, bounds);
75
75
 
76
76
  }
77
77
 
78
- const scratch_box_0 = new Float32Array(18);
79
- const stack = [];
78
+ const stack = SCRATCH_UINT32_TRAVERSAL_STACK;
80
79
 
81
80
  export class BinaryUint32BVH {
82
81
  /**
@@ -100,34 +99,41 @@ export class BinaryUint32BVH {
100
99
  */
101
100
  __data_uint32;
102
101
 
103
- constructor() {
104
-
105
- /**
106
- *
107
- * @type {number}
108
- * @private
109
- */
110
- this.__node_count_binary = 0;
102
+ /**
103
+ *
104
+ * @type {number}
105
+ * @private
106
+ */
107
+ __node_count_binary = 0;
111
108
 
112
- /**
113
- *
114
- * @type {number}
115
- * @private
116
- */
117
- this.__node_count_leaf = 0;
109
+ /**
110
+ *
111
+ * @type {number}
112
+ * @private
113
+ */
114
+ __node_count_leaf = 0;
118
115
 
116
+ constructor() {
119
117
  this.data = new ArrayBuffer(320);
120
118
  }
121
119
 
120
+ /**
121
+ * In bytes
122
+ * @returns {number}
123
+ */
124
+ estimateByteSize() {
125
+ return this.data.byteLength + 248;
126
+ }
127
+
122
128
  getTotalBoxCount() {
123
129
  return this.__node_count_binary + this.__node_count_leaf;
124
130
  }
125
131
 
126
- getBinaryNodeCount() {
132
+ get binary_node_count() {
127
133
  return this.__node_count_binary;
128
134
  }
129
135
 
130
- getLeafNodeCount() {
136
+ get leaf_node_count() {
131
137
  return this.__node_count_leaf;
132
138
  }
133
139
 
@@ -149,10 +155,12 @@ export class BinaryUint32BVH {
149
155
 
150
156
  /**
151
157
  *
152
- * @param {ArrayBuffer} v
158
+ * @param {ArrayBuffer} buffer
153
159
  */
154
- set data(v) {
155
- this.__data_buffer = v;
160
+ set data(buffer) {
161
+ assert.defined(buffer, 'buffer');
162
+
163
+ this.__data_buffer = buffer;
156
164
 
157
165
  this.__data_float32 = new Float32Array(this.__data_buffer);
158
166
  this.__data_uint32 = new Uint32Array(this.__data_buffer);
@@ -162,6 +170,24 @@ export class BinaryUint32BVH {
162
170
  return this.__data_buffer;
163
171
  }
164
172
 
173
+ /**
174
+ * Resolve index of the node to address where the node data starts, this is required to know where AABB is stored in memory
175
+ * @param {number} node_index
176
+ * @returns {number}
177
+ */
178
+ getNodeAddress(node_index) {
179
+ const binary_node_count = this.__node_count_binary;
180
+ const leaf_node_index = node_index - binary_node_count;
181
+
182
+ if (leaf_node_index < 0) {
183
+ // binary node
184
+ return node_index * BVH_BINARY_NODE_SIZE;
185
+ } else {
186
+ // leaf node
187
+ return binary_node_count * BVH_BINARY_NODE_SIZE + leaf_node_index * BVH_LEAF_NODE_SIZE;
188
+ }
189
+ }
190
+
165
191
  initialize_structure() {
166
192
  // compute memory requirements
167
193
  const word_count = this.__node_count_binary * BVH_BINARY_NODE_SIZE + this.__node_count_leaf * BVH_LEAF_NODE_SIZE;
@@ -280,17 +306,15 @@ export class BinaryUint32BVH {
280
306
  * @private
281
307
  */
282
308
  __compute_bounds_area_of_3_boxes(a, b, c) {
283
- this.readBounds(a, scratch_box_0, 0);
284
- this.readBounds(b, scratch_box_0, 6);
285
- this.readBounds(c, scratch_box_0, 12);
309
+ const float32 = this.__data_float32;
286
310
 
287
- const x0 = min3(scratch_box_0[0], scratch_box_0[6], scratch_box_0[12]);
288
- const y0 = min3(scratch_box_0[1], scratch_box_0[7], scratch_box_0[13]);
289
- const z0 = min3(scratch_box_0[2], scratch_box_0[8], scratch_box_0[14]);
311
+ const x0 = min3(float32[a + 0], float32[b + 0], float32[c + 0]);
312
+ const y0 = min3(float32[a + 1], float32[b + 1], float32[c + 1]);
313
+ const z0 = min3(float32[a + 2], float32[b + 2], float32[c + 2]);
290
314
 
291
- const x1 = max3(scratch_box_0[3], scratch_box_0[9], scratch_box_0[15]);
292
- const y1 = max3(scratch_box_0[4], scratch_box_0[10], scratch_box_0[16]);
293
- const z1 = max3(scratch_box_0[5], scratch_box_0[11], scratch_box_0[17]);
315
+ const x1 = max3(float32[a + 3], float32[b + 3], float32[c + 3]);
316
+ const y1 = max3(float32[a + 4], float32[b + 4], float32[c + 4]);
317
+ const z1 = max3(float32[a + 5], float32[b + 5], float32[c + 5]);
294
318
 
295
319
  return aabb3_compute_half_surface_area(x0, y0, z0, x1, y1, z1);
296
320
  }
@@ -342,9 +366,9 @@ export class BinaryUint32BVH {
342
366
 
343
367
  /**
344
368
  * Sort leaf nodes according to their morton codes
345
- * @param {number[]} projection
369
+ * @param {number[]} bounds
346
370
  */
347
- sort_morton(projection) {
371
+ sort_morton(bounds) {
348
372
 
349
373
  const leaf_block_address = this.__node_count_binary * BVH_BINARY_NODE_SIZE;
350
374
 
@@ -374,15 +398,15 @@ export class BinaryUint32BVH {
374
398
 
375
399
  const pivot_address = pivotIndex * BVH_LEAF_NODE_SIZE + leaf_block_address;
376
400
 
377
- const pivot = build_morton(data, pivot_address, projection);
401
+ const pivot = build_morton(data, pivot_address, bounds);
378
402
 
379
403
  /* partition */
380
404
  while (i <= j) {
381
- while (build_morton(data, i * BVH_LEAF_NODE_SIZE + leaf_block_address, projection) < pivot) {
405
+ while (build_morton(data, i * BVH_LEAF_NODE_SIZE + leaf_block_address, bounds) < pivot) {
382
406
  i++;
383
407
  }
384
408
 
385
- while (build_morton(data, j * BVH_LEAF_NODE_SIZE + leaf_block_address, projection) > pivot) {
409
+ while (build_morton(data, j * BVH_LEAF_NODE_SIZE + leaf_block_address, bounds) > pivot) {
386
410
  j--;
387
411
  }
388
412
 
@@ -452,22 +476,22 @@ export class BinaryUint32BVH {
452
476
 
453
477
  // build bottom-most level, just above the leaves
454
478
  for (i = 0; i < level_node_count; i++) {
455
- const leafIndex0 = i * 2;
456
- const leafIndex1 = leafIndex0 + 1;
479
+ const leaf_index_0 = i * 2;
480
+ const leaf_index_1 = leaf_index_0 + 1;
457
481
 
458
- const leafOffset0 = leaf_node_block_address + leafIndex0 * BVH_LEAF_NODE_SIZE;
459
- const leafOffset1 = leaf_node_block_address + leafIndex1 * BVH_LEAF_NODE_SIZE;
482
+ const leaf_offset_0 = leaf_node_block_address + leaf_index_0 * BVH_LEAF_NODE_SIZE;
483
+ const leaf_offset_1 = leaf_node_block_address + leaf_index_1 * BVH_LEAF_NODE_SIZE;
460
484
 
461
- if (leafIndex1 < node_count_leaf) {
485
+ if (leaf_index_1 < node_count_leaf) {
462
486
  // both children nodes are valid
463
487
  aabb3_array_combine(
464
488
  float32, offset,
465
- float32, leafOffset0,
466
- float32, leafOffset1
489
+ float32, leaf_offset_0,
490
+ float32, leaf_offset_1
467
491
  );
468
- } else if (leafIndex0 < node_count_leaf) {
492
+ } else if (leaf_index_0 < node_count_leaf) {
469
493
  // only left child node is valid
470
- array_copy(float32, leafOffset0, float32, offset, 6);
494
+ array_copy(float32, leaf_offset_0, float32, offset, 6);
471
495
  } else {
472
496
  //initialize to 0-size box same position as previous node
473
497
  copy_box_zero_size(this.__data_float32, offset, (offset - BVH_BINARY_NODE_SIZE));
@@ -19,7 +19,7 @@ test('0 leaf tree must have a no binary nodes', () => {
19
19
  bvh.initialize_structure();
20
20
  bvh.build();
21
21
 
22
- expect(bvh.getBinaryNodeCount()).toBe(0);
22
+ expect(bvh.binary_node_count).toBe(0);
23
23
  });
24
24
 
25
25
  test('1 leaf tree must have a single binary node', () => {
@@ -29,7 +29,7 @@ test('1 leaf tree must have a single binary node', () => {
29
29
  bvh.initialize_structure();
30
30
  bvh.build();
31
31
 
32
- expect(bvh.getBinaryNodeCount()).toBe(1);
32
+ expect(bvh.binary_node_count).toBe(1);
33
33
  });
34
34
 
35
35
  test('4 leaf tree must have a 3 binary nodes', () => {
@@ -39,7 +39,7 @@ test('4 leaf tree must have a 3 binary nodes', () => {
39
39
  bvh.initialize_structure();
40
40
  bvh.build();
41
41
 
42
- expect(bvh.getBinaryNodeCount()).toBe(3);
42
+ expect(bvh.binary_node_count).toBe(3);
43
43
  });
44
44
 
45
45
  test('read/write 1 leaf', () => {
@@ -129,10 +129,8 @@ test('4 node sorted build', () => {
129
129
  bvh.setLeafData(3, 13, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6);
130
130
 
131
131
  bvh.sort_morton([
132
- 1, 0, 0, 0,
133
- 0, 1, 0, 0,
134
- 0, 0, 1, 0,
135
- 0, 0, 0, 1
132
+ 0, 0, 0,
133
+ 1, 1, 1
136
134
  ]);
137
135
  bvh.build();
138
136
  });
@@ -0,0 +1,94 @@
1
+ import { SCRATCH_UINT32_TRAVERSAL_STACK } from "../../../collection/SCRATCH_UINT32_TRAVERSAL_STACK.js";
2
+ import {
3
+ aabb3_array_intersects_clipping_volume_array
4
+ } from "../../../geom/3d/aabb/aabb3_array_intersects_clipping_volume_array.js";
5
+
6
+ const stack = SCRATCH_UINT32_TRAVERSAL_STACK;
7
+
8
+ /**
9
+ *
10
+ * @param {number[]} result
11
+ * @param {number} result_offset
12
+ * @param {BinaryUint32BVH} bvh
13
+ * @param {Float32Array|number[]} planes
14
+ * @param {number} planes_offset
15
+ * @param {number} plane_count
16
+ * @returns {number}
17
+ */
18
+ export function bvh32_query_user_data_overlaps_clipping_volume(
19
+ result, result_offset,
20
+ bvh,
21
+ planes, planes_offset, plane_count
22
+ ) {
23
+ let hit_count = 0;
24
+
25
+ const binary_node_count = bvh.binary_node_count;
26
+
27
+ if (binary_node_count <= 0) {
28
+ // this should not happen
29
+ return 0;
30
+ }
31
+
32
+ /**
33
+ *
34
+ * @type {number}
35
+ */
36
+ const stack_top = stack.pointer++;
37
+
38
+ /**
39
+ * After performing empirical tests, stack-based depth-first traversal turns out faster than using a queue
40
+ * @type {number}
41
+ */
42
+ stack[stack_top] = 0;
43
+
44
+ const last_valid_index = binary_node_count + bvh.leaf_node_count;
45
+
46
+ const float32 = bvh.float32;
47
+ const uint32 = bvh.uint32;
48
+
49
+ do {
50
+ stack.pointer--;
51
+
52
+ // query_bvh_frustum_from_objects.iteration_count++;
53
+ const node_index = stack[stack.pointer];
54
+
55
+ const node_address = bvh.getNodeAddress(node_index);
56
+
57
+ if (!aabb3_array_intersects_clipping_volume_array(
58
+ float32, node_address,
59
+ planes, planes_offset, plane_count
60
+ )) {
61
+ continue;
62
+ }
63
+
64
+ const is_intermediate_node = node_index < binary_node_count;
65
+
66
+ if (is_intermediate_node) {
67
+ // is intermediate node
68
+
69
+ const left_index = (node_index << 1) + 1;
70
+ const right_index = left_index + 1;
71
+
72
+ // left node ends up on top of the stack, which aligns with the desired access sequence
73
+ if (right_index < last_valid_index) {
74
+ stack[stack.pointer++] = right_index;
75
+ // micro-optimization, since we know that right node is valid and left appears before that, left is valid too
76
+ stack[stack.pointer++] = left_index;
77
+ } else if (left_index < last_valid_index) {
78
+ stack[stack.pointer++] = left_index;
79
+ }
80
+
81
+
82
+ } else {
83
+ // leaf node
84
+
85
+ // write to output
86
+ result[result_offset + hit_count] = uint32[node_address + 6];
87
+
88
+ hit_count++;
89
+ }
90
+
91
+ } while (stack.pointer > stack_top)
92
+
93
+ return hit_count;
94
+ }
@@ -1,14 +1,13 @@
1
1
  import { SCRATCH_UINT32_TRAVERSAL_STACK } from "../../../collection/SCRATCH_UINT32_TRAVERSAL_STACK.js";
2
2
  import { aabb3_array_intersects_ray } from "../../../geom/3d/aabb/aabb3_array_intersects_ray.js";
3
- import { BVH_BINARY_NODE_SIZE, BVH_LEAF_NODE_SIZE } from "./BinaryUint32BVH.js";
4
3
 
5
4
  const stack = SCRATCH_UINT32_TRAVERSAL_STACK;
6
5
 
7
6
  /**
8
7
  *
9
- * @param {BinaryUint32BVH} bvh
10
8
  * @param {number[]} result
11
9
  * @param {number} result_offset
10
+ * @param {BinaryUint32BVH} bvh
12
11
  * @param {number} origin_x
13
12
  * @param {number} origin_y
14
13
  * @param {number} origin_z
@@ -18,14 +17,14 @@ const stack = SCRATCH_UINT32_TRAVERSAL_STACK;
18
17
  * @returns {number}
19
18
  */
20
19
  export function bvh32_query_user_data_ray(
21
- bvh,
22
20
  result, result_offset,
21
+ bvh,
23
22
  origin_x, origin_y, origin_z,
24
23
  direction_x, direction_y, direction_z
25
24
  ) {
26
25
  let hit_count = 0;
27
26
 
28
- const binary_node_count = bvh.getBinaryNodeCount();
27
+ const binary_node_count = bvh.binary_node_count;
29
28
 
30
29
  if (binary_node_count <= 0) {
31
30
  // this should not happen
@@ -44,7 +43,7 @@ export function bvh32_query_user_data_ray(
44
43
  */
45
44
  stack[stack_top] = 0;
46
45
 
47
- const last_valid_index = binary_node_count + bvh.getLeafNodeCount();
46
+ const last_valid_index = binary_node_count + bvh.leaf_node_count;
48
47
 
49
48
  const float32 = bvh.float32;
50
49
  const uint32 = bvh.uint32;
@@ -55,17 +54,20 @@ export function bvh32_query_user_data_ray(
55
54
  // query_bvh_frustum_from_objects.iteration_count++;
56
55
  const node_index = stack[stack.pointer];
57
56
 
58
- if (node_index < binary_node_count) {
57
+ const node_address = bvh.getNodeAddress(node_index);
58
+
59
+ if (!aabb3_array_intersects_ray(
60
+ float32, node_address,
61
+ origin_x, origin_y, origin_z,
62
+ direction_x, direction_y, direction_z
63
+ )) {
64
+ continue;
65
+ }
66
+
67
+ const is_intermediate_node = node_index < binary_node_count;
68
+
69
+ if (is_intermediate_node) {
59
70
  // is intermediate node
60
- const node_address = node_index * BVH_BINARY_NODE_SIZE;
61
-
62
- if (!aabb3_array_intersects_ray(
63
- float32, node_address,
64
- origin_x, origin_y, origin_z,
65
- direction_x, direction_y, direction_z
66
- )) {
67
- continue;
68
- }
69
71
 
70
72
  const left_index = (node_index << 1) + 1;
71
73
  const right_index = left_index + 1;
@@ -82,9 +84,6 @@ export function bvh32_query_user_data_ray(
82
84
 
83
85
  } else {
84
86
  // leaf node
85
- const leaf_index = node_index - binary_node_count;
86
-
87
- const node_address = leaf_index * BVH_LEAF_NODE_SIZE + binary_node_count * BVH_BINARY_NODE_SIZE;
88
87
 
89
88
  // write to output
90
89
  result[result_offset + hit_count] = uint32[node_address + 6];
@@ -1,4 +1,6 @@
1
- import { aabb3_array_intersects_frustum_array } from "../../../geom/3d/aabb/aabb3_array_intersects_frustum_array.js";
1
+ import {
2
+ aabb3_array_intersects_clipping_volume_array
3
+ } from "../../../geom/3d/aabb/aabb3_array_intersects_clipping_volume_array.js";
2
4
  import { BVHQuery } from "./BVHQuery.js";
3
5
 
4
6
  const scratch_aabb = [];
@@ -29,6 +31,6 @@ export class BVHQueryIntersectsFrustum extends BVHQuery {
29
31
 
30
32
  tree.node_get_aabb(node, scratch_aabb);
31
33
 
32
- return aabb3_array_intersects_frustum_array(scratch_aabb, this.frustum);
34
+ return aabb3_array_intersects_clipping_volume_array(scratch_aabb, 0, this.frustum, 0, 6);
33
35
  }
34
36
  }
@@ -3,20 +3,20 @@
3
3
  */
4
4
 
5
5
 
6
- import {assert} from "../../../assert.js";
6
+ import { assert } from "../../../assert.js";
7
7
  import computeMortonCode from "../morton/Morton.js";
8
- import {aabb3_array_intersects_point} from "./aabb3_array_intersects_point.js";
9
- import {aabb3_build_corners} from "./aabb3_build_corners.js";
10
- import {aabb3_compute_distance_above_plane_max} from "./aabb3_compute_distance_above_plane_max.js";
11
- import {aabb3_compute_plane_side} from "./aabb3_compute_plane_side.js";
12
- import {aabb3_compute_surface_area} from "./aabb3_compute_surface_area.js";
13
- import {aabb3_intersects_frustum_array} from "./aabb3_intersects_frustum_array.js";
14
- import {aabb3_intersects_frustum_degree} from "./aabb3_intersects_frustum_degree.js";
15
- import {aabb3_intersects_line_segment} from "./aabb3_intersects_line_segment.js";
16
- import {aabb3_intersects_ray} from "./aabb3_intersects_ray.js";
17
- import {aabb3_matrix4_project} from "./aabb3_matrix4_project.js";
18
- import {aabb3_signed_distance_sqr_to_point} from "./aabb3_signed_distance_sqr_to_point.js";
19
- import {aabb3_signed_distance_to_aabb3} from "./aabb3_signed_distance_to_aabb3.js";
8
+ import { aabb3_array_intersects_point } from "./aabb3_array_intersects_point.js";
9
+ import { aabb3_build_corners } from "./aabb3_build_corners.js";
10
+ import { aabb3_compute_distance_above_plane_max } from "./aabb3_compute_distance_above_plane_max.js";
11
+ import { aabb3_compute_plane_side } from "./aabb3_compute_plane_side.js";
12
+ import { aabb3_compute_surface_area } from "./aabb3_compute_surface_area.js";
13
+ import { aabb3_intersects_clipping_volume_array } from "./aabb3_intersects_clipping_volume_array.js";
14
+ import { aabb3_intersects_frustum_degree } from "./aabb3_intersects_frustum_degree.js";
15
+ import { aabb3_intersects_line_segment } from "./aabb3_intersects_line_segment.js";
16
+ import { aabb3_intersects_ray } from "./aabb3_intersects_ray.js";
17
+ import { aabb3_matrix4_project } from "./aabb3_matrix4_project.js";
18
+ import { aabb3_signed_distance_sqr_to_point } from "./aabb3_signed_distance_sqr_to_point.js";
19
+ import { aabb3_signed_distance_to_aabb3 } from "./aabb3_signed_distance_to_aabb3.js";
20
20
 
21
21
  /**
22
22
  * Axis-Aligned bounding box in 3D
@@ -850,7 +850,7 @@ export class AABB3 {
850
850
  const y1 = this.y1;
851
851
  const z1 = this.z1;
852
852
 
853
- return aabb3_intersects_frustum_array(x0, y0, z0, x1, y1, z1, frustum);
853
+ return aabb3_intersects_clipping_volume_array(x0, y0, z0, x1, y1, z1, frustum, 0, 6);
854
854
  }
855
855
 
856
856
  /**