@woosh/meep-engine 2.34.32 → 2.34.36

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 (56) hide show
  1. package/core/assert.js +11 -0
  2. package/core/binary/BitSet.js +5 -0
  3. package/core/bvh2/BinaryNode.js +210 -74
  4. package/core/bvh2/Node.d.ts +3 -0
  5. package/core/bvh2/aabb3/AABB3.js +50 -4
  6. package/core/bvh2/aabb3/AABB3Math.js +1 -1
  7. package/core/bvh2/aabb3/aabb3_from_v3_array.js +34 -0
  8. package/core/bvh2/aabb3/aabb3_from_v3_array_transformed.js +39 -0
  9. package/core/bvh2/aabb3/aabb3_intersects_frustum_degree.js +46 -0
  10. package/core/bvh2/transform/RotationOptimizer.js +2 -262
  11. package/core/bvh2/transform/tryRotateSingleNode.js +259 -0
  12. package/core/bvh2/traversal/ThreeFrustumsIntersectionBVHVisitor.js +16 -35
  13. package/core/bvh2/traversal/queryBinaryNode_FrustumIntersections.js +52 -0
  14. package/core/collection/list/List.js +0 -34
  15. package/core/events/signal/Signal.js +1 -1
  16. package/core/geom/3d/aabb/aabb3_matrix4_project.js +2 -3
  17. package/core/geom/Quaternion.d.ts +2 -0
  18. package/engine/Engine.js +5 -0
  19. package/engine/asset/loaders/ArrayBufferLoader.js +7 -0
  20. package/engine/asset/loaders/image/ImageRGBADataLoader.js +11 -6
  21. package/engine/development/performance/AbstractMetric.js +4 -0
  22. package/engine/development/performance/RingBufferMetric.js +4 -0
  23. package/engine/ecs/EntityBuilder.js +12 -5
  24. package/engine/ecs/EntityComponentDataset.js +26 -6
  25. package/engine/ecs/attachment/AttachmentSystem.js +1 -1
  26. package/engine/ecs/attachment/TransformAttachmentBinding.js +0 -1
  27. package/engine/ecs/foliage/FoliageVisibilitySetBuilder.js +1 -31
  28. package/engine/ecs/foliage/InstancedFoliage.js +81 -152
  29. package/engine/ecs/foliage/ViewState.js +190 -0
  30. package/engine/ecs/foliage/ecs/Foliage2System.js +80 -12
  31. package/engine/ecs/foliage/ecs/InstancedMeshComponent.js +30 -0
  32. package/engine/ecs/foliage/ecs/InstancedMeshLayer.js +16 -0
  33. package/engine/ecs/foliage/ecs/InstancedMeshUtils.js +2 -2
  34. package/engine/ecs/parent/EntityNode.js +31 -49
  35. package/engine/ecs/sockets/AttachmentSockets.js +11 -1
  36. package/engine/ecs/transform-attachment/TransformAttachment.js +88 -0
  37. package/engine/ecs/transform-attachment/TransformAttachmentSystem.js +59 -0
  38. package/engine/graphics/GraphicsEngine.js +23 -2
  39. package/engine/graphics/ecs/light/binding/three/ThreeLightBinding.js +2 -19
  40. package/engine/graphics/ecs/mesh/updateNodeByTransformAndBBB.js +21 -21
  41. package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +9 -1
  42. package/engine/graphics/ecs/mesh-v2/ShadedGeometryFlags.js +4 -1
  43. package/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js +3 -0
  44. package/engine/graphics/ecs/mesh-v2/sample/load_gltf.js +40 -8
  45. package/engine/graphics/ecs/mesh-v2/three_object_to_entity_composition.js +3 -3
  46. package/engine/graphics/geometry/instancing/InstancedMeshGroup.js +17 -11
  47. package/engine/graphics/micron/build/buildMicronGeometryFromBufferGeometry.js +1 -34
  48. package/engine/graphics/micron/build/fill_patch_geometry_data.js +19 -6
  49. package/engine/graphics/micron/format/MicronGeometry.js +21 -0
  50. package/engine/graphics/micron/plugin/MicronRenderPlugin.js +0 -3
  51. package/engine/graphics/micron/prototypeVirtualGeometry.js +69 -1
  52. package/engine/graphics/render/layers/RenderLayer.js +22 -85
  53. package/engine/graphics/render/visibility/VisibilityComputer.js +23 -103
  54. package/engine/sound/ecs/emitter/SoundEmitterSystem.js +1 -1
  55. package/package.json +1 -1
  56. package/samples/terrain/editor.js +0 -1
package/core/assert.js CHANGED
@@ -316,6 +316,17 @@ assert.defined = function (value, name = "value") {
316
316
 
317
317
  };
318
318
 
319
+ /**
320
+ *
321
+ * @param {*} value
322
+ * @param {String} [name]
323
+ */
324
+ assert.isNull = function (value, name){
325
+ if (value !== null) {
326
+ throw new Error(`${name} is NOT null`);
327
+ }
328
+ }
329
+
319
330
  /**
320
331
  *
321
332
  * @param {*} value
@@ -533,6 +533,11 @@ BitSet.prototype.shift = function (distance, start_index, end_index) {
533
533
  * Sets all of the bits in this BitSet to false.
534
534
  */
535
535
  BitSet.prototype.reset = function () {
536
+ if (this.__length <= 0) {
537
+ // no action required
538
+ return;
539
+ }
540
+
536
541
  this.__data_uint32.fill(0, 0, Math.ceil(this.__length / 32));
537
542
  this.__length = 0;
538
543
  };
@@ -8,7 +8,7 @@ import { arrayQuickSort } from "../collection/array/arrayQuickSort.js";
8
8
  import { max2 } from "../math/max2.js";
9
9
  import { min2 } from "../math/min2.js";
10
10
  import { computeSampleStandardDeviation } from "../math/statistics/computeSampleStandardDeviation.js";
11
- import { aabb3_intersect_aabb3, boxSurfaceArea2 } from "./aabb3/AABB3Math.js";
11
+ import { _boxSurfaceArea2, aabb3_intersect_aabb3, boxSurfaceArea2 } from "./aabb3/AABB3Math.js";
12
12
  import { isLeaf, LeafNode } from "./LeafNode.js";
13
13
  import { Node } from "./Node.js";
14
14
  import { surfaceAreaHeuristic } from "./sah/surfaceAreaHeuristic.js";
@@ -141,11 +141,133 @@ BinaryNode.prototype.setChildren = function (left, right) {
141
141
 
142
142
  /**
143
143
  *
144
+ * @param {Node} child
145
+ */
146
+ BinaryNode.prototype.setChildLeft = function (child) {
147
+ assert.isNull(this.left, 'left');
148
+
149
+ this.left = child;
150
+
151
+ this.updateLeafNodeCount();
152
+
153
+ this.refit();
154
+
155
+ child.parentNode = this;
156
+ }
157
+
158
+ /**
159
+ *
160
+ * @param {Node} child
161
+ */
162
+ BinaryNode.prototype.setChildRight = function (child) {
163
+ assert.isNull(this.right, 'right');
164
+
165
+ this.right = child;
166
+
167
+ this.updateLeafNodeCount();
168
+
169
+ this.refit();
170
+
171
+ child.parentNode = this;
172
+ }
173
+
174
+ /**
175
+ * @see "Dynamic BVH" by Erin Catto / Blizzard
176
+ * @param {AABB3} node
177
+ * @param {AABB3} addition
178
+ * @returns {number}
179
+ */
180
+ function inclusion_surface_area_heuristic(node, addition) {
181
+ const x0 = min2(node.x0, addition.x0);
182
+ const y0 = min2(node.y0, addition.y0);
183
+ const z0 = min2(node.z0, addition.z0);
184
+
185
+ const x1 = max2(node.x1, addition.x1);
186
+ const y1 = max2(node.y1, addition.y1);
187
+ const z1 = max2(node.z1, addition.z1);
188
+
189
+ return _boxSurfaceArea2(x0, y0, z0, x1, y1, z1) - boxSurfaceArea2(node);
190
+ }
191
+
192
+ /**
193
+ *
194
+ * @param {BinaryNode|LeafNode} node
195
+ * @param {AABB3} addition
196
+ */
197
+ function inclusion_cost_lower_bound(node, addition) {
198
+ let n = node;
199
+ let r = boxSurfaceArea2(addition);
200
+
201
+ while (n !== null) {
202
+
203
+ r += n.costForInclusion(addition);
204
+
205
+ n = n.parentNode;
206
+ }
207
+
208
+ return r;
209
+ }
210
+
211
+ /**
212
+ * For incremental insertion, a sibling needs to be found, newly inserted node will be parented together with this sibling
144
213
  * @param {AABB3} box
145
- * @returns {Node}
214
+ * @returns {BinaryNode|LeafNode}
215
+ */
216
+ BinaryNode.prototype.__insertion_findSiblingFor = function (box) {
217
+
218
+ const open_set = [this];
219
+ let cursor = 1;
220
+
221
+ let best_cost = Infinity;
222
+ let best_node = this;
223
+
224
+ while (cursor > 0) {
225
+ const node = open_set[--cursor];
226
+
227
+ const cost = inclusion_surface_area_heuristic(node, box);
228
+
229
+ if (cost < best_cost) {
230
+ best_cost = cost;
231
+ best_node = node;
232
+ }
233
+
234
+ if (node.isBinaryNode) {
235
+
236
+ if (node.isProtected()) {
237
+ continue;
238
+ }
239
+
240
+ // consider pushing children into the queue
241
+
242
+ // compute lower bound for cost
243
+ const c_low = inclusion_cost_lower_bound(node, box);
244
+
245
+ if (c_low < best_cost) {
246
+ // worth-while to explore children
247
+ if (node.left !== null) {
248
+ open_set[cursor++] = node.left;
249
+ }
250
+ if (node.right !== null) {
251
+ open_set[cursor++] = node.right
252
+ }
253
+ }
254
+ }
255
+
256
+
257
+ }
258
+
259
+ return best_node;
260
+ }
261
+
262
+ /**
263
+ *
264
+ * @param {AABB3} box
265
+ * @returns {Node|BinaryNode|LeafNode}
146
266
  */
147
267
  BinaryNode.prototype.findParentFor = function (box) {
148
268
  let n = this;
269
+ let aCost = 0;
270
+ let bCost = 0;
149
271
 
150
272
  for (; ;) {
151
273
 
@@ -181,8 +303,8 @@ BinaryNode.prototype.findParentFor = function (box) {
181
303
  }
182
304
  }
183
305
 
184
- let aCost = a.costForInclusion(box);
185
- let bCost = b.costForInclusion(box);
306
+ aCost = a.costForInclusion(box);
307
+ bCost = b.costForInclusion(box);
186
308
 
187
309
  if (aCost === bCost) {
188
310
 
@@ -196,9 +318,9 @@ BinaryNode.prototype.findParentFor = function (box) {
196
318
 
197
319
  }
198
320
 
199
- //change costs to be surface areas instead
200
- aCost = a.computeSAH();
201
- bCost = b.computeSAH();
321
+ //change costs to be based on balance
322
+ aCost = a.leafNodeCount / boxSurfaceArea2(a);
323
+ bCost = b.leafNodeCount / boxSurfaceArea2(b);
202
324
  }
203
325
 
204
326
  if (aCost === bCost) {
@@ -419,11 +541,12 @@ BinaryNode.prototype.bubbleRefit = function () {
419
541
  n = n.parentNode;
420
542
 
421
543
  if (n === null) {
544
+ // hit the root
422
545
  return;
423
546
  }
424
547
 
425
- //check if this node violates bounds of the parent
426
548
 
549
+ //check if this node violates bounds of the parent
427
550
  let flag = false;
428
551
 
429
552
  if (_x0 < n.x0) {
@@ -518,26 +641,29 @@ function countLeaves(node) {
518
641
  }
519
642
 
520
643
  /**
521
- *
644
+ * @deprecated Incorrect usage of SAH
522
645
  * @return {number}
523
646
  */
524
647
  BinaryNode.prototype.computeSAH = function () {
525
648
  let leftLeaves, rightLeaves, leftArea, rightArea;
526
649
 
527
- if (this.left === null) {
650
+ const left = this.left;
651
+
652
+ if (left === null) {
528
653
  leftArea = 0;
529
654
  leftLeaves = 0;
530
655
  } else {
531
- leftArea = boxSurfaceArea2(this.left);
532
- leftLeaves = this.left.leafNodeCount;
656
+ leftArea = boxSurfaceArea2(left);
657
+ leftLeaves = left.leafNodeCount;
533
658
  }
534
659
 
535
- if (this.right === null) {
660
+ const right = this.right;
661
+ if (right === null) {
536
662
  rightArea = 0;
537
663
  rightLeaves = 0;
538
664
  } else {
539
- rightArea = boxSurfaceArea2(this.right);
540
- rightLeaves = this.right.leafNodeCount;
665
+ rightArea = boxSurfaceArea2(right);
666
+ rightLeaves = right.leafNodeCount;
541
667
  }
542
668
 
543
669
  const thisArea = boxSurfaceArea2(this);
@@ -546,37 +672,37 @@ BinaryNode.prototype.computeSAH = function () {
546
672
  };
547
673
 
548
674
  BinaryNode.prototype.updateLeafNodeCount = function () {
549
- let n = 0;
675
+ let node = this;
550
676
 
551
- const right = this.right;
677
+ while (node !== null) {
678
+ let n = 0;
552
679
 
553
- if (right !== null) {
554
- if (right.isLeafNode) {
555
- n++;
556
- } else {
557
- n += right.leafNodeCount;
680
+ const right = node.right;
681
+
682
+ if (right !== null) {
683
+ if (right.isLeafNode) {
684
+ n++;
685
+ } else {
686
+ n += right.leafNodeCount;
687
+ }
558
688
  }
559
- }
560
689
 
561
- const left = this.left;
690
+ const left = this.left;
562
691
 
563
- if (left !== null) {
564
- if (left.isLeafNode) {
565
- n++;
566
- } else {
567
- n += left.leafNodeCount;
692
+ if (left !== null) {
693
+ if (left.isLeafNode) {
694
+ n++;
695
+ } else {
696
+ n += left.leafNodeCount;
697
+ }
568
698
  }
569
- }
570
699
 
571
- this.leafNodeCount = n;
700
+ node.leafNodeCount = n;
572
701
 
573
- // propagate update up the tree
574
- let parentNode = this.parentNode;
575
-
576
- if (parentNode !== null) {
577
- // bubble up
578
- parentNode.updateLeafNodeCount();
702
+ // propagate update up the tree
703
+ node = node.parentNode;
579
704
  }
705
+
580
706
  }
581
707
 
582
708
 
@@ -1024,19 +1150,18 @@ BinaryNode.prototype.computeBalanceFactor = function () {
1024
1150
  };
1025
1151
 
1026
1152
  /**
1027
- *
1153
+ * @template T
1028
1154
  * @param {number} x0
1029
1155
  * @param {number} y0
1030
1156
  * @param {number} z0
1031
1157
  * @param {number} x1
1032
1158
  * @param {number} y1
1033
1159
  * @param {number} z1
1034
- * @param {*} value
1160
+ * @param {T} value
1035
1161
  * @returns {LeafNode}
1036
1162
  */
1037
1163
  BinaryNode.prototype.insert = function (x0, y0, z0, x1, y1, z1, value) {
1038
- const leaf = new LeafNode(value);
1039
- leaf.setBounds(x0, y0, z0, x1, y1, z1);
1164
+ const leaf = new LeafNode(value, x0, y0, z0, x1, y1, z1);
1040
1165
  this.insertNode(leaf);
1041
1166
  return leaf;
1042
1167
  };
@@ -1065,6 +1190,8 @@ function transplantNewCommonParent(node, child) {
1065
1190
 
1066
1191
  parent.bubbleExpandToFit(bNode);
1067
1192
 
1193
+ parent.updateLeafNodeCount();
1194
+
1068
1195
  return bNode;
1069
1196
  }
1070
1197
 
@@ -1073,51 +1200,60 @@ function transplantNewCommonParent(node, child) {
1073
1200
  * @param {Node|BinaryNode|LeafNode} child
1074
1201
  */
1075
1202
  BinaryNode.prototype.insertNode = function (child) {
1076
- assert.notEqual(child, null, "child node is null");
1077
- assert.notEqual(child, undefined, "child node is undefined");
1078
- assert.ok(child instanceof Node, undefined, "child node is not an instance of Node");
1203
+
1204
+ assert.notNull(child, "child");
1205
+ assert.defined(child, "child");
1206
+ assert.isInstanceOf(child, Node, 'child', "Node");
1079
1207
  assert.equal(child.parentNode, null, "parentNode must be null, otherwise Node still belongs to another tree");
1080
1208
 
1081
- const node = this.findParentFor(child);
1082
-
1083
- let bNode;
1084
-
1085
- if (node.isBinaryNode) {
1086
- if ((node.isProtected() && node !== this)) {
1087
- transplantNewCommonParent(node, child);
1088
- } else if (node.left === null) {
1089
- node.left = child;
1090
- child.parentNode = node;
1091
- node.bubbleExpandToFit(child);
1092
- } else if (node.right === null) {
1093
- node.right = child;
1094
- child.parentNode = node;
1095
- node.bubbleExpandToFit(child);
1209
+ const sibling = this.__insertion_findSiblingFor(child);
1210
+
1211
+ const sibling_parent = sibling.parentNode;
1212
+ if (sibling_parent === null) {
1213
+ // root node
1214
+
1215
+ if (sibling.left === null) {
1216
+ sibling.setChildLeft(child);
1217
+ } else if (sibling.right === null) {
1218
+ sibling.setChildRight(child);
1096
1219
  } else {
1097
- //take right child and insert another binary node there
1098
- bNode = new BinaryNode();
1099
- bNode.setChildren(node.right, child);
1100
- //
1101
- node.right = bNode;
1102
- bNode.parentNode = node;
1103
- node.bubbleExpandToFit(bNode);
1220
+ const parent = new BinaryNode();
1221
+
1222
+ parent.setChildren(sibling.right, child);
1223
+ sibling.right = parent;
1224
+ parent.parentNode = sibling;
1104
1225
  }
1105
1226
 
1106
- node.updateLeafNodeCount();
1107
1227
  } else {
1108
- //need to do transplanting and introduce a new common parent
1109
- bNode = transplantNewCommonParent(node, child);
1110
1228
 
1111
- bNode.updateLeafNodeCount();
1112
- }
1229
+ // non-root
1113
1230
 
1114
- };
1231
+ if (sibling_parent.left === sibling && sibling_parent.right === null) {
1232
+
1233
+ // right node is free, take it
1234
+ sibling_parent.setChildRight(child);
1235
+
1236
+ } else if (sibling_parent.right === sibling && sibling_parent.left === null) {
1237
+
1238
+ // left node is free, take it
1239
+ sibling_parent.setChildLeft(child);
1240
+
1241
+ } else {
1242
+
1243
+ transplantNewCommonParent(sibling, child)
1244
+
1245
+ }
1246
+
1247
+ sibling_parent.bubbleRefit();
1248
+
1249
+ }
1250
+ }
1115
1251
 
1116
1252
  /**
1117
- *
1253
+ * @param {boolean} deep
1118
1254
  * @returns {BinaryNode}
1119
1255
  */
1120
- BinaryNode.prototype.clone = function (deep) {
1256
+ BinaryNode.prototype.clone = function (deep = false) {
1121
1257
  const clone = new BinaryNode();
1122
1258
 
1123
1259
  clone.x0 = this.x0;
@@ -3,4 +3,7 @@ import {BinaryNode} from "./BinaryNode";
3
3
 
4
4
  export class Node<T> extends AABB3 {
5
5
  public parentNode: BinaryNode<T>
6
+
7
+
8
+ readonly leafNodeCount: number
6
9
  }
@@ -6,9 +6,10 @@
6
6
  import { aabb3_computeDistanceAbovePlane } from "../../geom/3d/aabb/aabb3_computeDistanceAbovePlane.js";
7
7
  import { computeAABB3PlaneSide } from "../../geom/3d/aabb/computeAABB3PlaneSide.js";
8
8
  import computeMortonCode from "../../geom/3d/morton/Morton.js";
9
- import { _boxSurfaceArea2, intersectRay, intersectSegment } from "./AABB3Math.js";
9
+ import { boxSurfaceArea, intersectRay, intersectSegment } from "./AABB3Math.js";
10
10
  import { aabb3_build_corners } from "../../geom/3d/aabb/aabb3_build_corners.js";
11
11
  import { assert } from "../../assert.js";
12
+ import { aabb3_intersects_frustum_degree } from "./aabb3_intersects_frustum_degree.js";
12
13
 
13
14
 
14
15
  /**
@@ -81,7 +82,7 @@ AABB3.prototype.computeMortonCode = function () {
81
82
  * @returns {number}
82
83
  */
83
84
  AABB3.prototype.computeSurfaceArea = function () {
84
- return _boxSurfaceArea2(this.x0, this.y0, this.z0, this.x1, this.y1, this.z1);
85
+ return boxSurfaceArea(this.x0, this.y0, this.z0, this.x1, this.y1, this.z1);
85
86
  };
86
87
 
87
88
  /**
@@ -296,7 +297,8 @@ AABB3.prototype.costForInclusion = function (other) {
296
297
  };
297
298
 
298
299
  /**
299
- *
300
+ * Surface area delta when including a given AABB
301
+ * 0 means that including a given AABB would not cause any change to total surface area
300
302
  * @param {number} x0
301
303
  * @param {number} y0
302
304
  * @param {number} z0
@@ -834,7 +836,7 @@ AABB3.prototype.intersectFrustumDegree = function (frustum) {
834
836
 
835
837
  let i = 0;
836
838
  let result = 2;
837
- for (i = 0; i < 6; i++) {
839
+ for (; i < 6; i++) {
838
840
 
839
841
  const plane = planes[i];
840
842
 
@@ -848,6 +850,16 @@ AABB3.prototype.intersectFrustumDegree = function (frustum) {
848
850
  }
849
851
  return result;
850
852
  };
853
+ /**
854
+ *
855
+ * @param {number[]} frustum
856
+ * @returns {number}
857
+ */
858
+ AABB3.prototype.intersectFrustumDegree_array = function (frustum) {
859
+ return aabb3_intersects_frustum_degree(
860
+ this.x0, this.y0, this.z0, this.x1, this.y1, this.z1, frustum
861
+ );
862
+ };
851
863
 
852
864
  /**
853
865
  *
@@ -866,6 +878,40 @@ AABB3.prototype.intersectFrustum = function intersectFrustum(frustum) {
866
878
  return true;
867
879
  };
868
880
 
881
+ /**
882
+ *
883
+ * @param {ArrayLike<number>|number[]|Float32Array}frustum
884
+ * @returns {boolean}
885
+ */
886
+ AABB3.prototype.intersectFrustum_array = function intersectFrustum(frustum) {
887
+ const x0 = this.x0;
888
+ const y0 = this.y0;
889
+ const z0 = this.z0;
890
+ const x1 = this.x1;
891
+ const y1 = this.y1;
892
+ const z1 = this.z1;
893
+
894
+ for (let i = 0; i < 24; i += 4) {
895
+
896
+ const p_nx = frustum[i];
897
+ const p_ny = frustum[i + 1];
898
+ const p_nz = frustum[i + 2];
899
+ const p_c = frustum[i + 3];
900
+
901
+ if (aabb3_computeDistanceAbovePlane(
902
+ p_nx, p_ny, p_nz, p_c,
903
+ x0, y0, z0,
904
+ x1, y1, z1
905
+ ) < 0) {
906
+ // below plane, i.e. outside of the frustum
907
+ return false;
908
+ }
909
+
910
+ }
911
+ return true;
912
+ };
913
+
914
+
869
915
  /**
870
916
  *
871
917
  * @param {number} v
@@ -540,7 +540,7 @@ function boxSurfaceArea(x0, y0, z0, x1, y1, z1) {
540
540
  const dx = x1 - x0;
541
541
  const dy = y1 - y0;
542
542
  const dz = z1 - z0;
543
- return (dx * dy + dy * dz + dz * dx) * 2; //2 of each side
543
+ return (dy * (dx + dz) + dz * dx) * 2; //2 of each side
544
544
  }
545
545
 
546
546
  /**
@@ -0,0 +1,34 @@
1
+ import { min2 } from "../../math/min2.js";
2
+ import { max2 } from "../../math/max2.js";
3
+
4
+ /**
5
+ *
6
+ * @param {AABB3} result
7
+ * @param {number[]|ArrayLike<number>} input
8
+ * @param {number} input_length
9
+ */
10
+ export function aabb3_from_v3_array(result, input, input_length) {
11
+ let x0 = Infinity;
12
+ let y0 = Infinity;
13
+ let z0 = Infinity;
14
+
15
+ let x1 = -Infinity;
16
+ let y1 = -Infinity;
17
+ let z1 = -Infinity;
18
+
19
+ for (let i = 0; i < input_length; i += 3) {
20
+ const x = input[i];
21
+ const y = input[i + 1];
22
+ const z = input[i + 2];
23
+
24
+ x0 = min2(x, x0);
25
+ y0 = min2(y, y0);
26
+ z0 = min2(z, z0);
27
+
28
+ x1 = max2(x, x1);
29
+ y1 = max2(y, y1);
30
+ z1 = max2(z, z1);
31
+ }
32
+
33
+ result.setBounds(x0, y0, z0, x1, y1, z1);
34
+ }
@@ -0,0 +1,39 @@
1
+ import { min2 } from "../../math/min2.js";
2
+ import { max2 } from "../../math/max2.js";
3
+
4
+ /**
5
+ *
6
+ * @param {AABB3} result
7
+ * @param {number[]|ArrayLike<number>} input
8
+ * @param {number} input_length
9
+ * @param {ArrayLike<number>|number[]|Float32Array} e 4x4 transformation matrix
10
+ */
11
+ export function aabb3_from_v3_array_transformed(result, input, input_length, e) {
12
+ let x0 = Infinity;
13
+ let y0 = Infinity;
14
+ let z0 = Infinity;
15
+
16
+ let x1 = -Infinity;
17
+ let y1 = -Infinity;
18
+ let z1 = -Infinity;
19
+
20
+ for (let i = 0; i < input_length; i += 3) {
21
+ const x = input[i];
22
+ const y = input[i + 1];
23
+ const z = input[i + 2];
24
+
25
+ const _x = e[0] * x + e[4] * y + e[8] * z + e[12];
26
+ const _y = e[1] * x + e[5] * y + e[9] * z + e[13];
27
+ const _z = e[2] * x + e[6] * y + e[10] * z + e[14];
28
+
29
+ x0 = min2(_x, x0);
30
+ y0 = min2(_y, y0);
31
+ z0 = min2(_z, z0);
32
+
33
+ x1 = max2(_x, x1);
34
+ y1 = max2(_y, y1);
35
+ z1 = max2(_z, z1);
36
+ }
37
+
38
+ result.setBounds(x0, y0, z0, x1, y1, z1);
39
+ }
@@ -0,0 +1,46 @@
1
+ //
2
+
3
+ import { computeAABB3PlaneSide } from "../../geom/3d/aabb/computeAABB3PlaneSide.js";
4
+
5
+ /**
6
+ *
7
+ * @param {number} x0
8
+ * @param {number} y0
9
+ * @param {number} z0
10
+ * @param {number} x1
11
+ * @param {number} y1
12
+ * @param {number} z1
13
+ * @param {number[]} frustum
14
+ * @return {number}
15
+ */
16
+ export function aabb3_intersects_frustum_degree(
17
+ x0, y0, z0,
18
+ x1, y1, z1,
19
+ frustum
20
+ ) {
21
+
22
+ let i = 0;
23
+ let result = 2;
24
+
25
+ for (; i < 24; i += 4) {
26
+
27
+ const p_nx = frustum[i];
28
+ const p_ny = frustum[i + 1];
29
+ const p_nz = frustum[i + 2];
30
+ const p_c = frustum[i + 3];
31
+
32
+ const plane_side = computeAABB3PlaneSide(
33
+ p_nx, p_ny, p_nz, p_c,
34
+ x0, y0, z0, x1, y1, z1
35
+ );
36
+
37
+ if (plane_side < 0) {
38
+ // completely outside
39
+ return 0;
40
+ } else if (plane_side === 0) {
41
+ result = 1;
42
+ }
43
+ }
44
+
45
+ return result;
46
+ }