@woosh/meep-engine 2.34.42 → 2.34.46

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 (69) hide show
  1. package/core/bvh2/BinaryNode.js +60 -32
  2. package/core/bvh2/LeafNode.js +2 -1
  3. package/core/bvh2/aabb3/AABB3.js +879 -1059
  4. package/core/bvh2/aabb3/AABB3.spec.js +5 -7
  5. package/core/bvh2/aabb3/aabb3_array_intersects_ray.js +2 -2
  6. package/core/bvh2/aabb3/aabb3_box_surface_area_2.js +10 -0
  7. package/core/bvh2/aabb3/aabb3_compute_half_surface_area.js +16 -0
  8. package/core/bvh2/aabb3/aabb3_compute_surface_area.js +18 -0
  9. package/core/bvh2/aabb3/aabb3_expand_array.js +15 -0
  10. package/core/bvh2/aabb3/aabb3_intersect_aabb3.js +28 -0
  11. package/core/bvh2/aabb3/aabb3_intersect_ray_slab.js +73 -0
  12. package/core/bvh2/aabb3/{aabb3_intersects_frustum.js → aabb3_intersects_frustum_array.js} +16 -1
  13. package/core/bvh2/aabb3/aabb3_intersects_line_segment.js +79 -0
  14. package/core/bvh2/aabb3/aabb3_intersects_ray.js +92 -0
  15. package/core/bvh2/aabb3/{AABB3Math.spec.js → aabb3_intersects_ray.spec.js} +3 -3
  16. package/core/bvh2/aabb3/aabb3_intersects_ray_fast.js +176 -0
  17. package/core/bvh2/aabb3/aabb3_score_boxes_SAH.js +43 -0
  18. package/core/bvh2/aabb3/aabb_score_boxes_SAH_delta.js +37 -0
  19. package/core/bvh2/aabb3/deserializeAABB3.js +17 -0
  20. package/core/bvh2/aabb3/deserializeAABB3Encoded_v0.js +73 -0
  21. package/core/bvh2/aabb3/deserializeAABB3Quantized16Uint.js +36 -0
  22. package/core/bvh2/aabb3/serializeAABB3.js +13 -0
  23. package/core/bvh2/aabb3/serializeAABB3Quantized16Uint.js +33 -0
  24. package/core/bvh2/binary/2/BinaryUint32BVH.js +3 -3
  25. package/core/bvh2/binary/BinaryBVH.js +2 -2
  26. package/core/bvh2/binary/RayLeafIntersectionVisitor.js +2 -2
  27. package/core/bvh2/serialization/deserializeBinaryNode.js +1 -1
  28. package/core/bvh2/serialization/deserializeBinaryNodeFromBinaryBuffer.js +2 -1
  29. package/core/bvh2/serialization/serializeBinaryNode.js +1 -1
  30. package/core/bvh2/serialization/serializeBinaryNodeToBinaryBuffer.js +2 -1
  31. package/core/bvh2/transform/BottomUpOptimizingRebuilder.js +6 -5
  32. package/core/bvh2/transform/tryRotateSingleNode.js +2 -1
  33. package/core/bvh2/traversal/bvh_traverse_pre_order_using_stack.js +43 -0
  34. package/core/bvh2/visual/convert_bvh_to_dot_format_string.js +50 -0
  35. package/core/geom/3d/frustum/{array_setFromProjectionMatrix.js → frustum_from_projection_matrix_array.js} +1 -1
  36. package/core/geom/3d/topology/TopoMesh.js +0 -8
  37. package/core/geom/3d/topology/TopoVertex.js +7 -6
  38. package/core/geom/3d/topology/simplify/quadratic/Quadratic3.js +93 -5
  39. package/core/geom/3d/topology/simplify/quadratic/build_vertex_quadratics.js +7 -4
  40. package/core/geom/3d/topology/simplify/quadratic/compute_edge_collapse_cost_quadratic.js +7 -1
  41. package/core/geom/3d/topology/simplify/simplifyTopoMesh.js +1 -14
  42. package/core/graph/convertGraphToDotString.js +4 -4
  43. package/core/graph/v2/Graph.js +4 -0
  44. package/core/math/fabsf.js +8 -0
  45. package/engine/development/performance/MetricCollection.js +6 -0
  46. package/engine/ecs/foliage/ecs/Foliage2System.js +6 -2
  47. package/engine/graphics/compute_geometry_polycount.js +21 -0
  48. package/engine/graphics/ecs/light/binding/three/ThreeLightBinding.js +1 -1
  49. package/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js +2 -2
  50. package/engine/graphics/ecs/mesh-v2/sample/prototypeShadedGeometry.js +77 -7
  51. package/engine/graphics/geometry/buffered/query/RaycastNearestHitComputingVisitor.js +2 -2
  52. package/engine/graphics/micron/build/buildMicronGeometryFromBufferGeometry.js +4 -0
  53. package/engine/graphics/micron/build/hierarchy/merge_patches.js +1 -1
  54. package/engine/graphics/micron/convert_three_object_to_micron.js +2 -0
  55. package/engine/graphics/micron/format/MicronGeometryPatchOccurance.js +3 -2
  56. package/engine/graphics/micron/plugin/GLTFAssetTransformer.js +176 -0
  57. package/engine/graphics/micron/plugin/MicronRenderPlugin.js +1 -135
  58. package/engine/graphics/micron/prototypeVirtualGeometry.js +12 -7
  59. package/engine/graphics/micron/render/PatchCacheKey.js +1 -1
  60. package/engine/graphics/micron/render/VirtualGeometryBuilder.js +16 -43
  61. package/engine/graphics/micron/render/instanced/ThreeInstancedAdapter.js +5 -1
  62. package/engine/graphics/micron/render/refinement/ActivePatchList.js +4 -10
  63. package/engine/graphics/micron/render/refinement/RefinementSpec.js +16 -20
  64. package/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +316 -11
  65. package/engine/graphics/render/layers/RenderLayer.js +22 -14
  66. package/engine/graphics/render/visibility/IncrementalDeltaSet.js +18 -5
  67. package/engine/graphics/render/visibility/VisibilityComputer.js +11 -15
  68. package/package.json +1 -1
  69. package/core/bvh2/aabb3/AABB3Math.js +0 -579
@@ -23,7 +23,6 @@ export function extract_edge_cost(edge) {
23
23
  /**
24
24
  * @param {number} number_faces_to_remove minimum number of faces to removed
25
25
  * @param {BinaryHeap<EdgeCollapseCandidate>} heap
26
- * @param {EdgeCollapseCandidate[]} removed_edges
27
26
  * @param {TopoMesh} mesh
28
27
  * @param {Map<TopoEdge, EdgeCollapseCandidate>} edge_to_collapse_map
29
28
  * @param {Map<number, Quadratic3>} vertex_quadratics
@@ -32,7 +31,6 @@ export function extract_edge_cost(edge) {
32
31
  export function collapse_edges(
33
32
  number_faces_to_remove,
34
33
  heap,
35
- removed_edges,
36
34
  mesh,
37
35
  edge_to_collapse_map,
38
36
  vertex_quadratics,
@@ -64,8 +62,6 @@ export function collapse_edges(
64
62
  // continue;
65
63
  // }
66
64
 
67
- removed_edges.push(collapse_candidate);
68
-
69
65
  // find edges that need to be updated
70
66
  const victim_vertex = collapse_candidate.victim_vertex;
71
67
 
@@ -208,21 +204,15 @@ export function collapse_edges(
208
204
  * @param {TopoMesh} mesh
209
205
  * @param {number} num_faces_to_remove desired number of faces to remove
210
206
  * @param {Set<number>} [restricted_vertices] vertices that are not allowed to be removed
211
- * @returns {EdgeCollapseCandidate[]} collapsed edges
212
207
  */
213
208
  export function simplifyTopoMesh(mesh, num_faces_to_remove, restricted_vertices = new Set()) {
214
- /**
215
- *
216
- * @type {EdgeCollapseCandidate[]}
217
- */
218
- const removed_edges = [];
219
209
 
220
210
  const faces = mesh.getFaces();
221
211
  const face_count = faces.size;
222
212
 
223
213
  if (num_faces_to_remove <= 0 || face_count <= 0) {
224
214
  // we're already at the target
225
- return removed_edges;
215
+ return ;
226
216
  }
227
217
 
228
218
 
@@ -258,7 +248,6 @@ export function simplifyTopoMesh(mesh, num_faces_to_remove, restricted_vertices
258
248
  collapse_edges(
259
249
  num_faces_to_remove,
260
250
  open_set,
261
- removed_edges,
262
251
  mesh,
263
252
  edge_to_collapse_map,
264
253
  vertex_quadratics,
@@ -270,6 +259,4 @@ export function simplifyTopoMesh(mesh, num_faces_to_remove, restricted_vertices
270
259
  collapse_all_degenerate_edges(mesh.getEdges(), mesh);
271
260
 
272
261
  // debugValidateMesh(mesh);
273
-
274
- return removed_edges;
275
262
  }
@@ -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) {
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Float ABS, from standard C lib
3
+ * @param {Number} val
4
+ * @returns {number}
5
+ */
6
+ export function fabsf(val) {
7
+ return val >= 0 ? val : -val;
8
+ }
@@ -10,6 +10,12 @@ export class MetricCollection {
10
10
  this.data = new Map();
11
11
  }
12
12
 
13
+ clear() {
14
+ this.data.forEach((value, key) => {
15
+ value.clear();
16
+ });
17
+ }
18
+
13
19
  /**
14
20
  *
15
21
  * @returns {string[]}
@@ -116,8 +116,9 @@ export class Foliage2System extends System {
116
116
  graphics.views.elements.on.added.add(this.__handle_view_added, this);
117
117
  graphics.views.elements.on.removed.add(this.__handle_view_removed, this);
118
118
 
119
- this.renderLayer.buildVisibleSet = (view, visitObject, thisArg) => {
119
+ this.renderLayer.buildVisibleSet = (destination, destination_offset, view) => {
120
120
  const data = this.data;
121
+ let additions = 0;
121
122
 
122
123
  for (let entity in data) {
123
124
 
@@ -147,11 +148,14 @@ export class Foliage2System extends System {
147
148
  }
148
149
 
149
150
  const mesh = group.mesh;
150
- visitObject.call(thisArg, mesh);
151
+
152
+ destination[additions + destination_offset] = mesh;
151
153
  }
152
154
 
153
155
  }
154
156
  }
157
+
158
+ return additions;
155
159
  };
156
160
 
157
161
  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
+ }
@@ -58,7 +58,7 @@ function scene_object_filter(object3D) {
58
58
  /**
59
59
  * @type {THREE.Material|null|undefined}
60
60
  */
61
- const material = (object3D.customDepthMaterial !== null ? object3D.customDepthMaterial : object3D.material);
61
+ const material = (object3D.customDepthMaterial ? object3D.customDepthMaterial : object3D.material);
62
62
 
63
63
  if (material && material.visible === false) {
64
64
  //material's main
@@ -1,12 +1,12 @@
1
1
  import { ShadedGeometry } from "./ShadedGeometry.js";
2
2
  import { Transform } from "../../../ecs/transform/Transform.js";
3
3
  import { System } from "../../../ecs/System.js";
4
- import { intersectRay } from "../../../../core/bvh2/aabb3/AABB3Math.js";
5
4
  import { GeometrySpatialQueryAccelerator } from "../../geometry/buffered/query/GeometrySpatialQueryAccelerator.js";
6
5
  import { SurfacePoint3 } from "../../../../core/geom/3d/SurfacePoint3.js";
7
6
  import { v3_distance_sqr } from "../../../../core/geom/v3_distance_sqr.js";
8
7
  import { mat4 } from "gl-matrix";
9
8
  import { returnTrue } from "../../../../core/function/Functions.js";
9
+ import { aabb3_intersects_ray } from "../../../../core/bvh2/aabb3/aabb3_intersects_ray.js";
10
10
 
11
11
  /**
12
12
  *
@@ -142,7 +142,7 @@ export class ShadedGeometrySystem extends System {
142
142
  const node = traversal_stack[traversal_cursor];
143
143
 
144
144
  // test node against the ray
145
- const intersects = intersectRay(
145
+ const intersects = aabb3_intersects_ray(
146
146
  node.x0, node.y0, node.z0,
147
147
  node.x1, node.y1, node.z1,
148
148
  origin_x, origin_y, origin_z,
@@ -1,9 +1,18 @@
1
1
  import { EngineHarness } from "../../../../EngineHarness.js";
2
- import { ShadedGeometrySystem } from "../ShadedGeometrySystem.d.ts";
3
- import EntityBuilder from "../../../../ecs/EntityBuilder.d.ts";
4
- import { Transform } from "../../../../ecs/transform/Transform.d.ts";
5
- import { ShadedGeometry } from "../ShadedGeometry.d.ts";
2
+ import { ShadedGeometrySystem } from "../ShadedGeometrySystem.js";
3
+ import EntityBuilder from "../../../../ecs/EntityBuilder.js";
4
+ import { Transform } from "../../../../ecs/transform/Transform.js";
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
 
@@ -22,10 +31,71 @@ async function main(engine) {
22
31
 
23
32
  const ecd = em.dataset;
24
33
 
34
+ const material = new MeshBasicMaterial({
35
+ color: 0xFFFFFF
36
+ });
37
+
38
+ // material.visible = false;
39
+
40
+ window.material = material;
41
+
42
+ const geometry = new BoxBufferGeometry();
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
+ }
87
+
25
88
  new EntityBuilder()
26
- .add(new Transform())
27
- .add(ShadedGeometry.from(new BoxBufferGeometry(), new MeshBasicMaterial({
28
- color: 0xFFFFFF
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',
98
+ }
29
99
  })))
30
100
  .build(ecd);
31
101
  }
@@ -1,9 +1,9 @@
1
1
  import { SurfacePoint3 } from "../../../../../core/geom/3d/SurfacePoint3.js";
2
2
  import { NodeType } from "../../../../../core/bvh2/binary/NodeType.js";
3
- import { intersectRay } from "../../../../../core/bvh2/aabb3/AABB3Math.js";
4
3
  import Vector3 from "../../../../../core/geom/Vector3.js";
5
4
  import { computeTriangleRayIntersection } from "../../../../../core/geom/3d/triangle/computeTriangleRayIntersection.js";
6
5
  import { GeometrySpatialAcceleratorVisitor } from "./GeometryVisitor.js";
6
+ import { aabb3_intersects_ray } from "../../../../../core/bvh2/aabb3/aabb3_intersects_ray.js";
7
7
 
8
8
  export class RaycastNearestHitComputingVisitor extends GeometrySpatialAcceleratorVisitor {
9
9
  constructor() {
@@ -158,7 +158,7 @@ export class RaycastNearestHitComputingVisitor extends GeometrySpatialAccelerato
158
158
  const y1 = data[address + 4];
159
159
  const z1 = data[address + 5];
160
160
 
161
- return intersectRay(
161
+ return aabb3_intersects_ray(
162
162
  x0, y0, z0,
163
163
  x1, y1, z1,
164
164
 
@@ -15,6 +15,7 @@ import { compute_buffer_geometry_byte_size } from "../../geometry/buffered/compu
15
15
  import { deinterleaveBufferGeometry } from "../../geometry/buffered/deinterleaveBufferGeometry.js";
16
16
  import { AABB3 } from "../../../../core/bvh2/aabb3/AABB3.js";
17
17
  import { aabb3_from_v3_array } from "../../../../core/bvh2/aabb3/aabb3_from_v3_array.js";
18
+ import { update_topo_face_normals } from "../../../../core/geom/3d/topology/update_topo_face_normals.js";
18
19
 
19
20
  /**
20
21
  * Returns current time in milliseconds
@@ -142,6 +143,9 @@ export async function buildMicronGeometryFromBufferGeometry(input) {
142
143
 
143
144
  expandConnectivityByLocality(topoMesh, geometry_aabb);
144
145
 
146
+ // ensure faces have normals for mesh simplification
147
+ update_topo_face_normals(Array.from(topoMesh.getFaces()), topoMesh.getFaces().size);
148
+
145
149
  /**
146
150
  * Used to generate neighbourhood assignment
147
151
  * @type {Map<number, PatchRepresentation>}
@@ -399,7 +399,6 @@ async function many_to_many_merge(
399
399
  collapse_edges(
400
400
  num_desired_faces_to_remove,
401
401
  open_set,
402
- [],
403
402
  merged_mesh,
404
403
  edge_to_collapse_map,
405
404
  vertex_quadratics,
@@ -462,6 +461,7 @@ async function many_to_many_merge(
462
461
  // );
463
462
 
464
463
  const group_per_pixel_error = group_inverse_polycount;
464
+ // const group_per_pixel_error = Math.sqrt(largest_squared_error);
465
465
 
466
466
  // split topology into desired number of pieces
467
467
  const pieces = recursive_split_mesh_partition(merged_mesh, actual_up_count, MICRON_PATCH_SIZE_MAX);
@@ -76,6 +76,8 @@ 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
+
79
81
  return micron_geometry;
80
82
  }
81
83
 
@@ -1,4 +1,5 @@
1
1
  import { squirrel3 } from "../../../../core/math/hash/squirrel3.js";
2
+ import { isArrayEqualStrict } from "../../../../core/collection/array/isArrayEqualStrict.js";
2
3
 
3
4
  export class MicronGeometryPatchOccurrence {
4
5
  constructor() {
@@ -21,7 +22,7 @@ export class MicronGeometryPatchOccurrence {
21
22
  this.patch = null;
22
23
  /**
23
24
  *
24
- * @type {THREE.Matrix4|null}
25
+ * @type {number[]|Float32Array|null}
25
26
  */
26
27
  this.transform = null;
27
28
  }
@@ -41,7 +42,7 @@ export class MicronGeometryPatchOccurrence {
41
42
  return this.geometry_id === other.geometry_id
42
43
  && this.instance_id === other.instance_id
43
44
  && this.patch.id === other.patch.id
44
- && this.transform.equals(other.transform)
45
+ && isArrayEqualStrict(this.transform, other.transform)
45
46
  ;
46
47
  }
47
48
 
@@ -0,0 +1,176 @@
1
+ import { AssetTransformer } from "../../../asset/AssetTransformer.js";
2
+ import { MicronGeometryBinarySerializationAdapter } from "../format/serialization/MicronGeometryBinarySerializationAdapter.js";
3
+ import { MICRON_URI_FIELD } from "../MICRON_URI_FIELD.js";
4
+ import { computePathDirectory } from "../../../../core/FilePath.js";
5
+ import { BinaryBuffer } from "../../../../core/binary/BinaryBuffer.js";
6
+ import { MicronGeometry } from "../format/MicronGeometry.js";
7
+ import { MICRON_GEOMETRY_FIELD } from "../MICRON_GEOMETRY_FIELD.js";
8
+ import { async_traverse_three_object } from "../../../asset/loaders/async_traverse_three_object.js";
9
+ import { convert_three_object_to_micron } from "../convert_three_object_to_micron.js";
10
+ import { compute_geometry_polycount } from "../../compute_geometry_polycount.js";
11
+ import { traverseThreeObject } from "../../ecs/highlight/renderer/traverseThreeObject.js";
12
+ import { max2 } from "../../../../core/math/max2.js";
13
+
14
+ export const ASSET_TYPE_ARRAY_BUFFER = "arraybuffer";
15
+
16
+ const DEFAULT_THRESHOLD_POLYCOUNT = 1024;
17
+
18
+ /**
19
+ *
20
+ * @param {THREE.Object3D} object
21
+ * @return {number}
22
+ */
23
+ function max_polycount(object) {
24
+ let r = 0;
25
+
26
+ traverseThreeObject(object, (m) => {
27
+ if (m.isMesh) {
28
+ const geo = m.geometry;
29
+ if (geo !== null) {
30
+ r = max2(r, compute_geometry_polycount(geo))
31
+ }
32
+ }
33
+ });
34
+
35
+ return r;
36
+ }
37
+
38
+ export class GLTFAssetTransformer extends AssetTransformer {
39
+ /**
40
+ *
41
+ * @param {AbstractAsyncMap<THREE.BufferGeometry, MicronGeometry>} cache
42
+ */
43
+ constructor(cache) {
44
+ super();
45
+
46
+ /**
47
+ *
48
+ * @type {AbstractAsyncMap<THREE.BufferGeometry, MicronGeometry>}
49
+ * @private
50
+ */
51
+ this.__cache = cache;
52
+
53
+ /**
54
+ *
55
+ * @type {AssetManager|null}
56
+ * @private
57
+ */
58
+ this.__am = null;
59
+
60
+ /**
61
+ * Minimum number of polygons required for micron to be used
62
+ * @type {number}
63
+ * @private
64
+ */
65
+ this.__threshold_polycount = DEFAULT_THRESHOLD_POLYCOUNT;
66
+
67
+ /**
68
+ *
69
+ * @type {MicronGeometryBinarySerializationAdapter}
70
+ * @private
71
+ */
72
+ this.__serde = new MicronGeometryBinarySerializationAdapter();
73
+ }
74
+
75
+ /**
76
+ *
77
+ * @param {AssetManager|null} am
78
+ */
79
+ set assetManager(am) {
80
+ this.__am = am;
81
+ }
82
+
83
+
84
+ /**
85
+ * @param {THREE.Object3D} object
86
+ * @param {{asset:AssetDescription}} ctx
87
+ * @return {Promise<void>}
88
+ * @private
89
+ */
90
+ async __visitObjectToLoadMicron(object, ctx) {
91
+ if (!object.isMesh) {
92
+ return;
93
+ }
94
+
95
+ /**
96
+ * @type {THREE.BufferGeometry}
97
+ */
98
+ const geometry = object.geometry;
99
+
100
+ const micron_uri = geometry.userData[MICRON_URI_FIELD];
101
+
102
+ if (typeof micron_uri !== "string") {
103
+ return;
104
+ }
105
+
106
+
107
+ /**
108
+ * @type {AssetDescription}
109
+ */
110
+ const ad = ctx.asset;
111
+
112
+ const base = computePathDirectory(ad.path);
113
+
114
+ let micron_data;
115
+
116
+ const micron_path = `${base}/${micron_uri}`;
117
+
118
+ try {
119
+ micron_data = await this.__am.promise(micron_path, ASSET_TYPE_ARRAY_BUFFER);
120
+ } catch (e) {
121
+ console.error(`Failed to load micron geometry '${micron_path}' referenced in GLTF (will skip): ${e}`);
122
+ return;
123
+ }
124
+
125
+ // deserialize micron data
126
+ const buffer = BinaryBuffer.fromArrayBuffer(micron_data.create());
127
+ const micron_geometry = new MicronGeometry();
128
+
129
+ this.__serde.deserialize(buffer, micron_geometry);
130
+
131
+ // set proxy for raycasting
132
+ micron_geometry.proxy = geometry;
133
+
134
+ geometry[MICRON_GEOMETRY_FIELD] = micron_geometry;
135
+ }
136
+
137
+
138
+ /**
139
+ *
140
+ * @param {Asset} source
141
+ * @param {AssetDescription} asset_description
142
+ * @return {Promise<Asset>}
143
+ */
144
+ async transform(source, asset_description) {
145
+ const animationClips = source.animations;
146
+
147
+ if (animationClips !== undefined && animationClips.length > 0) {
148
+ // animations might cause trouble
149
+ console.warn(`model '${asset_description.path}' contains animations, these animations might not works as intended with micron.`);
150
+ }
151
+
152
+ /**
153
+ * @type {THREE.Object3D}
154
+ */
155
+ const root = source.create();
156
+
157
+ const gltf_max_polycount = max_polycount(root);
158
+
159
+ if (gltf_max_polycount < this.__threshold_polycount) {
160
+ // no change, geometries are too small
161
+ return source;
162
+ }
163
+
164
+ // attempt to load existing micron geometries
165
+ await async_traverse_three_object(root, this.__visitObjectToLoadMicron, this, {
166
+ asset: asset_description
167
+ });
168
+
169
+ const micron_root = await convert_three_object_to_micron(root.clone(), this.__cache);
170
+ micron_root.boundingSphere = root.boundingSphere;
171
+
172
+ source.override_mesh = micron_root;
173
+
174
+ return source;
175
+ }
176
+ }