@woosh/meep-engine 2.34.45 → 2.34.49

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 (27) hide show
  1. package/core/binary/BitSet.js +10 -3
  2. package/core/bvh2/BinaryNode.js +53 -25
  3. package/core/bvh2/traversal/bvh_traverse_pre_order_using_stack.js +43 -0
  4. package/core/bvh2/visual/convert_bvh_to_dot_format_string.js +50 -0
  5. package/core/geom/3d/aabb/aabb3_estimate_projected_area2.js +1 -1
  6. package/core/geom/3d/frustum/frustum_from_projection_matrix_array.js +27 -24
  7. package/core/graph/convertGraphToDotString.js +4 -4
  8. package/core/graph/v2/Graph.js +4 -0
  9. package/engine/asset/loaders/geometry/geometry/computeGeometryEquality.js +2 -1
  10. package/engine/ecs/foliage/ecs/Foliage2System.js +22 -5
  11. package/engine/graphics/compute_geometry_polycount.js +21 -0
  12. package/engine/graphics/ecs/mesh-v2/sample/prototypeShadedGeometry.js +64 -9
  13. package/engine/graphics/micron/convert_three_object_to_micron.js +0 -2
  14. package/engine/graphics/micron/format/MicronGeometry.js +1 -3
  15. package/engine/graphics/micron/format/MicronGeometryPatch.js +33 -23
  16. package/engine/graphics/micron/format/serialization/MicronGeometryBinarySerializationAdapter.js +6 -0
  17. package/engine/graphics/micron/plugin/GLTFAssetTransformer.js +176 -0
  18. package/engine/graphics/micron/plugin/MicronRenderPlugin.js +1 -135
  19. package/engine/graphics/micron/prototypeVirtualGeometry.js +9 -5
  20. package/engine/graphics/micron/render/VirtualGeometryBuilder.js +14 -53
  21. package/engine/graphics/micron/render/refinement/RefinementSpec.js +0 -11
  22. package/engine/graphics/micron/render/refinement/get_geometry_patch_cut.js +125 -0
  23. package/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +318 -13
  24. package/engine/graphics/render/layers/RenderLayer.js +22 -14
  25. package/engine/graphics/render/visibility/IncrementalDeltaSet.js +18 -5
  26. package/engine/graphics/render/visibility/VisibilityComputer.js +11 -15
  27. package/package.json +1 -1
@@ -59,7 +59,6 @@ const SHRINK_FACTOR = 0.5;
59
59
  */
60
60
  const RESIZE_COUNT_THRESHOLD = 128;
61
61
 
62
-
63
62
  /**
64
63
  * Dynamically sized bit field
65
64
  * @constructor
@@ -389,6 +388,7 @@ BitSet.prototype.set = function (bitIndex, value) {
389
388
  const bitIndexInc = bitIndex + 1;
390
389
 
391
390
  if (bitIndexInc > this.__length) {
391
+ // ensure capacity
392
392
  this.__setLength(bitIndexInc);
393
393
  }
394
394
 
@@ -401,6 +401,7 @@ BitSet.prototype.set = function (bitIndex, value) {
401
401
  this.__data_uint32[word_offset] &= ~word_mask;
402
402
 
403
403
  if (bitIndex === this.__length - 1) {
404
+ // trim down set size potentially
404
405
  const newLastSetBit = this.previousSetBit(bitIndex);
405
406
 
406
407
  this.__setLength(newLastSetBit + 1);
@@ -533,12 +534,18 @@ BitSet.prototype.shift = function (distance, start_index, end_index) {
533
534
  * Sets all of the bits in this BitSet to false.
534
535
  */
535
536
  BitSet.prototype.reset = function () {
536
- if (this.__length <= 0) {
537
+ const current_length = this.__length;
538
+
539
+ if (current_length <= 0) {
537
540
  // no action required
538
541
  return;
542
+ } else if (current_length <= 32) {
543
+ // one word, set first word to 0 manually
544
+ this.__data_uint32[0] = 0;
545
+ } else {
546
+ this.__data_uint32.fill(0, 0, Math.ceil(current_length / 32));
539
547
  }
540
548
 
541
- this.__data_uint32.fill(0, 0, Math.ceil(this.__length / 32));
542
549
  this.__length = 0;
543
550
  };
544
551
 
@@ -211,44 +211,62 @@ export class BinaryNode extends Node {
211
211
  */
212
212
  __insertion_findSiblingFor(box) {
213
213
 
214
- const open_set = [this];
215
- let cursor = 1;
214
+ let node = this;
215
+ let cost_left = 0;
216
+ let cost_right = 0;
216
217
 
217
- let best_cost = Infinity;
218
- let best_node = this;
218
+ while (node.isBinaryNode) {
219
+ const left = node.left;
220
+ const right = node.right;
219
221
 
220
- while (cursor > 0) {
221
- const node = open_set[--cursor];
222
+ const area = aabb3_box_surface_area_2(node);
222
223
 
223
- const cost = inclusion_surface_area_heuristic(node, box);
224
+ const combined_area = combined_surface_area(node, box);
224
225
 
225
- if (cost < best_cost) {
226
- best_cost = cost;
227
- best_node = node;
228
- }
226
+ //cost of creating a new parent for this node and the new leaf
227
+ const cost = combined_area;
229
228
 
230
- if (node.isBinaryNode) {
229
+ // minimum cost of pushing the leaf further down the tree
230
+ const inheritance_cost = combined_area - area;
231
231
 
232
- // consider pushing children into the queue
232
+ // cost of descending left
233
+ if (left !== null) {
234
+ if (left.isLeafNode) {
235
+ cost_left = combined_surface_area(left, box) + inheritance_cost;
236
+ } else {
237
+ cost_left = combined_surface_area(left, box) - aabb3_box_surface_area_2(left) + inheritance_cost;
238
+ }
239
+ } else {
240
+ cost_left = Infinity;
241
+ }
233
242
 
234
- // compute lower bound for cost
235
- const c_low = inclusion_cost_lower_bound(node, box);
243
+ // cost of descending right
244
+ if (right !== null) {
236
245
 
237
- if (c_low < best_cost) {
238
- // worth-while to explore children
239
- if (node.left !== null) {
240
- open_set[cursor++] = node.left;
241
- }
242
- if (node.right !== null) {
243
- open_set[cursor++] = node.right
244
- }
246
+ if (right.isLeafNode) {
247
+ cost_right = combined_surface_area(right, box) + inheritance_cost;
248
+ } else {
249
+ cost_right = combined_surface_area(right, box) - aabb3_box_surface_area_2(right) + inheritance_cost;
245
250
  }
251
+ } else {
252
+ cost_right = Infinity;
246
253
  }
247
254
 
255
+ if (cost < cost_left && cost < cost_right) {
256
+ // descending either branch is too expensive
257
+ break;
258
+ }
248
259
 
260
+ if (cost_left < cost_right && left !== null) {
261
+ node = left;
262
+ } else if (right !== null) {
263
+ node = right;
264
+ } else {
265
+ break;
266
+ }
249
267
  }
250
268
 
251
- return best_node;
269
+ return node;
252
270
  }
253
271
 
254
272
  /**
@@ -1134,6 +1152,16 @@ BinaryNode.prototype.isBinaryNode = true;
1134
1152
  * @returns {number}
1135
1153
  */
1136
1154
  function inclusion_surface_area_heuristic(node, addition) {
1155
+ return combined_surface_area(node, addition) - aabb3_box_surface_area_2(node);
1156
+ }
1157
+
1158
+ /**
1159
+ *
1160
+ * @param {AABB3} node
1161
+ * @param {AABB3} addition
1162
+ * @returns {number}
1163
+ */
1164
+ function combined_surface_area(node, addition) {
1137
1165
  const x0 = min2(node.x0, addition.x0);
1138
1166
  const y0 = min2(node.y0, addition.y0);
1139
1167
  const z0 = min2(node.z0, addition.z0);
@@ -1142,7 +1170,7 @@ function inclusion_surface_area_heuristic(node, addition) {
1142
1170
  const y1 = max2(node.y1, addition.y1);
1143
1171
  const z1 = max2(node.z1, addition.z1);
1144
1172
 
1145
- return aabb3_compute_half_surface_area(x0, y0, z0, x1, y1, z1) - aabb3_box_surface_area_2(node);
1173
+ return aabb3_compute_half_surface_area(x0, y0, z0, x1, y1, z1);
1146
1174
  }
1147
1175
 
1148
1176
  /**
@@ -0,0 +1,43 @@
1
+ const stack = [];
2
+ let stackPointer = 0;
3
+
4
+ /**
5
+ *
6
+ * @param {BinaryNode} root
7
+ * @param {function(BinaryNode|LeafNode):*} visitor
8
+ * @param {*} [thisArg]
9
+ * @return {number}
10
+ */
11
+ export function bvh_traverse_pre_order_using_stack(root, visitor, thisArg) {
12
+ let visitCount = 0;
13
+
14
+ const stackOffset = stackPointer;
15
+
16
+ stack[stackPointer++] = root;
17
+
18
+ let n;
19
+
20
+ while (stackPointer-- > stackOffset) {
21
+
22
+ visitCount++;
23
+
24
+ n = stack[stackPointer];
25
+
26
+ visitor.call(thisArg, n);
27
+
28
+ if (!n.isLeafNode) {
29
+ //a binary node
30
+ if (n.right !== null) {
31
+ stack[stackPointer++] = n.right;
32
+ }
33
+ if (n.left !== null) {
34
+ stack[stackPointer++] = n.left;
35
+ }
36
+ }
37
+ }
38
+
39
+ // drop stack frame
40
+ stackPointer = stackOffset;
41
+
42
+ return visitCount;
43
+ }
@@ -0,0 +1,50 @@
1
+ import { convertGraphToDotString } from "../../graph/convertGraphToDotString.js";
2
+ import { bvh_traverse_pre_order_using_stack } from "../traversal/bvh_traverse_pre_order_using_stack.js";
3
+ import { Graph } from "../../graph/v2/Graph.js";
4
+ import { Edge, EdgeDirectionType } from "../../graph/Edge.js";
5
+
6
+ /**
7
+ *
8
+ * @param {BinaryNode} bvh
9
+ * @returns {Graph}
10
+ */
11
+ export function bvh_to_graph(bvh) {
12
+ //traverse twice, first collect all nodes, second time introduce edges
13
+ const graph = new Graph();
14
+
15
+ bvh_traverse_pre_order_using_stack(bvh, node => {
16
+ graph.addNode(node);
17
+ });
18
+
19
+ bvh_traverse_pre_order_using_stack(bvh, node => {
20
+ if (node.isBinaryNode) {
21
+
22
+ if (node.left !== null) {
23
+ const edge = new Edge(node, node.left);
24
+
25
+ edge.direction = EdgeDirectionType.Forward;
26
+
27
+ graph.addEdge(edge);
28
+ }
29
+ if (node.right !== null) {
30
+ const edge = new Edge(node, node.right);
31
+
32
+ edge.direction = EdgeDirectionType.Forward;
33
+
34
+ graph.addEdge(edge);
35
+ }
36
+ }
37
+ });
38
+
39
+ return graph;
40
+ }
41
+
42
+ /**
43
+ * Build a Graphviz DOT representation of the graph
44
+ * @param {BinaryNode} bvh
45
+ * @returns {string}
46
+ */
47
+ export function convert_bvh_to_dot_format_string(bvh) {
48
+ const graph = bvh_to_graph(bvh);
49
+ return convertGraphToDotString(graph);
50
+ }
@@ -16,7 +16,7 @@ export function aabb3_estimate_projected_area2(aabb, matrix) {
16
16
  for (let i = 0; i < 2; i++) {
17
17
  for (let j = 0; j < 3; j++) {
18
18
 
19
- const m_a = i * 4 + j;
19
+ const m_a = i + j* 4;
20
20
  const m_v = matrix[m_a];
21
21
 
22
22
  const a = m_v * aabb[j];
@@ -7,53 +7,56 @@
7
7
  * @param {number} z
8
8
  * @param {number} w
9
9
  */
10
- function array_set_plane_normalized(destination, destination_offset, x, y, z, w) {
10
+ function array_set_plane_normalized(
11
+ destination, destination_offset,
12
+ x, y, z, w
13
+ ) {
11
14
  // compute vector length
12
15
  const length = Math.hypot(x, y, z);
13
16
 
14
- const inverseNormalLength = 1.0 / length;
17
+ const inverse_length = 1.0 / length;
15
18
 
16
19
  // apply normalization
17
- destination[destination_offset] = x * inverseNormalLength;
18
- destination[destination_offset + 1] = y * inverseNormalLength;
19
- destination[destination_offset + 2] = z * inverseNormalLength;
20
- destination[destination_offset + 3] = w * inverseNormalLength;
20
+ destination[destination_offset] = x * inverse_length;
21
+ destination[destination_offset + 1] = y * inverse_length;
22
+ destination[destination_offset + 2] = z * inverse_length;
23
+ destination[destination_offset + 3] = w * inverse_length;
21
24
  }
22
25
 
23
26
  /**
24
27
  * Set frustum from projection matrix
25
28
  * @param {number[]|Float32Array} frustum_planes
26
- * @param {number[]} me
29
+ * @param {number[]} m4
27
30
  */
28
- export function frustum_from_projection_matrix_array(frustum_planes, me) {
31
+ export function frustum_from_projection_matrix_array(frustum_planes, m4) {
29
32
 
30
- const me0 = me[0];
31
- const me3 = me[3];
33
+ const me0 = m4[0];
34
+ const me3 = m4[3];
32
35
 
33
- const me4 = me[4];
34
- const me7 = me[7];
36
+ const me4 = m4[4];
37
+ const me7 = m4[7];
35
38
 
36
- const me8 = me[8];
37
- const me11 = me[11];
39
+ const me8 = m4[8];
40
+ const me11 = m4[11];
38
41
 
39
- const me12 = me[12];
40
- const me15 = me[15];
42
+ const me12 = m4[12];
43
+ const me15 = m4[15];
41
44
 
42
45
  array_set_plane_normalized(frustum_planes, 0, me3 - me0, me7 - me4, me11 - me8, me15 - me12);
43
46
  array_set_plane_normalized(frustum_planes, 4, me3 + me0, me7 + me4, me11 + me8, me15 + me12);
44
47
 
45
- const me1 = me[1];
46
- const me5 = me[5];
47
- const me9 = me[9];
48
- const me13 = me[13];
48
+ const me1 = m4[1];
49
+ const me5 = m4[5];
50
+ const me9 = m4[9];
51
+ const me13 = m4[13];
49
52
 
50
53
  array_set_plane_normalized(frustum_planes, 8, me3 + me1, me7 + me5, me11 + me9, me15 + me13);
51
54
  array_set_plane_normalized(frustum_planes, 12, me3 - me1, me7 - me5, me11 - me9, me15 - me13);
52
55
 
53
- const me2 = me[2];
54
- const me6 = me[6];
55
- const me10 = me[10];
56
- const me14 = me[14];
56
+ const me2 = m4[2];
57
+ const me6 = m4[6];
58
+ const me10 = m4[10];
59
+ const me14 = m4[14];
57
60
 
58
61
  array_set_plane_normalized(frustum_planes, 16, me3 - me2, me7 - me6, me11 - me10, me15 - me14);
59
62
  array_set_plane_normalized(frustum_planes, 20, me3 + me2, me7 + me6, me11 + me10, me15 + me14);
@@ -2,7 +2,7 @@ import LineBuilder from "../codegen/LineBuilder.js";
2
2
  import { EdgeDirectionType } from "./Edge.js";
3
3
 
4
4
  /**
5
- * Build a DOT representation of the graph
5
+ * Build a Graphviz DOT representation of the graph
6
6
  * @param {Graph} graph
7
7
  * @returns {string}
8
8
  */
@@ -13,7 +13,7 @@ export function convertGraphToDotString(graph) {
13
13
 
14
14
  lb.indent();
15
15
 
16
- const nodes = graph.nodes;
16
+ const nodes = Array.from(graph.getNodes());
17
17
  const nodeCount = nodes.length;
18
18
 
19
19
  function nodeId(index) {
@@ -33,9 +33,9 @@ export function convertGraphToDotString(graph) {
33
33
 
34
34
  const node = nodes[i];
35
35
 
36
- const attachedEdges = graph.getAttachedEdges(node);
36
+ const attachedEdges = [];
37
37
 
38
- const nAttachedEdges = attachedEdges.length;
38
+ const nAttachedEdges = graph.getAttachedEdges(attachedEdges, node);
39
39
 
40
40
  for (let j = 0; j < nAttachedEdges; j++) {
41
41
  const edge = attachedEdges[j];
@@ -335,6 +335,10 @@ export class Graph {
335
335
  * @returns {number}
336
336
  */
337
337
  getAttachedEdges(result, node) {
338
+ assert.defined(result, 'result');
339
+ assert.isArray(result, 'result');
340
+ assert.defined(node, 'node');
341
+
338
342
  const context = this.__nodes.get(node);
339
343
 
340
344
  if (context === undefined) {
@@ -1,4 +1,5 @@
1
1
  import { isArrayEqualStrict } from "../../../../../core/collection/array/isArrayEqualStrict.js";
2
+ import { is_typed_array_equals } from "../../../../../core/collection/array/typed/is_typed_array_equals.js";
2
3
 
3
4
 
4
5
  /**
@@ -46,7 +47,7 @@ export function computeGeometryEquality(a, b) {
46
47
  const a_attribute = a.attributes[key];
47
48
  const b_attribute = b.attributes[key];
48
49
 
49
- if (!isArrayEqualStrict(a_attribute.array, b_attribute.array)) {
50
+ if (!is_typed_array_equals(a_attribute.array, b_attribute.array)) {
50
51
  return false;
51
52
  }
52
53
  }
@@ -111,13 +111,26 @@ export class Foliage2System extends System {
111
111
 
112
112
  this.renderLayer = graphics.layers.create('instanced-mesh-system');
113
113
 
114
- graphics.views.elements.forEach(this.__handle_view_added, this);
114
+ /**
115
+ *
116
+ * @type {CameraViewManager}
117
+ */
118
+ const views = graphics.views;
119
+
120
+ /**
121
+ *
122
+ * @type {List<CameraView>}
123
+ */
124
+ const view_list = views.elements;
125
+
126
+ view_list.forEach(this.__handle_view_added, this);
115
127
 
116
- graphics.views.elements.on.added.add(this.__handle_view_added, this);
117
- graphics.views.elements.on.removed.add(this.__handle_view_removed, this);
128
+ view_list.on.added.add(this.__handle_view_added, this);
129
+ view_list.on.removed.add(this.__handle_view_removed, this);
118
130
 
119
- this.renderLayer.buildVisibleSet = (view, visitObject, thisArg) => {
131
+ this.renderLayer.buildVisibleSet = (destination, destination_offset, view) => {
120
132
  const data = this.data;
133
+ let additions = 0;
121
134
 
122
135
  for (let entity in data) {
123
136
 
@@ -147,11 +160,15 @@ export class Foliage2System extends System {
147
160
  }
148
161
 
149
162
  const mesh = group.mesh;
150
- visitObject.call(thisArg, mesh);
163
+
164
+ destination[additions + destination_offset] = mesh;
165
+ additions++;
151
166
  }
152
167
 
153
168
  }
154
169
  }
170
+
171
+ return additions;
155
172
  };
156
173
 
157
174
  readyCallback();
@@ -0,0 +1,21 @@
1
+ /**
2
+ *
3
+ * @param {THREE.BufferGeometry} geometry
4
+ * @returns {number}
5
+ */
6
+ export function compute_geometry_polycount(geometry) {
7
+ const index = geometry.getIndex();
8
+
9
+ if (index !== null) {
10
+ return index.count / 3;
11
+ }
12
+
13
+ const position_attribute = geometry.getAttribute('position');
14
+
15
+ if (position_attribute !== undefined) {
16
+ return position_attribute.count / 3;
17
+ }
18
+
19
+ // no valid way to discern polycount, assume 0
20
+ return 0;
21
+ }
@@ -4,6 +4,15 @@ import EntityBuilder from "../../../../ecs/EntityBuilder.js";
4
4
  import { Transform } from "../../../../ecs/transform/Transform.js";
5
5
  import { ShadedGeometry } from "../ShadedGeometry.js";
6
6
  import { BoxBufferGeometry, MeshBasicMaterial } from "three";
7
+ import { randomFloatBetween } from "../../../../../core/math/random/randomFloatBetween.js";
8
+ import { seededRandom } from "../../../../../core/math/random/seededRandom.js";
9
+ import ViewportPosition from "../../../../ecs/gui/position/ViewportPosition.js";
10
+ import GUIElement from "../../../../ecs/gui/GUIElement.js";
11
+ import ButtonView from "../../../../../view/elements/button/ButtonView.js";
12
+ import { downloadAsFile } from "../../../../../core/binary/ByteArrayTools.js";
13
+ import { convert_bvh_to_dot_format_string } from "../../../../../core/bvh2/visual/convert_bvh_to_dot_format_string.js";
14
+ import ViewportPositionSystem from "../../../../ecs/gui/position/ViewportPositionSystem.js";
15
+ import GUIElementSystem from "../../../../ecs/gui/GUIElementSystem.js";
7
16
 
8
17
  const eh = new EngineHarness();
9
18
 
@@ -26,22 +35,68 @@ async function main(engine) {
26
35
  color: 0xFFFFFF
27
36
  });
28
37
 
29
- material.visible = false;
38
+ // material.visible = false;
30
39
 
31
40
  window.material = material;
32
41
 
33
- const g = ShadedGeometry.from(new BoxBufferGeometry(), material);
42
+ const geometry = new BoxBufferGeometry();
34
43
 
44
+ const random = seededRandom(0);
45
+
46
+ for (let i = 0; i < 100000; i++) {
47
+
48
+ new EntityBuilder()
49
+ .add(Transform.fromJSON({
50
+ position: {
51
+ x: randomFloatBetween(random, -50, 50),
52
+ y: randomFloatBetween(random, 0, 10),
53
+ z: randomFloatBetween(random, -50, 50)
54
+ },
55
+ scale: 0.01
56
+ }))
57
+ .add(ShadedGeometry.from(geometry, material))
58
+ .build(ecd);
59
+ }
60
+
61
+ debug_button(engine, () => {
62
+ const dot = convert_bvh_to_dot_format_string(engine.graphics.layers.getLayerByName('shaded-geometry').bvh);
63
+ downloadAsFile(dot, 'bvh.dot', 'text');
64
+
65
+ }, 'save dot file');
66
+
67
+ }
68
+
69
+
70
+ const entityManager = engine.entityManager;
71
+
72
+ /**
73
+ *
74
+ * @param {Engine} engine
75
+ * @param {function} action
76
+ * @param {string} [name]
77
+ * @param {EntityComponentDataset} ecd
78
+ */
79
+ function debug_button(engine, action, name = "Button", ecd = entityManager.dataset) {
80
+ if (entityManager.getSystem(ViewportPositionSystem) === null) {
81
+ entityManager.addSystem(new ViewportPositionSystem(engine.graphics.viewport.size));
82
+ }
83
+
84
+ if (entityManager.getSystem(GUIElementSystem) === null) {
85
+ entityManager.addSystem(new GUIElementSystem(engine.gui.view, engine));
86
+ }
35
87
 
36
88
  new EntityBuilder()
37
- .add(Transform.fromJSON({
38
- position: {
39
- x: 10,
40
- y: 1,
41
- z: 10
89
+ .add(ViewportPosition.fromJSON({}))
90
+ .add(GUIElement.fromView(new ButtonView({
91
+ action,
92
+ name,
93
+ css: {
94
+ background: 'rgba(255,255,255,0.8)',
95
+ border: '1px solid black',
96
+ borderRadius: '4px',
97
+ padding: '2px',
42
98
  }
43
- }))
44
- .add(g)
99
+ })))
45
100
  .build(ecd);
46
101
  }
47
102
 
@@ -76,8 +76,6 @@ export async function convert_three_object_to_micron(object, micron_cache = defa
76
76
 
77
77
  await micron_cache.set(g, micron_geometry);
78
78
 
79
- // console.log(micron_geometry);
80
-
81
79
  return micron_geometry;
82
80
  }
83
81
 
@@ -226,11 +226,9 @@ export class MicronGeometry {
226
226
  }
227
227
 
228
228
  // push to stack
229
- stack[stack_cursor] = child;
229
+ stack[stack_cursor++] = child;
230
230
 
231
231
  included_set.set(child.id, true);
232
-
233
- stack_cursor++;
234
232
  }
235
233
  }
236
234
  }