@woosh/meep-engine 2.43.20 → 2.43.22
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.
- package/core/collection/HashMap.d.ts +2 -2
- package/core/collection/HashMap.js +22 -2
- package/core/geom/3d/morton/mortonEncode_magicbits.js +18 -0
- package/core/geom/3d/topology/struct/BinaryElementPool.js +292 -0
- package/core/geom/3d/topology/struct/BinaryElementPool.spec.js +36 -0
- package/core/geom/3d/topology/struct/BinaryTopology.js +454 -66
- package/core/geom/3d/topology/struct/BinaryTopology.spec.js +16 -0
- package/core/geom/3d/topology/struct/TopoEdge.js +4 -0
- package/core/geom/3d/topology/struct/TopoMesh.js +25 -0
- package/core/geom/3d/topology/struct/TopoTriangle.js +4 -0
- package/core/geom/3d/topology/struct/TopoVertex.js +8 -0
- package/core/geom/3d/topology/struct/bt_index_geometry_to_topology.js +329 -0
- package/core/geom/3d/topology/struct/bt_index_geometry_to_topology.spec.js +26 -0
- package/core/geom/3d/topology/struct/prototypeBinaryTopology.js +55 -0
- package/engine/graphics/ecs/mesh-v2/aggregate/SGMeshHighlightSystem.js +12 -3
- package/engine/graphics/micron/format/MicronGeometryPatch.d.ts +1 -1
- package/engine/graphics/micron/format/MicronGeometryPatch.js +2 -1
- package/engine/graphics/micron/plugin/GLTFAssetTransformer.js +89 -64
- package/engine/graphics/sh3/path_tracer/PathTracedMesh.js +4 -0
- package/engine/graphics/sh3/path_tracer/PathTracer.js +90 -36
- package/engine/graphics/sh3/path_tracer/getBiasedNormalSample.js +1 -1
- package/engine/graphics/sh3/path_tracer/prototypePathTracer.js +44 -10
- package/engine/graphics/sh3/path_tracer/ray_hit_apply_transform.js +28 -13
- package/engine/save/storage/IndexedDBStorage.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import { HashMap } from "../../../../collection/HashMap.js";
|
|
2
|
+
import { split_by_2 } from "../../morton/mortonEncode_magicbits.js";
|
|
3
|
+
import { NULL_POINTER } from "./BinaryTopology.js";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Populates supplied topology with data from supplied indexed geometry
|
|
8
|
+
* @see https://github.com/blender/blender/blob/9cb061f4f0119e647173e7d354e1457e97632333/source/blender/blenkernel/intern/mesh_calc_edges.cc
|
|
9
|
+
* @see https://github.com/blender/blender/blob/9cb061f4f0119e647173e7d354e1457e97632333/source/blender/io/stl/importer/stl_import_mesh.cc#L63
|
|
10
|
+
* @param {BinaryTopology} out
|
|
11
|
+
* @param {number[]} indices
|
|
12
|
+
* @param {number[]} vertex_positions
|
|
13
|
+
* @param {number[]} [vertex_normals]
|
|
14
|
+
*/
|
|
15
|
+
export function bt_index_geometry_to_topology(
|
|
16
|
+
out,
|
|
17
|
+
indices,
|
|
18
|
+
vertex_positions,
|
|
19
|
+
vertex_normals
|
|
20
|
+
) {
|
|
21
|
+
|
|
22
|
+
// remove any existing data
|
|
23
|
+
out.clear();
|
|
24
|
+
|
|
25
|
+
/*
|
|
26
|
+
NOTES:
|
|
27
|
+
- we use {@link BinaryElementPool#allocate_continuous} to avoid having to allocate additional mapping structure
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
// ingest all vertices
|
|
31
|
+
const vertex_count = vertex_positions.length / 3;
|
|
32
|
+
|
|
33
|
+
const vertex_allocation_offset = out.vertices.allocate_continuous(vertex_count);
|
|
34
|
+
|
|
35
|
+
for (let i = 0; i < vertex_count; i++) {
|
|
36
|
+
const i3 = i * 3;
|
|
37
|
+
|
|
38
|
+
const vertex_id = i + vertex_allocation_offset;
|
|
39
|
+
|
|
40
|
+
out.vertex_write_coordinate(vertex_id, vertex_positions, i3);
|
|
41
|
+
|
|
42
|
+
if (vertex_normals !== undefined) {
|
|
43
|
+
out.vertex_write_normal(vertex_id, vertex_normals, i3);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// initialize edge to NULL
|
|
47
|
+
out.vertex_write_edge(vertex_id, NULL_POINTER);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const face_count = indices.length / 3;
|
|
51
|
+
|
|
52
|
+
// reserve some memory to avoid extra allocations
|
|
53
|
+
out.loops.ensure_capacity(face_count * 3);
|
|
54
|
+
out.edges.ensure_capacity(face_count * 1.6);
|
|
55
|
+
|
|
56
|
+
// create faces
|
|
57
|
+
const face_allocation_offset = out.faces.allocate_continuous(face_count);
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
*
|
|
61
|
+
* @type {HashMap<OrderedEdge, number>}
|
|
62
|
+
*/
|
|
63
|
+
const edge_hash_map = new HashMap({
|
|
64
|
+
capacity: Math.ceil(1 + 2.1 * face_count)
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
for (let i = 0; i < face_count; i++) {
|
|
68
|
+
const i3 = i * 3;
|
|
69
|
+
|
|
70
|
+
const a = indices[i3];
|
|
71
|
+
const b = indices[i3 + 1];
|
|
72
|
+
const c = indices[i3 + 2];
|
|
73
|
+
|
|
74
|
+
const vertex_a = a + vertex_allocation_offset;
|
|
75
|
+
const vertex_b = b + vertex_allocation_offset;
|
|
76
|
+
const vertex_c = c + vertex_allocation_offset;
|
|
77
|
+
|
|
78
|
+
const face_id = i + face_allocation_offset;
|
|
79
|
+
|
|
80
|
+
// create edges
|
|
81
|
+
const edge_ab = get_or_create_edge(vertex_a, vertex_b, edge_hash_map, out);
|
|
82
|
+
const edge_bc = get_or_create_edge(vertex_b, vertex_c, edge_hash_map, out);
|
|
83
|
+
const edge_ca = get_or_create_edge(vertex_c, vertex_a, edge_hash_map, out);
|
|
84
|
+
|
|
85
|
+
// allocate loops
|
|
86
|
+
const loop_a = out.loop_create();
|
|
87
|
+
const loop_b = out.loop_create();
|
|
88
|
+
const loop_c = out.loop_create();
|
|
89
|
+
|
|
90
|
+
// write loops
|
|
91
|
+
out.loop_write_vertex(loop_a, vertex_a);
|
|
92
|
+
out.loop_write_vertex(loop_b, vertex_b);
|
|
93
|
+
out.loop_write_vertex(loop_c, vertex_c);
|
|
94
|
+
|
|
95
|
+
// link loops to edges
|
|
96
|
+
link_loop_to_edge(loop_a, edge_ab, out);
|
|
97
|
+
link_loop_to_edge(loop_b, edge_bc, out);
|
|
98
|
+
link_loop_to_edge(loop_c, edge_ca, out);
|
|
99
|
+
|
|
100
|
+
out.loop_write_face(loop_a, face_id);
|
|
101
|
+
out.loop_write_face(loop_b, face_id);
|
|
102
|
+
out.loop_write_face(loop_c, face_id);
|
|
103
|
+
|
|
104
|
+
/*
|
|
105
|
+
NOTE: Vertices (#BMLoop.v & #BMLoop.next.v) always contain vertices from (#BMEdge.v1 & #BMEdge.v2).
|
|
106
|
+
*/
|
|
107
|
+
// link up loops around the face
|
|
108
|
+
out.loop_write_next(loop_a, loop_b);
|
|
109
|
+
out.loop_write_prev(loop_a, loop_c);
|
|
110
|
+
|
|
111
|
+
out.loop_write_next(loop_b, loop_c);
|
|
112
|
+
out.loop_write_prev(loop_b, loop_a);
|
|
113
|
+
|
|
114
|
+
out.loop_write_next(loop_c, loop_a);
|
|
115
|
+
out.loop_write_prev(loop_c, loop_b);
|
|
116
|
+
|
|
117
|
+
// update face
|
|
118
|
+
out.face_write_loop(face_id, loop_a);
|
|
119
|
+
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* follow the pointer list to the end along radial list
|
|
125
|
+
* @param {number} start_loop
|
|
126
|
+
* @param {BinaryTopology} mesh
|
|
127
|
+
* @returns {number}
|
|
128
|
+
*/
|
|
129
|
+
function loop_radial_get_last(start_loop, mesh) {
|
|
130
|
+
let prev_loop = start_loop;
|
|
131
|
+
let next_loop;
|
|
132
|
+
|
|
133
|
+
while ((next_loop = mesh.loop_read_radial_next(prev_loop)) !== NULL_POINTER) {
|
|
134
|
+
prev_loop = next_loop;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return prev_loop;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
*
|
|
142
|
+
* @param {number} loop_id
|
|
143
|
+
* @param {number} edge_id
|
|
144
|
+
* @param {BinaryTopology} mesh
|
|
145
|
+
*/
|
|
146
|
+
function link_loop_to_edge(loop_id, edge_id, mesh) {
|
|
147
|
+
mesh.loop_write_edge(loop_id, edge_id);
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* First loop attached to the edge
|
|
151
|
+
* @type {number}
|
|
152
|
+
*/
|
|
153
|
+
const edge_loop_start = mesh.edge_read_loop(edge_id);
|
|
154
|
+
|
|
155
|
+
if (edge_loop_start === NULL_POINTER) {
|
|
156
|
+
// no loops connected yet
|
|
157
|
+
mesh.edge_write_loop(edge_id, loop_id);
|
|
158
|
+
} else {
|
|
159
|
+
// connect loop to the end of the list
|
|
160
|
+
const last_loop_in_list = loop_radial_get_last(edge_loop_start, mesh);
|
|
161
|
+
|
|
162
|
+
mesh.loop_write_radial_next(last_loop_in_list, loop_id);
|
|
163
|
+
mesh.loop_write_radial_prev(loop_id, last_loop_in_list);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* @see https://github.com/blender/blender/blob/9cb061f4f0119e647173e7d354e1457e97632333/source/blender/blenkernel/intern/mesh_calc_edges.cc#L209
|
|
170
|
+
* @param {BinaryTopology} mesh
|
|
171
|
+
*/
|
|
172
|
+
function bt_mesh_calc_edges(mesh) {
|
|
173
|
+
/**
|
|
174
|
+
*
|
|
175
|
+
* @type {HashMap<OrderedEdge, unknown>}
|
|
176
|
+
*/
|
|
177
|
+
const map = new HashMap();
|
|
178
|
+
|
|
179
|
+
add_polygon_edges_to_map(mesh, map);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
class OrderedEdge {
|
|
183
|
+
/**
|
|
184
|
+
*
|
|
185
|
+
* @param {number} v1
|
|
186
|
+
* @param {number} v2
|
|
187
|
+
*/
|
|
188
|
+
constructor(v1, v2) {
|
|
189
|
+
if (v1 < v2) {
|
|
190
|
+
this.v_low = v1;
|
|
191
|
+
this.v_high = v2;
|
|
192
|
+
} else {
|
|
193
|
+
this.v_low = v2;
|
|
194
|
+
this.v_high = v1;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
*
|
|
200
|
+
* @param {number} v1
|
|
201
|
+
* @param {number} v2
|
|
202
|
+
*/
|
|
203
|
+
set(v1, v2) {
|
|
204
|
+
if (v1 < v2) {
|
|
205
|
+
this.v_low = v1;
|
|
206
|
+
this.v_high = v2;
|
|
207
|
+
} else {
|
|
208
|
+
this.v_low = v2;
|
|
209
|
+
this.v_high = v1;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
*
|
|
215
|
+
* @param {OrderedEdge} other
|
|
216
|
+
*/
|
|
217
|
+
copy(other) {
|
|
218
|
+
this.v_low = other.v_low;
|
|
219
|
+
this.v_high = other.v_high;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
clone() {
|
|
223
|
+
return new OrderedEdge(this.v_low, this.v_high);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
*
|
|
228
|
+
* @return {number}
|
|
229
|
+
*/
|
|
230
|
+
hash() {
|
|
231
|
+
return split_by_2(this.v_low) | (split_by_2(this.v_high) << 1);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
*
|
|
236
|
+
* @param {OrderedEdge} other
|
|
237
|
+
* @returns {boolean}
|
|
238
|
+
*/
|
|
239
|
+
equals(other) {
|
|
240
|
+
return this.v_low === other.v_low
|
|
241
|
+
&& this.v_high === other.v_high
|
|
242
|
+
;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* @see https://github.com/blender/blender/blob/9cb061f4f0119e647173e7d354e1457e97632333/source/blender/blenkernel/intern/mesh_calc_edges.cc#L96
|
|
248
|
+
* @param {BinaryTopology} mesh
|
|
249
|
+
* @param {HashMap<OrderedEdge,*>} edge_map
|
|
250
|
+
*/
|
|
251
|
+
function add_polygon_edges_to_map(mesh, edge_map) {
|
|
252
|
+
|
|
253
|
+
const faces = mesh.faces;
|
|
254
|
+
const face_count = faces.size;
|
|
255
|
+
|
|
256
|
+
for (let i = 0; i < face_count; i++) {
|
|
257
|
+
if (!faces.is_allocated(i)) {
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const first_loop = mesh.face_read_loop(i);
|
|
262
|
+
let prev_loop = first_loop + j;
|
|
263
|
+
|
|
264
|
+
for (let j = 0; j < 3; j++) {
|
|
265
|
+
const loop = first_loop + j;
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
const prev_v = mesh.loop_read_vertex(prev_loop);
|
|
269
|
+
const next_v = mesh.loop_read_vertex(loop);
|
|
270
|
+
|
|
271
|
+
const edge = new OrderedEdge(prev_v, next_v);
|
|
272
|
+
|
|
273
|
+
edge_map.getOrSet(edge, null);
|
|
274
|
+
|
|
275
|
+
prev_loop = loop;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
*
|
|
283
|
+
* @param {number} v0
|
|
284
|
+
* @param {number} v1
|
|
285
|
+
* @param {HashMap<OrderedEdge,number>} map
|
|
286
|
+
* @param {BinaryTopology} mesh
|
|
287
|
+
*/
|
|
288
|
+
function get_or_create_edge(v0, v1, map, mesh) {
|
|
289
|
+
const scratch_ordered_edge = new OrderedEdge(v0, v1);
|
|
290
|
+
|
|
291
|
+
const existing = map.get(scratch_ordered_edge);
|
|
292
|
+
|
|
293
|
+
if (existing !== undefined) {
|
|
294
|
+
return existing;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// doesn't exist - create
|
|
298
|
+
const edge_id = mesh.edges.allocate();
|
|
299
|
+
|
|
300
|
+
mesh.edge_write_vertex1(edge_id, v0);
|
|
301
|
+
mesh.edge_write_vertex2(edge_id, v1);
|
|
302
|
+
|
|
303
|
+
// initialize rest of the edge
|
|
304
|
+
mesh.edge_write_loop(edge_id, NULL_POINTER);
|
|
305
|
+
|
|
306
|
+
// TODO process disk_link pointers for the edge
|
|
307
|
+
|
|
308
|
+
map.set(scratch_ordered_edge, edge_id);
|
|
309
|
+
|
|
310
|
+
return edge_id;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Ensure an edge between two vertices
|
|
316
|
+
* NOTE: works without having to use a separate hash map, resulting in faster execution and smaller RAM requirement
|
|
317
|
+
* @param {number} v0
|
|
318
|
+
* @param {number} v1
|
|
319
|
+
* @param {BinaryTopology} mesh
|
|
320
|
+
*/
|
|
321
|
+
function get_or_create_edge_2(v0, v1, mesh) {
|
|
322
|
+
const first_edge = mesh.vertex_read_edge(v0);
|
|
323
|
+
|
|
324
|
+
// iterate over all edges around the vertex
|
|
325
|
+
|
|
326
|
+
// if match is found - return the match, else create a new edge and assign
|
|
327
|
+
|
|
328
|
+
// TODO implement
|
|
329
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { bt_index_geometry_to_topology } from "./bt_index_geometry_to_topology.js";
|
|
2
|
+
import { BinaryTopology } from "./BinaryTopology.js";
|
|
3
|
+
|
|
4
|
+
test('Empty geometry work as expected', () => {
|
|
5
|
+
const mesh = new BinaryTopology();
|
|
6
|
+
bt_index_geometry_to_topology(mesh, [], []);
|
|
7
|
+
|
|
8
|
+
expect(mesh.faces.size).toBe(0);
|
|
9
|
+
expect(mesh.vertices.size).toBe(0);
|
|
10
|
+
expect(mesh.edges.size).toBe(0);
|
|
11
|
+
expect(mesh.loops.size).toBe(0);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test('Single triangle', () => {
|
|
15
|
+
const mesh = new BinaryTopology();
|
|
16
|
+
bt_index_geometry_to_topology(mesh, [0, 1, 2], [
|
|
17
|
+
1, 3, 7,
|
|
18
|
+
11, 13, 17,
|
|
19
|
+
23, 27, -1
|
|
20
|
+
]);
|
|
21
|
+
|
|
22
|
+
expect(mesh.faces.size).toBe(1);
|
|
23
|
+
expect(mesh.loops.size).toBe(3);
|
|
24
|
+
expect(mesh.edges.size).toBe(3);
|
|
25
|
+
expect(mesh.vertices.size).toBe(3);
|
|
26
|
+
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { PLYLoader } from "three/examples/jsm/loaders/PLYLoader.js";
|
|
2
|
+
import { noop } from "../../../../function/Functions.js";
|
|
3
|
+
import { bt_index_geometry_to_topology } from "./bt_index_geometry_to_topology.js";
|
|
4
|
+
import { BinaryTopology } from "./BinaryTopology.js";
|
|
5
|
+
import {
|
|
6
|
+
compute_buffer_geometry_byte_size
|
|
7
|
+
} from "../../../../../engine/graphics/geometry/buffered/compute_buffer_geometry_byte_size.js";
|
|
8
|
+
import { prettyPrint } from "../../../../NumberFormat.js";
|
|
9
|
+
import { TopoMesh } from "./TopoMesh.js";
|
|
10
|
+
|
|
11
|
+
function promise_ply(url) {
|
|
12
|
+
|
|
13
|
+
return new Promise((resolve, reject) => {
|
|
14
|
+
new PLYLoader().load(url, resolve, noop, reject);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
async function main() {
|
|
20
|
+
|
|
21
|
+
// const url = "data/models/stanford/Lucy100k.ply";
|
|
22
|
+
const url = "data/models/stanford/dragon_recon/dragon_vrip.ply";
|
|
23
|
+
const lucy_geom = await promise_ply(url);
|
|
24
|
+
|
|
25
|
+
const mesh = new BinaryTopology();
|
|
26
|
+
|
|
27
|
+
const positions_array = lucy_geom.getAttribute('position').array;
|
|
28
|
+
const index_array = lucy_geom.getIndex().array;
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
const topoMesh = new TopoMesh();
|
|
32
|
+
|
|
33
|
+
console.time('topo build - obj');
|
|
34
|
+
topoMesh.build(positions_array, index_array);
|
|
35
|
+
console.timeEnd('topo build - obj');
|
|
36
|
+
|
|
37
|
+
// console.time('topo build - bin');
|
|
38
|
+
console.profile('topo build - bin');
|
|
39
|
+
bt_index_geometry_to_topology(mesh, index_array, positions_array);
|
|
40
|
+
console.profileEnd('topo build - bin');
|
|
41
|
+
// console.timeEnd('topo build - bin');
|
|
42
|
+
|
|
43
|
+
mesh.trim();
|
|
44
|
+
|
|
45
|
+
console.log(mesh, lucy_geom);
|
|
46
|
+
|
|
47
|
+
console.log(`source mesh size: ${prettyPrint(compute_buffer_geometry_byte_size(lucy_geom))} bytes`);
|
|
48
|
+
console.log(`binary topology size: ${prettyPrint(mesh.byteSize)} bytes`);
|
|
49
|
+
console.log(`object topology size: ${prettyPrint(topoMesh.byteSize)} bytes`);
|
|
50
|
+
|
|
51
|
+
window.topo_obj = topoMesh;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
main();
|
|
55
|
+
|
|
@@ -16,12 +16,21 @@ export class SGMeshHighlightSystem extends System {
|
|
|
16
16
|
* @param {number} entity
|
|
17
17
|
* @private
|
|
18
18
|
*/
|
|
19
|
-
__apply_highlight(
|
|
19
|
+
__apply_highlight(event, entity) {
|
|
20
20
|
const ecd = this.entityManager.dataset;
|
|
21
21
|
|
|
22
22
|
const sg_mesh = ecd.getComponent(entity, SGMesh);
|
|
23
|
+
|
|
24
|
+
if (sg_mesh === undefined) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
23
28
|
const highlight = ecd.getComponent(entity, Highlight);
|
|
24
29
|
|
|
30
|
+
if (highlight === undefined) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
25
34
|
const node = sg_mesh.__node;
|
|
26
35
|
|
|
27
36
|
node.traverse(t => {
|
|
@@ -35,7 +44,7 @@ export class SGMeshHighlightSystem extends System {
|
|
|
35
44
|
* @param {number} entity
|
|
36
45
|
* @private
|
|
37
46
|
*/
|
|
38
|
-
__remove_highlight(
|
|
47
|
+
__remove_highlight(event, entity) {
|
|
39
48
|
|
|
40
49
|
const ecd = this.entityManager.dataset;
|
|
41
50
|
|
|
@@ -56,7 +65,7 @@ export class SGMeshHighlightSystem extends System {
|
|
|
56
65
|
*/
|
|
57
66
|
link(highlight, mesh, entity) {
|
|
58
67
|
if (mesh.__node !== null) {
|
|
59
|
-
this.__apply_highlight(undefined,
|
|
68
|
+
this.__apply_highlight(undefined, entity);
|
|
60
69
|
}
|
|
61
70
|
|
|
62
71
|
const ecd = this.entityManager.dataset;
|
|
@@ -35,7 +35,7 @@ export class MicronGeometryPatch {
|
|
|
35
35
|
this.group_bounding_box = null;
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
-
*
|
|
38
|
+
* TODO get rid of this, use bounding box instead for smaller memory footprint
|
|
39
39
|
* @type {number[]|Float32Array}
|
|
40
40
|
*/
|
|
41
41
|
this.group_bounding_box_corners = null;
|
|
@@ -124,6 +124,7 @@ export class MicronGeometryPatch {
|
|
|
124
124
|
* @returns {number}
|
|
125
125
|
*/
|
|
126
126
|
allocate_metadata(buffer, offset) {
|
|
127
|
+
assert.isNonNegativeInteger(offset, 'offset');
|
|
127
128
|
assert.greaterThanOrEqual(buffer.byteLength, offset + 144, 'buffer underflow');
|
|
128
129
|
|
|
129
130
|
this.bounding_box = new Float32Array(buffer, offset, 6);
|
|
@@ -56,14 +56,13 @@ function ensureProxy(object) {
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
class TransformContext {
|
|
60
60
|
/**
|
|
61
61
|
*
|
|
62
|
-
* @param {
|
|
62
|
+
* @param {AssetManager} assetManager
|
|
63
|
+
* @param {AbstractAsyncMap<THREE.BufferGeometry, MicronGeometry>} cache
|
|
63
64
|
*/
|
|
64
|
-
constructor(cache) {
|
|
65
|
-
super();
|
|
66
|
-
|
|
65
|
+
constructor(assetManager, cache) {
|
|
67
66
|
/**
|
|
68
67
|
*
|
|
69
68
|
* @type {AbstractAsyncMap<THREE.BufferGeometry, MicronGeometry>|undefined}
|
|
@@ -71,20 +70,6 @@ export class GLTFAssetTransformer extends AssetTransformer {
|
|
|
71
70
|
*/
|
|
72
71
|
this.__cache = cache;
|
|
73
72
|
|
|
74
|
-
/**
|
|
75
|
-
*
|
|
76
|
-
* @type {AssetManager|null}
|
|
77
|
-
* @private
|
|
78
|
-
*/
|
|
79
|
-
this.__am = null;
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Minimum number of polygons required for micron to be used
|
|
83
|
-
* @type {number}
|
|
84
|
-
* @private
|
|
85
|
-
*/
|
|
86
|
-
this.__threshold_polycount = DEFAULT_THRESHOLD_POLYCOUNT;
|
|
87
|
-
|
|
88
73
|
/**
|
|
89
74
|
*
|
|
90
75
|
* @type {MicronGeometry[]}
|
|
@@ -92,31 +77,54 @@ export class GLTFAssetTransformer extends AssetTransformer {
|
|
|
92
77
|
*/
|
|
93
78
|
this.__active_mesh_micron_cache = [];
|
|
94
79
|
|
|
95
|
-
|
|
96
|
-
* @deprecated
|
|
97
|
-
* Whether override mesh will be created for the asset, this is generally outdated
|
|
98
|
-
* @type {boolean}
|
|
99
|
-
* @private
|
|
100
|
-
*/
|
|
101
|
-
this.__settings_build_override_mesh = false;
|
|
80
|
+
this.__am = assetManager;
|
|
102
81
|
}
|
|
103
82
|
|
|
104
83
|
/**
|
|
105
84
|
*
|
|
106
|
-
* @param {
|
|
85
|
+
* @param {{userData:{}}} gltf
|
|
86
|
+
* @param {AssetDescription} ad
|
|
107
87
|
*/
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
88
|
+
async load_mesh_micron_data(gltf, ad) {
|
|
89
|
+
// clear active cache
|
|
90
|
+
this.__active_mesh_micron_cache = [];
|
|
111
91
|
|
|
92
|
+
const micron_metadata = gltf.userData.micron;
|
|
93
|
+
|
|
94
|
+
if (micron_metadata === undefined) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const uri = micron_metadata.geometry_data_uri;
|
|
99
|
+
if (uri === undefined) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const base = computePathDirectory(ad.path);
|
|
104
|
+
|
|
105
|
+
let micron_data;
|
|
106
|
+
|
|
107
|
+
const micron_path = `${base}/${uri}`;
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
micron_data = await this.__am.promise(micron_path, ASSET_TYPE_ARRAY_BUFFER, { skip_queue: true });
|
|
111
|
+
} catch (e) {
|
|
112
|
+
console.error(`Failed to load micron geometry '${micron_path}' referenced in GLTF (will skip): ${e}`);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// deserialize micron data
|
|
117
|
+
const buffer = BinaryBuffer.fromArrayBuffer(micron_data.create());
|
|
118
|
+
|
|
119
|
+
deserialize_geometry_collection(this.__active_mesh_micron_cache, buffer);
|
|
120
|
+
}
|
|
112
121
|
|
|
113
122
|
/**
|
|
114
123
|
* @param {THREE.Object3D} object
|
|
115
124
|
* @param {{asset:AssetDescription}} ctx
|
|
116
125
|
* @return {Promise<void>}
|
|
117
|
-
* @private
|
|
118
126
|
*/
|
|
119
|
-
async
|
|
127
|
+
async visitObjectToLoadMicron(object, ctx) {
|
|
120
128
|
if (!object.isMesh) {
|
|
121
129
|
return;
|
|
122
130
|
}
|
|
@@ -150,46 +158,59 @@ export class GLTFAssetTransformer extends AssetTransformer {
|
|
|
150
158
|
}
|
|
151
159
|
}
|
|
152
160
|
|
|
161
|
+
}
|
|
153
162
|
|
|
163
|
+
export class GLTFAssetTransformer extends AssetTransformer {
|
|
154
164
|
/**
|
|
155
165
|
*
|
|
156
|
-
* @param {
|
|
157
|
-
* @param {AssetDescription} ad
|
|
158
|
-
* @private
|
|
166
|
+
* @param {AbstractAsyncMap<THREE.BufferGeometry, MicronGeometry>} [cache]
|
|
159
167
|
*/
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
this.__active_mesh_micron_cache = [];
|
|
163
|
-
|
|
164
|
-
const micron_metadata = gltf.userData.micron;
|
|
165
|
-
|
|
166
|
-
if (micron_metadata === undefined) {
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const uri = micron_metadata.geometry_data_uri;
|
|
171
|
-
if (uri === undefined) {
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
const base = computePathDirectory(ad.path);
|
|
168
|
+
constructor(cache) {
|
|
169
|
+
super();
|
|
176
170
|
|
|
177
|
-
|
|
171
|
+
/**
|
|
172
|
+
*
|
|
173
|
+
* @type {AbstractAsyncMap<THREE.BufferGeometry, MicronGeometry>|undefined}
|
|
174
|
+
* @private
|
|
175
|
+
*/
|
|
176
|
+
this.__cache = cache;
|
|
178
177
|
|
|
179
|
-
|
|
178
|
+
/**
|
|
179
|
+
*
|
|
180
|
+
* @type {AssetManager|null}
|
|
181
|
+
* @private
|
|
182
|
+
*/
|
|
183
|
+
this.__am = null;
|
|
180
184
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
185
|
+
/**
|
|
186
|
+
* Minimum number of polygons required for micron to be used
|
|
187
|
+
* @type {number}
|
|
188
|
+
* @private
|
|
189
|
+
*/
|
|
190
|
+
this.__threshold_polycount = DEFAULT_THRESHOLD_POLYCOUNT;
|
|
187
191
|
|
|
188
|
-
|
|
189
|
-
|
|
192
|
+
/**
|
|
193
|
+
*
|
|
194
|
+
* @type {MicronGeometry[]}
|
|
195
|
+
* @private
|
|
196
|
+
*/
|
|
197
|
+
this.__active_mesh_micron_cache = [];
|
|
190
198
|
|
|
191
|
-
|
|
199
|
+
/**
|
|
200
|
+
* @deprecated
|
|
201
|
+
* Whether override mesh will be created for the asset, this is generally outdated
|
|
202
|
+
* @type {boolean}
|
|
203
|
+
* @private
|
|
204
|
+
*/
|
|
205
|
+
this.__settings_build_override_mesh = false;
|
|
206
|
+
}
|
|
192
207
|
|
|
208
|
+
/**
|
|
209
|
+
*
|
|
210
|
+
* @param {AssetManager|null} am
|
|
211
|
+
*/
|
|
212
|
+
set assetManager(am) {
|
|
213
|
+
this.__am = am;
|
|
193
214
|
}
|
|
194
215
|
|
|
195
216
|
|
|
@@ -212,10 +233,12 @@ export class GLTFAssetTransformer extends AssetTransformer {
|
|
|
212
233
|
*/
|
|
213
234
|
const root = source.create();
|
|
214
235
|
|
|
215
|
-
|
|
236
|
+
const context = new TransformContext(this.__am, this.__cache);
|
|
237
|
+
|
|
238
|
+
await context.load_mesh_micron_data(source.gltf, asset_description);
|
|
216
239
|
|
|
217
240
|
// attempt to load existing micron geometries
|
|
218
|
-
await async_traverse_three_object(root,
|
|
241
|
+
await async_traverse_three_object(root, context.visitObjectToLoadMicron, context, {
|
|
219
242
|
asset: asset_description
|
|
220
243
|
});
|
|
221
244
|
|
|
@@ -227,6 +250,8 @@ export class GLTFAssetTransformer extends AssetTransformer {
|
|
|
227
250
|
}
|
|
228
251
|
|
|
229
252
|
if (this.__settings_build_override_mesh) {
|
|
253
|
+
console.warn(`Deprecated OVERRIDE_MESH setting is ON, generating override mesh for asset: ${asset_description}`);
|
|
254
|
+
|
|
230
255
|
const micron_root = await convert_three_object_to_micron(root.clone(), this.__cache);
|
|
231
256
|
micron_root.boundingSphere = root.boundingSphere;
|
|
232
257
|
|