@woosh/meep-engine 2.34.35 → 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 (37) hide show
  1. package/core/binary/BitSet.js +5 -0
  2. package/core/bvh2/BinaryNode.js +25 -76
  3. package/core/bvh2/aabb3/AABB3.js +46 -1
  4. package/core/bvh2/aabb3/aabb3_from_v3_array.js +34 -0
  5. package/core/bvh2/aabb3/aabb3_from_v3_array_transformed.js +39 -0
  6. package/core/bvh2/aabb3/aabb3_intersects_frustum_degree.js +46 -0
  7. package/core/bvh2/traversal/ThreeFrustumsIntersectionBVHVisitor.js +16 -35
  8. package/core/bvh2/traversal/queryBinaryNode_FrustumIntersections.js +52 -0
  9. package/core/geom/3d/aabb/aabb3_matrix4_project.js +2 -3
  10. package/core/geom/Quaternion.d.ts +2 -0
  11. package/engine/ecs/attachment/TransformAttachmentBinding.js +0 -1
  12. package/engine/ecs/foliage/FoliageVisibilitySetBuilder.js +1 -31
  13. package/engine/ecs/foliage/InstancedFoliage.js +81 -152
  14. package/engine/ecs/foliage/ViewState.js +190 -0
  15. package/engine/ecs/foliage/ecs/Foliage2System.js +80 -12
  16. package/engine/ecs/foliage/ecs/InstancedMeshComponent.js +30 -0
  17. package/engine/ecs/foliage/ecs/InstancedMeshLayer.js +16 -0
  18. package/engine/ecs/foliage/ecs/InstancedMeshUtils.js +2 -2
  19. package/engine/ecs/parent/EntityNode.js +31 -49
  20. package/engine/ecs/transform-attachment/TransformAttachment.js +88 -0
  21. package/engine/ecs/transform-attachment/TransformAttachmentSystem.js +59 -0
  22. package/engine/graphics/GraphicsEngine.js +23 -2
  23. package/engine/graphics/ecs/light/binding/three/ThreeLightBinding.js +2 -19
  24. package/engine/graphics/ecs/mesh/updateNodeByTransformAndBBB.js +21 -21
  25. package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +9 -1
  26. package/engine/graphics/ecs/mesh-v2/ShadedGeometryFlags.js +4 -1
  27. package/engine/graphics/ecs/mesh-v2/sample/load_gltf.js +32 -8
  28. package/engine/graphics/geometry/instancing/InstancedMeshGroup.js +17 -11
  29. package/engine/graphics/micron/build/buildMicronGeometryFromBufferGeometry.js +1 -34
  30. package/engine/graphics/micron/build/fill_patch_geometry_data.js +12 -0
  31. package/engine/graphics/micron/format/MicronGeometry.js +21 -0
  32. package/engine/graphics/micron/plugin/MicronRenderPlugin.js +0 -3
  33. package/engine/graphics/micron/prototypeVirtualGeometry.js +69 -1
  34. package/engine/graphics/render/layers/RenderLayer.js +22 -85
  35. package/engine/graphics/render/visibility/VisibilityComputer.js +23 -103
  36. package/package.json +1 -1
  37. package/samples/terrain/editor.js +0 -1
@@ -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
  };
@@ -672,37 +672,37 @@ BinaryNode.prototype.computeSAH = function () {
672
672
  };
673
673
 
674
674
  BinaryNode.prototype.updateLeafNodeCount = function () {
675
- let n = 0;
675
+ let node = this;
676
676
 
677
- const right = this.right;
677
+ while (node !== null) {
678
+ let n = 0;
678
679
 
679
- if (right !== null) {
680
- if (right.isLeafNode) {
681
- n++;
682
- } else {
683
- 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
+ }
684
688
  }
685
- }
686
689
 
687
- const left = this.left;
690
+ const left = this.left;
688
691
 
689
- if (left !== null) {
690
- if (left.isLeafNode) {
691
- n++;
692
- } else {
693
- n += left.leafNodeCount;
692
+ if (left !== null) {
693
+ if (left.isLeafNode) {
694
+ n++;
695
+ } else {
696
+ n += left.leafNodeCount;
697
+ }
694
698
  }
695
- }
696
-
697
- this.leafNodeCount = n;
698
699
 
699
- // propagate update up the tree
700
- let parentNode = this.parentNode;
700
+ node.leafNodeCount = n;
701
701
 
702
- if (parentNode !== null) {
703
- // bubble up
704
- parentNode.updateLeafNodeCount();
702
+ // propagate update up the tree
703
+ node = node.parentNode;
705
704
  }
705
+
706
706
  }
707
707
 
708
708
 
@@ -1150,19 +1150,18 @@ BinaryNode.prototype.computeBalanceFactor = function () {
1150
1150
  };
1151
1151
 
1152
1152
  /**
1153
- *
1153
+ * @template T
1154
1154
  * @param {number} x0
1155
1155
  * @param {number} y0
1156
1156
  * @param {number} z0
1157
1157
  * @param {number} x1
1158
1158
  * @param {number} y1
1159
1159
  * @param {number} z1
1160
- * @param {*} value
1160
+ * @param {T} value
1161
1161
  * @returns {LeafNode}
1162
1162
  */
1163
1163
  BinaryNode.prototype.insert = function (x0, y0, z0, x1, y1, z1, value) {
1164
- const leaf = new LeafNode(value);
1165
- leaf.setBounds(x0, y0, z0, x1, y1, z1);
1164
+ const leaf = new LeafNode(value, x0, y0, z0, x1, y1, z1);
1166
1165
  this.insertNode(leaf);
1167
1166
  return leaf;
1168
1167
  };
@@ -1196,7 +1195,6 @@ function transplantNewCommonParent(node, child) {
1196
1195
  return bNode;
1197
1196
  }
1198
1197
 
1199
-
1200
1198
  /**
1201
1199
  *
1202
1200
  * @param {Node|BinaryNode|LeafNode} child
@@ -1251,55 +1249,6 @@ BinaryNode.prototype.insertNode = function (child) {
1251
1249
  }
1252
1250
  }
1253
1251
 
1254
- /**
1255
- * @deprecated
1256
- * @param {Node|BinaryNode|LeafNode} child
1257
- */
1258
- BinaryNode.prototype.insertNode_old = function (child) {
1259
- assert.notNull(child, "child");
1260
- assert.defined(child, "child");
1261
- assert.isInstanceOf(child, Node, 'child', "Node");
1262
- assert.equal(child.parentNode, null, "parentNode must be null, otherwise Node still belongs to another tree");
1263
-
1264
- const node = this.findParentFor(child);
1265
-
1266
- let bNode;
1267
-
1268
- if (
1269
- node.isBinaryNode &&
1270
- !(node.isProtected() && node !== this) // protected node, can't insert into this subtree
1271
- ) {
1272
-
1273
- if (node.left === null) {
1274
- node.left = child;
1275
- child.parentNode = node;
1276
- node.bubbleExpandToFit(child);
1277
-
1278
- } else if (node.right === null) {
1279
-
1280
- node.right = child;
1281
- child.parentNode = node;
1282
- node.bubbleExpandToFit(child);
1283
-
1284
- } else {
1285
- //take right child and insert another binary node there
1286
- bNode = new BinaryNode();
1287
- bNode.setChildren(node.right, child);
1288
- //
1289
- node.right = bNode;
1290
- bNode.parentNode = node;
1291
- node.bubbleExpandToFit(bNode);
1292
- }
1293
-
1294
- node.updateLeafNodeCount();
1295
- } else {
1296
- //need to do transplanting and introduce a new common parent
1297
- transplantNewCommonParent(node, child);
1298
-
1299
- }
1300
-
1301
- };
1302
-
1303
1252
  /**
1304
1253
  * @param {boolean} deep
1305
1254
  * @returns {BinaryNode}
@@ -9,6 +9,7 @@ import computeMortonCode from "../../geom/3d/morton/Morton.js";
9
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
  /**
@@ -835,7 +836,7 @@ AABB3.prototype.intersectFrustumDegree = function (frustum) {
835
836
 
836
837
  let i = 0;
837
838
  let result = 2;
838
- for (i = 0; i < 6; i++) {
839
+ for (; i < 6; i++) {
839
840
 
840
841
  const plane = planes[i];
841
842
 
@@ -849,6 +850,16 @@ AABB3.prototype.intersectFrustumDegree = function (frustum) {
849
850
  }
850
851
  return result;
851
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
+ };
852
863
 
853
864
  /**
854
865
  *
@@ -867,6 +878,40 @@ AABB3.prototype.intersectFrustum = function intersectFrustum(frustum) {
867
878
  return true;
868
879
  };
869
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
+
870
915
  /**
871
916
  *
872
917
  * @param {number} v
@@ -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
+ }
@@ -6,13 +6,11 @@ export class ThreeFrustumsIntersectionBVHVisitor extends BVHVisitor {
6
6
  super();
7
7
 
8
8
  /**
9
- * Collection of THREE.js Frustums
9
+ * [plane_x, plane_y, plane_z, constant] collection, defining a frustum
10
10
  * @private
11
- * @type {Frustum[]}
11
+ * @type {ArrayLike<number>|number[]}
12
12
  */
13
- this.frustums = [];
14
-
15
- this.frustumCount = 0;
13
+ this.frustum = [];
16
14
 
17
15
  /**
18
16
  *
@@ -23,49 +21,32 @@ export class ThreeFrustumsIntersectionBVHVisitor extends BVHVisitor {
23
21
 
24
22
  /**
25
23
  *
26
- * @param {Frustum[]} frustums
24
+ * @param {ArrayLike<number>|number[]|Float32Array} frustum
27
25
  */
28
- setFrustums(frustums) {
29
- this.frustums = frustums;
30
- this.frustumCount = frustums.length;
26
+ setFrustum(frustum) {
27
+ this.frustum = frustum;
31
28
  }
32
29
 
33
30
  visitLeaf(node) {
34
31
 
35
- const n = this.frustumCount;
36
-
37
- for (let i = 0; i < n; i++) {
32
+ const degree = node.intersectFrustumDegree_array(this.frustum);
38
33
 
39
- const degree = node.intersectFrustumDegree(this.frustums[i]);
40
-
41
- if (degree !== 0) {
42
- this.collector.visitLeaf(node);
43
- return;
44
- }
34
+ if (degree !== 0) {
35
+ // at least partially visible
36
+ this.collector.visitLeaf(node);
45
37
  }
46
-
47
38
  }
48
39
 
49
40
  visitBinary(node) {
50
- let flag = false;
51
-
52
- const n = this.frustumCount;
53
-
54
- for (let i = 0; i < n; i++) {
55
-
56
- const degree = node.intersectFrustumDegree(this.frustums[i]);
57
41
 
58
- if (degree === 2) {
59
- //completely inside
60
- traverseBinaryNodeUsingVisitor(node, this.collector);
61
- return false;
62
- } else if (degree === 1) {
63
- //partially inside, continue traversal
64
- flag = true;
65
- }
42
+ const degree = node.intersectFrustumDegree_array(this.frustum);
66
43
 
44
+ if (degree === 2) {
45
+ //completely inside, do fast traversal
46
+ traverseBinaryNodeUsingVisitor(node, this.collector);
47
+ return false;
67
48
  }
68
49
 
69
- return flag;
50
+ return degree === 1;
70
51
  }
71
52
  }
@@ -0,0 +1,52 @@
1
+ /**
2
+ *
3
+ * @type {(BinaryNode|LeafNode)[]}
4
+ */
5
+ const stack = [];
6
+
7
+
8
+ /**
9
+ * @template T
10
+ * @param {T[]} destination
11
+ * @param {number} destinationOffset
12
+ * @param {BinaryNode<T>} root
13
+ * @param {ArrayLike<number>|number[]|Float32Array} frustum
14
+ * @returns {number} Number of results
15
+ */
16
+ export function queryBinaryNode_FrustumIntersections_Data(destination, destinationOffset, root, frustum) {
17
+ let n;
18
+ let i = 0;
19
+ let stackPointer = 1;
20
+
21
+ stack[0] = root;
22
+
23
+ while (stackPointer > 0) {
24
+ stackPointer--;
25
+
26
+ n = stack[stackPointer];
27
+
28
+ if (!n.intersectFrustum_array(frustum)) {
29
+ continue;
30
+ }
31
+
32
+ if (n.isBinaryNode) {
33
+
34
+ if (n.right !== null) {
35
+ stack[stackPointer++] = n.right;
36
+ }
37
+
38
+ if (n.left !== null) {
39
+ stack[stackPointer++] = n.left;
40
+ }
41
+
42
+ } else {
43
+
44
+ destination[destinationOffset + i] = n.object;
45
+
46
+ i++;
47
+ }
48
+
49
+ }
50
+
51
+ return i;
52
+ }
@@ -1,8 +1,7 @@
1
-
2
1
  /**
3
2
  * NOTE: Based on Transforming Axis-Aligned Bounding Boxes by Jim Arvo from "Graphics Gems", Academic Press, 1990
4
- * @param {number[]} result
5
- * @param {number[]} aabb
3
+ * @param {ArrayLike<number>|number[]|Float32Array} result
4
+ * @param {ArrayLike<number>|number[]|Float32Array} aabb
6
5
  * @param {number[]} matrix 4x4 matrix
7
6
  */
8
7
  export function aabb3_matrix4_project(result, aabb, matrix) {
@@ -22,4 +22,6 @@ export default class Quaternion {
22
22
  threeSetRotationMatrix(result: Matrix4): void
23
23
 
24
24
  setFromRotationMatrix(m: Matrix4): void
25
+
26
+ decodeFromUint32(uint: number): void
25
27
  }
@@ -8,7 +8,6 @@ const scratch_m4_2 = new Float32Array(16);
8
8
  export class TransformAttachmentBinding extends AttachmentBinding {
9
9
  constructor() {
10
10
  super();
11
-
12
11
  }
13
12
 
14
13
  /**
@@ -5,28 +5,13 @@ export class FoliageVisibilitySetBuilder extends BVHVisitor {
5
5
  constructor() {
6
6
  super();
7
7
 
8
- /**
9
- * Visibility filters
10
- * @type {(function(LeafNode):boolean)[]}
11
- */
12
- this.filters = [];
13
-
14
8
  /**
15
9
  *
16
10
  * @type {BitSet}
17
11
  */
18
12
  this.visibleSet = new BitSet();
19
13
  //prevent re-allocation
20
- this.visibleSet.__shrinkFactor = 0;
21
- }
22
-
23
- /**
24
- *
25
- * @param {(function(LeafNode):boolean)[]} filters
26
- */
27
- setFilters(filters) {
28
- this.filters = filters;
29
- this.filterCount = filters.length;
14
+ this.visibleSet.preventShrink();
30
15
  }
31
16
 
32
17
  initialize() {
@@ -34,21 +19,6 @@ export class FoliageVisibilitySetBuilder extends BVHVisitor {
34
19
  }
35
20
 
36
21
  visitLeaf(node) {
37
-
38
- const n = this.filterCount;
39
-
40
- const filters = this.filters;
41
-
42
- for (let i = 0; i < n; i++) {
43
- const visibilityFilter = filters[i];
44
-
45
- if (!visibilityFilter(node)) {
46
- //not visible
47
- return;
48
- }
49
-
50
- }
51
-
52
22
  const index = node.object;
53
23
 
54
24
  //TODO check screen space size to decide if element should be seen or not