@inweb/viewer-three 26.10.6 → 26.11.0
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/README.md +7 -4
- package/dist/{plugins → extensions}/components/AxesHelperComponent.js +23 -1
- package/dist/extensions/components/AxesHelperComponent.js.map +1 -0
- package/dist/extensions/components/AxesHelperComponent.min.js +24 -0
- package/dist/{plugins → extensions}/components/AxesHelperComponent.module.js +24 -2
- package/dist/extensions/components/AxesHelperComponent.module.js.map +1 -0
- package/dist/{plugins → extensions}/components/ExtentsHelperComponent.js +18 -0
- package/dist/extensions/components/ExtentsHelperComponent.js.map +1 -0
- package/dist/{plugins/components/AxesHelperComponent.min.js → extensions/components/ExtentsHelperComponent.min.js} +1 -1
- package/dist/{plugins → extensions}/components/ExtentsHelperComponent.module.js +19 -1
- package/dist/extensions/components/ExtentsHelperComponent.module.js.map +1 -0
- package/dist/extensions/components/GridHelperComponent.js.map +1 -0
- package/dist/extensions/components/GridHelperComponent.module.js.map +1 -0
- package/dist/extensions/components/LightHelperComponent.js.map +1 -0
- package/dist/extensions/components/LightHelperComponent.module.js.map +1 -0
- package/dist/extensions/components/RoomEnvironmentComponent.js.map +1 -0
- package/dist/extensions/components/RoomEnvironmentComponent.module.js.map +1 -0
- package/dist/extensions/components/StatsPanelComponent.js.map +1 -0
- package/dist/extensions/components/StatsPanelComponent.module.js.map +1 -0
- package/dist/{plugins → extensions}/loaders/GLTFCloudLoader.js +2 -3
- package/dist/extensions/loaders/GLTFCloudLoader.js.map +1 -0
- package/dist/{plugins → extensions}/loaders/GLTFCloudLoader.min.js +1 -1
- package/dist/{plugins → extensions}/loaders/GLTFCloudLoader.module.js +2 -3
- package/dist/extensions/loaders/GLTFCloudLoader.module.js.map +1 -0
- package/dist/extensions/loaders/GLTFFileLoader.js +2499 -0
- package/dist/extensions/loaders/GLTFFileLoader.js.map +1 -0
- package/dist/extensions/loaders/GLTFFileLoader.min.js +24 -0
- package/dist/extensions/loaders/GLTFFileLoader.module.js +74 -0
- package/dist/extensions/loaders/GLTFFileLoader.module.js.map +1 -0
- package/dist/{plugins → extensions}/loaders/IFCXLoader.js +5 -7
- package/dist/extensions/loaders/IFCXLoader.js.map +1 -0
- package/dist/{plugins → extensions}/loaders/IFCXLoader.min.js +1 -1
- package/dist/{plugins → extensions}/loaders/IFCXLoader.module.js +5 -7
- package/dist/extensions/loaders/IFCXLoader.module.js.map +1 -0
- package/dist/{plugins → extensions}/loaders/PotreeLoader.js +1 -2
- package/dist/extensions/loaders/PotreeLoader.js.map +1 -0
- package/dist/{plugins → extensions}/loaders/PotreeLoader.min.js +1 -1
- package/dist/{plugins → extensions}/loaders/PotreeLoader.module.js +1 -2
- package/dist/extensions/loaders/PotreeLoader.module.js.map +1 -0
- package/dist/viewer-three.js +1015 -2926
- package/dist/viewer-three.js.map +1 -1
- package/dist/viewer-three.min.js +3 -3
- package/dist/viewer-three.module.js +847 -356
- package/dist/viewer-three.module.js.map +1 -1
- package/{plugins → extensions}/components/AxesHelperComponent.ts +31 -2
- package/{plugins → extensions}/components/ExtentsHelperComponent.ts +25 -0
- package/{plugins → extensions}/loaders/GLTFCloudLoader.ts +2 -3
- package/{src/Viewer → extensions}/loaders/GLTFFileLoader.ts +21 -12
- package/{plugins → extensions}/loaders/IFCX/IFCXCloudLoader.ts +5 -5
- package/{plugins → extensions}/loaders/IFCX/IFCXFileLoader.ts +3 -4
- package/{plugins → extensions}/loaders/Potree/PotreeFileLoader.ts +3 -4
- package/lib/Viewer/Viewer.d.ts +27 -20
- package/lib/Viewer/commands/GetSelected2.d.ts +2 -0
- package/lib/Viewer/commands/SelectModel.d.ts +1 -1
- package/lib/Viewer/commands/SetSelected2.d.ts +2 -0
- package/lib/Viewer/components/SelectionComponent.d.ts +1 -3
- package/lib/Viewer/components/index.d.ts +6 -6
- package/lib/Viewer/draggers/MeasureLineDragger.d.ts +7 -1
- package/lib/Viewer/loaders/DynamicGltfLoader/DynamicModelImpl.d.ts +0 -1
- package/lib/Viewer/loaders/GLTFBinaryExtension.d.ts +5 -0
- package/lib/Viewer/loaders/GLTFCloudDynamicLoader.d.ts +2 -2
- package/lib/Viewer/loaders/{GLTFFileLoader.d.ts → GLTFFileDynamicLoader.d.ts} +7 -1
- package/lib/Viewer/loaders/GLTFLoadingManager.d.ts +4 -3
- package/lib/Viewer/loaders/RangesLoader.d.ts +15 -0
- package/lib/Viewer/loaders/index.d.ts +22 -14
- package/lib/Viewer/measurement/Snapper.d.ts +15 -0
- package/lib/Viewer/measurement/UnitConverter.d.ts +63 -0
- package/lib/Viewer/measurement/UnitFormatter.d.ts +4 -0
- package/lib/Viewer/models/IModelImpl.d.ts +10 -8
- package/lib/Viewer/models/ModelImpl.d.ts +7 -5
- package/package.json +11 -11
- package/src/Viewer/Viewer.ts +120 -88
- package/src/Viewer/commands/ClearSelected.ts +3 -1
- package/src/Viewer/commands/GetModels.ts +1 -1
- package/src/Viewer/commands/GetSelected.ts +2 -2
- package/src/Viewer/commands/GetSelected2.ts +34 -0
- package/src/Viewer/commands/HideSelected.ts +3 -1
- package/src/Viewer/commands/SelectModel.ts +5 -5
- package/src/Viewer/commands/SetSelected.ts +9 -10
- package/src/Viewer/commands/SetSelected2.ts +42 -0
- package/src/Viewer/commands/ZoomToObjects.ts +5 -6
- package/src/Viewer/commands/ZoomToSelected.ts +3 -1
- package/src/Viewer/commands/index.ts +4 -0
- package/src/Viewer/components/CameraComponent.ts +6 -1
- package/src/Viewer/components/ExtentsComponent.ts +4 -1
- package/src/Viewer/components/SelectionComponent.ts +7 -30
- package/src/Viewer/components/index.ts +6 -6
- package/src/Viewer/draggers/MeasureLineDragger.ts +84 -226
- package/src/Viewer/loaders/DynamicGltfLoader/DynamicGltfLoader.js +263 -34
- package/src/Viewer/loaders/DynamicGltfLoader/DynamicModelImpl.ts +20 -10
- package/src/Viewer/loaders/DynamicGltfLoader/GltfStructure.js +4 -1
- package/src/Viewer/loaders/GLTFBinaryExtension.ts +91 -0
- package/src/Viewer/loaders/GLTFCloudDynamicLoader.ts +13 -19
- package/src/Viewer/loaders/GLTFFileDynamicLoader.ts +145 -0
- package/src/Viewer/loaders/GLTFLoadingManager.ts +5 -4
- package/src/Viewer/loaders/RangesLoader.ts +95 -0
- package/src/Viewer/loaders/index.ts +24 -16
- package/src/Viewer/measurement/Snapper.ts +208 -0
- package/src/Viewer/measurement/UnitConverter.ts +47 -0
- package/src/Viewer/measurement/UnitFormatter.ts +95 -0
- package/src/Viewer/models/IModelImpl.ts +15 -8
- package/src/Viewer/models/ModelImpl.ts +48 -17
- package/src/index-umd.ts +1 -1
- package/dist/plugins/components/AxesHelperComponent.js.map +0 -1
- package/dist/plugins/components/AxesHelperComponent.module.js.map +0 -1
- package/dist/plugins/components/ExtentsHelperComponent.js.map +0 -1
- package/dist/plugins/components/ExtentsHelperComponent.min.js +0 -24
- package/dist/plugins/components/ExtentsHelperComponent.module.js.map +0 -1
- package/dist/plugins/components/GridHelperComponent.js.map +0 -1
- package/dist/plugins/components/GridHelperComponent.module.js.map +0 -1
- package/dist/plugins/components/LightHelperComponent.js.map +0 -1
- package/dist/plugins/components/LightHelperComponent.module.js.map +0 -1
- package/dist/plugins/components/RoomEnvironmentComponent.js.map +0 -1
- package/dist/plugins/components/RoomEnvironmentComponent.module.js.map +0 -1
- package/dist/plugins/components/StatsPanelComponent.js.map +0 -1
- package/dist/plugins/components/StatsPanelComponent.module.js.map +0 -1
- package/dist/plugins/loaders/GLTFCloudLoader.js.map +0 -1
- package/dist/plugins/loaders/GLTFCloudLoader.module.js.map +0 -1
- package/dist/plugins/loaders/IFCXLoader.js.map +0 -1
- package/dist/plugins/loaders/IFCXLoader.module.js.map +0 -1
- package/dist/plugins/loaders/PotreeLoader.js.map +0 -1
- package/dist/plugins/loaders/PotreeLoader.module.js.map +0 -1
- /package/dist/{plugins → extensions}/components/GridHelperComponent.js +0 -0
- /package/dist/{plugins → extensions}/components/GridHelperComponent.min.js +0 -0
- /package/dist/{plugins → extensions}/components/GridHelperComponent.module.js +0 -0
- /package/dist/{plugins → extensions}/components/LightHelperComponent.js +0 -0
- /package/dist/{plugins → extensions}/components/LightHelperComponent.min.js +0 -0
- /package/dist/{plugins → extensions}/components/LightHelperComponent.module.js +0 -0
- /package/dist/{plugins → extensions}/components/RoomEnvironmentComponent.js +0 -0
- /package/dist/{plugins → extensions}/components/RoomEnvironmentComponent.min.js +0 -0
- /package/dist/{plugins → extensions}/components/RoomEnvironmentComponent.module.js +0 -0
- /package/dist/{plugins → extensions}/components/StatsPanelComponent.js +0 -0
- /package/dist/{plugins → extensions}/components/StatsPanelComponent.min.js +0 -0
- /package/dist/{plugins → extensions}/components/StatsPanelComponent.module.js +0 -0
- /package/{plugins → extensions}/components/GridHelperComponent.ts +0 -0
- /package/{plugins → extensions}/components/LightHelperComponent.ts +0 -0
- /package/{plugins → extensions}/components/RoomEnvironmentComponent.ts +0 -0
- /package/{plugins → extensions}/components/StatsPanelComponent.ts +0 -0
- /package/{plugins → extensions}/loaders/IFCX/IFCXLoader.ts +0 -0
- /package/{plugins → extensions}/loaders/IFCX/index.ts +0 -0
- /package/{plugins → extensions}/loaders/IFCX/render.js +0 -0
- /package/{plugins → extensions}/loaders/Potree/PotreeModelImpl.ts +0 -0
- /package/{plugins → extensions}/loaders/Potree/index.ts +0 -0
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
LineLoop,
|
|
11
11
|
Group,
|
|
12
12
|
Vector3,
|
|
13
|
+
Vector2,
|
|
13
14
|
Quaternion,
|
|
14
15
|
Matrix4,
|
|
15
16
|
Box3,
|
|
@@ -26,6 +27,8 @@ import {
|
|
|
26
27
|
import { GL_CONSTANTS } from "./GltfStructure.js";
|
|
27
28
|
import { mergeGeometries } from "three/examples/jsm/utils/BufferGeometryUtils.js";
|
|
28
29
|
|
|
30
|
+
const STRUCTURE_ID_SEPARATOR = ":";
|
|
31
|
+
|
|
29
32
|
//#AI-GENERATED using Gemini 2.5 Pro, Claude-4-sonnet
|
|
30
33
|
//#Reviewed and adapted by dborysov@opendesign.com
|
|
31
34
|
|
|
@@ -42,6 +45,7 @@ export class DynamicGltfLoader {
|
|
|
42
45
|
geometryerror: [],
|
|
43
46
|
update: [],
|
|
44
47
|
geometrymemory: [],
|
|
48
|
+
optimizationprogress: [],
|
|
45
49
|
};
|
|
46
50
|
|
|
47
51
|
this.loadDistance = 100;
|
|
@@ -98,7 +102,6 @@ export class DynamicGltfLoader {
|
|
|
98
102
|
this.newOptimizedObjects = new Set();
|
|
99
103
|
this.oldOptimizeObjects = new Set();
|
|
100
104
|
|
|
101
|
-
this.maxConcurrentChunks = 8;
|
|
102
105
|
this.activeChunkLoads = 0;
|
|
103
106
|
this.chunkQueue = [];
|
|
104
107
|
|
|
@@ -113,6 +116,8 @@ export class DynamicGltfLoader {
|
|
|
113
116
|
// Merged geometry tracking
|
|
114
117
|
this.mergedObjectMap = new Map(); // objectId -> {mergedObject, startIndex, endIndex, vertexCount}
|
|
115
118
|
this.mergedGeometryVisibility = new Map(); // mergedObject -> visibility array
|
|
119
|
+
|
|
120
|
+
this._webglInfoCache = null; // { renderer, vendor }
|
|
116
121
|
}
|
|
117
122
|
|
|
118
123
|
setVisibleEdges(visible) {
|
|
@@ -244,6 +249,136 @@ export class DynamicGltfLoader {
|
|
|
244
249
|
console.log(`Final memory usage: ${Math.round(currentMemoryUsage / (1024 * 1024))}MB`);
|
|
245
250
|
}
|
|
246
251
|
|
|
252
|
+
getStats() {
|
|
253
|
+
let totalObjects = 0;
|
|
254
|
+
let renderedObjects = 0;
|
|
255
|
+
let totalTriangles = 0;
|
|
256
|
+
let renderedTriangles = 0;
|
|
257
|
+
let totalLines = 0;
|
|
258
|
+
let renderedLines = 0;
|
|
259
|
+
let totalEdges = 0;
|
|
260
|
+
let renderedEdges = 0;
|
|
261
|
+
|
|
262
|
+
this.scene.traverse((object) => {
|
|
263
|
+
totalObjects++;
|
|
264
|
+
|
|
265
|
+
const geometry = object.geometry;
|
|
266
|
+
if (!geometry) return;
|
|
267
|
+
|
|
268
|
+
let triCount = 0;
|
|
269
|
+
if (geometry.index) {
|
|
270
|
+
triCount = Math.floor(geometry.index.count / 3);
|
|
271
|
+
} else if (geometry.attributes && geometry.attributes.position) {
|
|
272
|
+
triCount = Math.floor(geometry.attributes.position.count / 3);
|
|
273
|
+
}
|
|
274
|
+
totalTriangles += triCount;
|
|
275
|
+
|
|
276
|
+
let lineCount = 0;
|
|
277
|
+
if (geometry.index) {
|
|
278
|
+
lineCount = Math.floor(geometry.index.count / 2);
|
|
279
|
+
} else if (geometry.attributes && geometry.attributes.position) {
|
|
280
|
+
lineCount = Math.floor(geometry.attributes.position.count / 2);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (object.type === "Line" || object.type === "LineSegments" || object.type === "LineLoop") {
|
|
284
|
+
if (object.userData.isEdge) {
|
|
285
|
+
totalEdges += lineCount;
|
|
286
|
+
} else {
|
|
287
|
+
totalLines += lineCount;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (object.visible !== false) {
|
|
292
|
+
if (object.isMesh || object.isLine || object.isPoints) {
|
|
293
|
+
renderedObjects++;
|
|
294
|
+
if (object.isMesh) {
|
|
295
|
+
renderedTriangles += triCount;
|
|
296
|
+
} else if (object.type === "Line" || object.type === "LineSegments" || object.type === "LineLoop") {
|
|
297
|
+
if (object.userData.isEdge) {
|
|
298
|
+
renderedEdges += lineCount;
|
|
299
|
+
} else {
|
|
300
|
+
renderedLines += lineCount;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
const geometryCount = this.geometryCache ? this.geometryCache.size : 0;
|
|
308
|
+
const geometryMemoryBytes = Array.from(this.geometryCache?.values?.() || []).reduce((a, b) => a + b, 0);
|
|
309
|
+
|
|
310
|
+
const uniqueMaterialIds = new Set();
|
|
311
|
+
const uniqueTextureIds = new Set();
|
|
312
|
+
if (Array.isArray(this.structures)) {
|
|
313
|
+
for (const structure of this.structures) {
|
|
314
|
+
console.log(structure.materialCache.values());
|
|
315
|
+
try {
|
|
316
|
+
for (const entry of structure.materialCache.values()) {
|
|
317
|
+
if (entry?.mesh?.uuid) uniqueMaterialIds.add(entry.mesh.uuid);
|
|
318
|
+
if (entry?.points?.uuid) uniqueMaterialIds.add(entry.points.uuid);
|
|
319
|
+
if (entry?.lines?.uuid) uniqueMaterialIds.add(entry.lines.uuid);
|
|
320
|
+
}
|
|
321
|
+
} catch (exp) {
|
|
322
|
+
console.error("Error adding material to uniqueMaterialIds", exp);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
const materialCount = uniqueMaterialIds.size;
|
|
327
|
+
const textureCount = uniqueTextureIds.size;
|
|
328
|
+
const estimatedGpuMemoryBytes = geometryMemoryBytes;
|
|
329
|
+
|
|
330
|
+
if (!this._webglInfoCache) {
|
|
331
|
+
try {
|
|
332
|
+
const gl = this.renderer.getContext();
|
|
333
|
+
const dbgInfo = gl.getExtension("WEBGL_debug_renderer_info");
|
|
334
|
+
if (dbgInfo) {
|
|
335
|
+
const rendererStr = gl.getParameter(dbgInfo.UNMASKED_RENDERER_WEBGL);
|
|
336
|
+
const vendorStr = gl.getParameter(dbgInfo.UNMASKED_VENDOR_WEBGL);
|
|
337
|
+
this._webglInfoCache = { renderer: rendererStr, vendor: vendorStr };
|
|
338
|
+
} else {
|
|
339
|
+
this._webglInfoCache = { renderer: null, vendor: null };
|
|
340
|
+
}
|
|
341
|
+
} catch (e) {
|
|
342
|
+
console.error("Error getting webgl info", e);
|
|
343
|
+
this._webglInfoCache = { renderer: null, vendor: null };
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const size = new Vector2();
|
|
348
|
+
if (this.renderer && this.renderer.getSize) {
|
|
349
|
+
this.renderer.getSize(size);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return {
|
|
353
|
+
scene: {
|
|
354
|
+
beforeOptimization: {
|
|
355
|
+
objects: totalObjects - renderedObjects,
|
|
356
|
+
triangles: totalTriangles - renderedTriangles,
|
|
357
|
+
lines: totalLines - renderedLines,
|
|
358
|
+
edges: totalEdges - renderedEdges,
|
|
359
|
+
},
|
|
360
|
+
|
|
361
|
+
afterOptimization: {
|
|
362
|
+
objects: renderedObjects,
|
|
363
|
+
triangles: renderedTriangles,
|
|
364
|
+
lines: renderedLines,
|
|
365
|
+
edges: renderedEdges,
|
|
366
|
+
},
|
|
367
|
+
},
|
|
368
|
+
memory: {
|
|
369
|
+
geometries: { count: geometryCount, bytes: geometryMemoryBytes },
|
|
370
|
+
textures: { count: textureCount },
|
|
371
|
+
materials: { count: materialCount },
|
|
372
|
+
totalEstimatedGpuBytes: estimatedGpuMemoryBytes,
|
|
373
|
+
},
|
|
374
|
+
system: {
|
|
375
|
+
webglRenderer: this._webglInfoCache?.renderer || "",
|
|
376
|
+
webglVendor: this._webglInfoCache?.vendor || "",
|
|
377
|
+
viewport: { width: size.x || 0, height: size.y || 0 },
|
|
378
|
+
},
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
|
|
247
382
|
async loadNode(nodeId, onLoadFinishCb) {
|
|
248
383
|
const node = this.nodes.get(nodeId);
|
|
249
384
|
if (!node || node.loaded || node.loading) return;
|
|
@@ -419,6 +554,7 @@ export class DynamicGltfLoader {
|
|
|
419
554
|
} else if (primitive.mode === GL_CONSTANTS.LINE_LOOP) {
|
|
420
555
|
mesh = new LineLoop(geometry, material);
|
|
421
556
|
}
|
|
557
|
+
|
|
422
558
|
if (node.extras) {
|
|
423
559
|
mesh.userData = { ...mesh.userData, ...node.extras };
|
|
424
560
|
}
|
|
@@ -428,17 +564,21 @@ export class DynamicGltfLoader {
|
|
|
428
564
|
if (primitive.extras) {
|
|
429
565
|
mesh.userData = { ...mesh.userData, ...primitive.extras };
|
|
430
566
|
}
|
|
567
|
+
|
|
431
568
|
if (node.handle) {
|
|
432
569
|
mesh.userData.handle = node.handle;
|
|
433
570
|
} else {
|
|
434
|
-
mesh.userData.handle =
|
|
571
|
+
mesh.userData.handle = this.getFullHandle(node.structure.id, mesh.userData.handle);
|
|
435
572
|
}
|
|
573
|
+
|
|
436
574
|
if (mesh.material.name === "edges") {
|
|
437
575
|
mesh.userData.isEdge = true;
|
|
438
576
|
} else {
|
|
439
577
|
mesh.userData.isEdge = false;
|
|
440
578
|
}
|
|
579
|
+
|
|
441
580
|
this.registerObjectWithHandle(mesh, mesh.userData.handle);
|
|
581
|
+
|
|
442
582
|
mesh.position.copy(node.position);
|
|
443
583
|
if (!geometry.attributes.normal) {
|
|
444
584
|
geometry.computeVertexNormals();
|
|
@@ -601,13 +741,17 @@ export class DynamicGltfLoader {
|
|
|
601
741
|
});
|
|
602
742
|
}
|
|
603
743
|
|
|
744
|
+
getFullHandle(structureId, originalHandle) {
|
|
745
|
+
return `${structureId}${STRUCTURE_ID_SEPARATOR}${originalHandle}`;
|
|
746
|
+
}
|
|
747
|
+
|
|
604
748
|
async processNodeHierarchy(structure, nodeId, parentGroup) {
|
|
605
749
|
const nodeDef = structure.json.nodes[nodeId];
|
|
606
750
|
let nodeGroup = null;
|
|
607
751
|
|
|
608
752
|
let handle = null;
|
|
609
753
|
if (nodeDef.extras?.handle) {
|
|
610
|
-
handle =
|
|
754
|
+
handle = this.getFullHandle(structure.id, nodeDef.extras.handle);
|
|
611
755
|
}
|
|
612
756
|
|
|
613
757
|
if (nodeDef.camera !== undefined) {
|
|
@@ -628,7 +772,7 @@ export class DynamicGltfLoader {
|
|
|
628
772
|
if (nodeDef.extras) {
|
|
629
773
|
nodeGroup.userData = { ...nodeDef.extras };
|
|
630
774
|
if (nodeGroup.userData.handle) {
|
|
631
|
-
nodeGroup.userData.handle =
|
|
775
|
+
nodeGroup.userData.handle = this.getFullHandle(structure.id, nodeGroup.userData.handle);
|
|
632
776
|
}
|
|
633
777
|
}
|
|
634
778
|
|
|
@@ -680,7 +824,7 @@ export class DynamicGltfLoader {
|
|
|
680
824
|
}
|
|
681
825
|
|
|
682
826
|
if (meshDef.extras && meshDef.extras.handle) {
|
|
683
|
-
handle =
|
|
827
|
+
handle = this.getFullHandle(structure.id, meshDef.extras.handle);
|
|
684
828
|
}
|
|
685
829
|
|
|
686
830
|
this.nodes.set(uniqueNodeId, {
|
|
@@ -694,7 +838,7 @@ export class DynamicGltfLoader {
|
|
|
694
838
|
structure,
|
|
695
839
|
extras: nodeDef.extras,
|
|
696
840
|
geometryExtents,
|
|
697
|
-
handle,
|
|
841
|
+
handle: handle || this.getFullHandle(structure.id, structure._nextObjectId++),
|
|
698
842
|
});
|
|
699
843
|
}
|
|
700
844
|
|
|
@@ -785,13 +929,13 @@ export class DynamicGltfLoader {
|
|
|
785
929
|
}
|
|
786
930
|
|
|
787
931
|
async loadNodes() {
|
|
788
|
-
console.time("
|
|
932
|
+
console.time("Process nodes");
|
|
789
933
|
await this.processNodes();
|
|
790
|
-
console.timeEnd("
|
|
934
|
+
console.timeEnd("Process nodes");
|
|
791
935
|
|
|
792
|
-
console.time("
|
|
936
|
+
console.time("Optimize scene");
|
|
793
937
|
await this.optimizeScene();
|
|
794
|
-
console.timeEnd("
|
|
938
|
+
console.timeEnd("Optimize scene");
|
|
795
939
|
}
|
|
796
940
|
|
|
797
941
|
cleanupPartialLoad() {
|
|
@@ -955,7 +1099,7 @@ export class DynamicGltfLoader {
|
|
|
955
1099
|
}
|
|
956
1100
|
|
|
957
1101
|
createVisibilityMaterial(material) {
|
|
958
|
-
//
|
|
1102
|
+
// Apply shader directly to the original material
|
|
959
1103
|
material.onBeforeCompile = (shader) => {
|
|
960
1104
|
shader.vertexShader = shader.vertexShader.replace(
|
|
961
1105
|
"#include <common>",
|
|
@@ -991,7 +1135,7 @@ export class DynamicGltfLoader {
|
|
|
991
1135
|
);
|
|
992
1136
|
};
|
|
993
1137
|
|
|
994
|
-
//
|
|
1138
|
+
// Force recompilation of material
|
|
995
1139
|
material.needsUpdate = true;
|
|
996
1140
|
|
|
997
1141
|
return material;
|
|
@@ -1162,7 +1306,7 @@ export class DynamicGltfLoader {
|
|
|
1162
1306
|
}
|
|
1163
1307
|
this.handleToObjects.get(fullHandle).add(object);
|
|
1164
1308
|
|
|
1165
|
-
object.userData.structureId = object.userData.handle.split(
|
|
1309
|
+
object.userData.structureId = object.userData.handle.split(STRUCTURE_ID_SEPARATOR)[0];
|
|
1166
1310
|
}
|
|
1167
1311
|
|
|
1168
1312
|
getObjectsByHandle(handle) {
|
|
@@ -1237,11 +1381,32 @@ export class DynamicGltfLoader {
|
|
|
1237
1381
|
this.originalObjects.add(object);
|
|
1238
1382
|
}
|
|
1239
1383
|
|
|
1240
|
-
|
|
1384
|
+
yieldToUI() {
|
|
1385
|
+
return new Promise((resolve) => {
|
|
1386
|
+
requestAnimationFrame(() => {
|
|
1387
|
+
setTimeout(resolve, 0);
|
|
1388
|
+
});
|
|
1389
|
+
});
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
async optimizeScene() {
|
|
1393
|
+
console.log("Starting scene optimization...");
|
|
1394
|
+
this.dispatchEvent("optimizationprogress", {
|
|
1395
|
+
phase: "start",
|
|
1396
|
+
progress: 0,
|
|
1397
|
+
message: "Starting optimization...",
|
|
1398
|
+
});
|
|
1399
|
+
|
|
1241
1400
|
this.originalObjects.clear();
|
|
1242
1401
|
this.originalObjectsToSelection.clear();
|
|
1243
1402
|
const structureGroups = new Map();
|
|
1244
1403
|
|
|
1404
|
+
this.dispatchEvent("optimizationprogress", {
|
|
1405
|
+
phase: "collecting",
|
|
1406
|
+
progress: 5,
|
|
1407
|
+
message: "Collecting scene objects...",
|
|
1408
|
+
});
|
|
1409
|
+
|
|
1245
1410
|
this.scene.traverse((object) => {
|
|
1246
1411
|
if (object.userData.structureId) {
|
|
1247
1412
|
const structureId = object.userData.structureId;
|
|
@@ -1274,32 +1439,78 @@ export class DynamicGltfLoader {
|
|
|
1274
1439
|
}
|
|
1275
1440
|
});
|
|
1276
1441
|
|
|
1442
|
+
let processedGroups = 0;
|
|
1443
|
+
const totalGroups = structureGroups.size;
|
|
1444
|
+
|
|
1445
|
+
this.dispatchEvent("optimizationprogress", {
|
|
1446
|
+
phase: "merging",
|
|
1447
|
+
progress: 10,
|
|
1448
|
+
message: `Merging ${totalGroups} structure groups...`,
|
|
1449
|
+
current: 0,
|
|
1450
|
+
total: totalGroups,
|
|
1451
|
+
});
|
|
1452
|
+
|
|
1277
1453
|
for (const group of structureGroups.values()) {
|
|
1278
1454
|
group.mapMeshes.clear();
|
|
1279
1455
|
group.mapLines.clear();
|
|
1280
1456
|
group.mapLineSegments.clear();
|
|
1281
1457
|
group.mapPoints.clear();
|
|
1282
1458
|
|
|
1283
|
-
this.mergeMeshGroups(group.meshes, group.rootGroup);
|
|
1284
|
-
this.
|
|
1285
|
-
|
|
1286
|
-
this.
|
|
1459
|
+
await this.mergeMeshGroups(group.meshes, group.rootGroup);
|
|
1460
|
+
await this.yieldToUI();
|
|
1461
|
+
|
|
1462
|
+
await this.mergeLineGroups(group.lines, group.rootGroup);
|
|
1463
|
+
await this.yieldToUI();
|
|
1464
|
+
|
|
1465
|
+
await this.mergeLineSegmentGroups(group.lineSegments, group.rootGroup);
|
|
1466
|
+
await this.yieldToUI();
|
|
1467
|
+
|
|
1468
|
+
await this.mergePointsGroups(group.points, group.rootGroup);
|
|
1469
|
+
|
|
1470
|
+
processedGroups++;
|
|
1471
|
+
const progress = 10 + Math.round((processedGroups / totalGroups) * 80);
|
|
1472
|
+
|
|
1473
|
+
this.dispatchEvent("optimizationprogress", {
|
|
1474
|
+
phase: "merging",
|
|
1475
|
+
progress,
|
|
1476
|
+
message: `Processing structure ${processedGroups}/${totalGroups}...`,
|
|
1477
|
+
current: processedGroups,
|
|
1478
|
+
total: totalGroups,
|
|
1479
|
+
});
|
|
1480
|
+
|
|
1481
|
+
console.log(`Optimization progress: ${processedGroups}/${totalGroups} structure groups processed (${progress}%)`);
|
|
1482
|
+
|
|
1483
|
+
await this.yieldToUI();
|
|
1287
1484
|
}
|
|
1288
1485
|
|
|
1486
|
+
this.dispatchEvent("optimizationprogress", {
|
|
1487
|
+
phase: "finalizing",
|
|
1488
|
+
progress: 95,
|
|
1489
|
+
message: "Finalizing optimization...",
|
|
1490
|
+
});
|
|
1491
|
+
|
|
1289
1492
|
this.originalObjects.forEach((obj) => {
|
|
1290
1493
|
obj.visible = false;
|
|
1291
1494
|
if (!(obj instanceof Points) && !obj.userData.isEdge) {
|
|
1292
1495
|
this.originalObjectsToSelection.add(obj);
|
|
1293
1496
|
}
|
|
1294
1497
|
});
|
|
1498
|
+
|
|
1295
1499
|
this.initializeObjectVisibility();
|
|
1296
1500
|
|
|
1297
1501
|
console.log(`Optimization complete. Total objects: ${this.maxObjectId}`);
|
|
1298
1502
|
|
|
1503
|
+
this.dispatchEvent("optimizationprogress", {
|
|
1504
|
+
phase: "complete",
|
|
1505
|
+
progress: 100,
|
|
1506
|
+
message: `Optimization complete! ${this.maxObjectId} objects processed.`,
|
|
1507
|
+
});
|
|
1508
|
+
|
|
1299
1509
|
this.dispatchEvent("update");
|
|
1300
1510
|
}
|
|
1301
1511
|
|
|
1302
|
-
mergeMeshGroups(materialGroups, rootGroup) {
|
|
1512
|
+
async mergeMeshGroups(materialGroups, rootGroup) {
|
|
1513
|
+
let processedGroups = 0;
|
|
1303
1514
|
for (const group of materialGroups) {
|
|
1304
1515
|
if (!group.material) {
|
|
1305
1516
|
console.warn("Skipping mesh group with null material");
|
|
@@ -1315,8 +1526,6 @@ export class DynamicGltfLoader {
|
|
|
1315
1526
|
|
|
1316
1527
|
for (const mesh of group.objects) {
|
|
1317
1528
|
const geometry = mesh.geometry.clone();
|
|
1318
|
-
mesh.updateWorldMatrix(true, false);
|
|
1319
|
-
geometry.applyMatrix4(mesh.matrixWorld);
|
|
1320
1529
|
|
|
1321
1530
|
const handle = mesh.userData.handle;
|
|
1322
1531
|
if (!this.objectIdToIndex.has(handle)) {
|
|
@@ -1399,6 +1608,11 @@ export class DynamicGltfLoader {
|
|
|
1399
1608
|
this.handleToOptimizedObjects.set(handle, mergedObjects);
|
|
1400
1609
|
}
|
|
1401
1610
|
});
|
|
1611
|
+
|
|
1612
|
+
processedGroups++;
|
|
1613
|
+
if (processedGroups % 5 === 0) {
|
|
1614
|
+
await this.yieldToUI();
|
|
1615
|
+
}
|
|
1402
1616
|
} catch (error) {
|
|
1403
1617
|
console.error("Failed to merge meshes for material:", error);
|
|
1404
1618
|
group.objects.forEach((mesh) => {
|
|
@@ -1408,7 +1622,8 @@ export class DynamicGltfLoader {
|
|
|
1408
1622
|
}
|
|
1409
1623
|
}
|
|
1410
1624
|
|
|
1411
|
-
mergeLineGroups(materialGroups, rootGroup) {
|
|
1625
|
+
async mergeLineGroups(materialGroups, rootGroup) {
|
|
1626
|
+
let processedGroups = 0;
|
|
1412
1627
|
for (const group of materialGroups) {
|
|
1413
1628
|
if (group.objects.length === 0) continue;
|
|
1414
1629
|
|
|
@@ -1433,7 +1648,9 @@ export class DynamicGltfLoader {
|
|
|
1433
1648
|
const indices = [];
|
|
1434
1649
|
let vertexOffset = 0;
|
|
1435
1650
|
|
|
1651
|
+
let isEdge = false;
|
|
1436
1652
|
group.objects.forEach((line) => {
|
|
1653
|
+
isEdge = line.userData.isEdge;
|
|
1437
1654
|
const geometry = line.geometry;
|
|
1438
1655
|
const positionAttr = geometry.attributes.position;
|
|
1439
1656
|
const vertexCount = positionAttr.count;
|
|
@@ -1442,21 +1659,16 @@ export class DynamicGltfLoader {
|
|
|
1442
1659
|
if (!this.objectIdToIndex.has(handle)) {
|
|
1443
1660
|
this.objectIdToIndex.set(handle, this.maxObjectId++);
|
|
1444
1661
|
}
|
|
1445
|
-
// const objectId = this.objectIdToIndex.get(handle);
|
|
1446
1662
|
|
|
1447
1663
|
objectMapping.set(line, {
|
|
1448
1664
|
startVertexIndex: currentVertexOffset,
|
|
1449
1665
|
vertexCount,
|
|
1450
1666
|
});
|
|
1451
1667
|
currentVertexOffset += vertexCount;
|
|
1452
|
-
|
|
1453
|
-
line.updateWorldMatrix(true, false);
|
|
1454
|
-
const matrix = line.matrixWorld;
|
|
1455
1668
|
const vector = new Vector3();
|
|
1456
1669
|
|
|
1457
1670
|
for (let i = 0; i < vertexCount; i++) {
|
|
1458
1671
|
vector.fromBufferAttribute(positionAttr, i);
|
|
1459
|
-
vector.applyMatrix4(matrix);
|
|
1460
1672
|
positions[posOffset++] = vector.x;
|
|
1461
1673
|
positions[posOffset++] = vector.y;
|
|
1462
1674
|
positions[posOffset++] = vector.z;
|
|
@@ -1497,6 +1709,8 @@ export class DynamicGltfLoader {
|
|
|
1497
1709
|
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
1498
1710
|
|
|
1499
1711
|
const mergedLine = new LineSegments(geometry, visibilityMaterial);
|
|
1712
|
+
mergedLine.userData.isEdge = isEdge;
|
|
1713
|
+
|
|
1500
1714
|
const mergedObjects = [mergedLine];
|
|
1501
1715
|
if (this.useVAO) {
|
|
1502
1716
|
this.createVAO(mergedLine);
|
|
@@ -1522,10 +1736,16 @@ export class DynamicGltfLoader {
|
|
|
1522
1736
|
this.handleToOptimizedObjects.set(handle, mergedObjects);
|
|
1523
1737
|
}
|
|
1524
1738
|
});
|
|
1739
|
+
|
|
1740
|
+
processedGroups++;
|
|
1741
|
+
if (processedGroups % 5 === 0) {
|
|
1742
|
+
await this.yieldToUI();
|
|
1743
|
+
}
|
|
1525
1744
|
}
|
|
1526
1745
|
}
|
|
1527
1746
|
|
|
1528
|
-
mergeLineSegmentGroups(materialGroups, rootGroup) {
|
|
1747
|
+
async mergeLineSegmentGroups(materialGroups, rootGroup) {
|
|
1748
|
+
let processedGroups = 0;
|
|
1529
1749
|
for (const group of materialGroups) {
|
|
1530
1750
|
if (!group.material) {
|
|
1531
1751
|
console.warn("Skipping line segment group with null material");
|
|
@@ -1538,11 +1758,11 @@ export class DynamicGltfLoader {
|
|
|
1538
1758
|
const handles = new Set();
|
|
1539
1759
|
const objectMapping = new Map();
|
|
1540
1760
|
let currentVertexOffset = 0;
|
|
1761
|
+
let isEdge = false;
|
|
1541
1762
|
|
|
1542
1763
|
for (const line of group.objects) {
|
|
1764
|
+
isEdge = line.userData.isEdge;
|
|
1543
1765
|
const geometry = line.geometry.clone();
|
|
1544
|
-
line.updateWorldMatrix(true, false);
|
|
1545
|
-
geometry.applyMatrix4(line.matrixWorld);
|
|
1546
1766
|
|
|
1547
1767
|
const handle = line.userData.handle;
|
|
1548
1768
|
if (!this.objectIdToIndex.has(handle)) {
|
|
@@ -1585,6 +1805,7 @@ export class DynamicGltfLoader {
|
|
|
1585
1805
|
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
1586
1806
|
|
|
1587
1807
|
const mergedLine = new LineSegments(mergedGeometry, visibilityMaterial);
|
|
1808
|
+
mergedLine.userData.isEdge = isEdge;
|
|
1588
1809
|
|
|
1589
1810
|
if (this.useVAO) {
|
|
1590
1811
|
this.createVAO(mergedLine);
|
|
@@ -1618,6 +1839,11 @@ export class DynamicGltfLoader {
|
|
|
1618
1839
|
this.handleToOptimizedObjects.set(handle, mergedObjects);
|
|
1619
1840
|
}
|
|
1620
1841
|
});
|
|
1842
|
+
|
|
1843
|
+
processedGroups++;
|
|
1844
|
+
if (processedGroups % 5 === 0) {
|
|
1845
|
+
await this.yieldToUI();
|
|
1846
|
+
}
|
|
1621
1847
|
} catch (error) {
|
|
1622
1848
|
console.warn("Failed to merge line segments for material:", error);
|
|
1623
1849
|
group.objects.forEach((line) => {
|
|
@@ -1627,7 +1853,8 @@ export class DynamicGltfLoader {
|
|
|
1627
1853
|
}
|
|
1628
1854
|
}
|
|
1629
1855
|
|
|
1630
|
-
mergePointsGroups(materialGroups, rootGroup) {
|
|
1856
|
+
async mergePointsGroups(materialGroups, rootGroup) {
|
|
1857
|
+
let processedGroups = 0;
|
|
1631
1858
|
for (const group of materialGroups) {
|
|
1632
1859
|
if (!group.material) {
|
|
1633
1860
|
console.warn("Skipping points group with null material");
|
|
@@ -1641,8 +1868,6 @@ export class DynamicGltfLoader {
|
|
|
1641
1868
|
|
|
1642
1869
|
for (const points of group.objects) {
|
|
1643
1870
|
const geometry = points.geometry.clone();
|
|
1644
|
-
points.updateWorldMatrix(true, false);
|
|
1645
|
-
geometry.applyMatrix4(points.matrixWorld);
|
|
1646
1871
|
geometries.push(geometry);
|
|
1647
1872
|
optimizedObjects.push(points);
|
|
1648
1873
|
handles.add(points.userData.handle);
|
|
@@ -1678,6 +1903,11 @@ export class DynamicGltfLoader {
|
|
|
1678
1903
|
this.handleToOptimizedObjects.set(handle, mergedObjects);
|
|
1679
1904
|
}
|
|
1680
1905
|
});
|
|
1906
|
+
|
|
1907
|
+
processedGroups++;
|
|
1908
|
+
if (processedGroups % 5 === 0) {
|
|
1909
|
+
await this.yieldToUI();
|
|
1910
|
+
}
|
|
1681
1911
|
} catch (error) {
|
|
1682
1912
|
console.warn("Failed to merge points for material:", error);
|
|
1683
1913
|
group.objects.forEach((points) => {
|
|
@@ -1700,7 +1930,6 @@ export class DynamicGltfLoader {
|
|
|
1700
1930
|
|
|
1701
1931
|
lineSegmentsArray.forEach((segment) => {
|
|
1702
1932
|
const clonedGeometry = segment.geometry.clone();
|
|
1703
|
-
segment.updateWorldMatrix(true, false);
|
|
1704
1933
|
clonedGeometry.applyMatrix4(segment.matrixWorld);
|
|
1705
1934
|
|
|
1706
1935
|
if (hasNormals && !clonedGeometry.attributes.normal) {
|
|
@@ -30,7 +30,6 @@ import { DynamicGltfLoader } from "./DynamicGltfLoader.js";
|
|
|
30
30
|
|
|
31
31
|
export class DynamicModelImpl extends ModelImpl {
|
|
32
32
|
public gltfLoader: DynamicGltfLoader;
|
|
33
|
-
public modelId: number;
|
|
34
33
|
|
|
35
34
|
override getExtents(target: Box3): Box3 {
|
|
36
35
|
return target.union(this.gltfLoader.getTotalGeometryExtent());
|
|
@@ -53,35 +52,46 @@ export class DynamicModelImpl extends ModelImpl {
|
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
override getObjectsByHandles(handles: string | string[]): Object3D[] {
|
|
56
|
-
const
|
|
55
|
+
const ownHandles = this.getOwnHandles(handles);
|
|
56
|
+
if (ownHandles.length === 0) return [];
|
|
57
|
+
|
|
58
|
+
const handlesSet = new Set(ownHandles);
|
|
59
|
+
|
|
57
60
|
const objects = [];
|
|
58
61
|
handlesSet.forEach((handle) => {
|
|
59
|
-
|
|
60
|
-
const handles = this.gltfLoader.handleToObjects.get(handle2) || [];
|
|
61
|
-
objects.push(...Array.from(handles));
|
|
62
|
+
objects.push(...this.gltfLoader.getObjectsByHandle(handle));
|
|
62
63
|
});
|
|
64
|
+
|
|
63
65
|
return objects;
|
|
64
66
|
}
|
|
65
67
|
|
|
66
68
|
override getHandlesByObjects(objects: Object3D | Object3D[]): string[] {
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
+
const ownObjects = this.getOwnObjects(objects);
|
|
70
|
+
if (ownObjects.length === 0) return [];
|
|
71
|
+
|
|
72
|
+
const handleSet = new Set<string>();
|
|
73
|
+
ownObjects.forEach((object) => {
|
|
74
|
+
const handle = object.userData.handle;
|
|
75
|
+
if (handle) handleSet.add(handle);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
return Array.from(handleSet);
|
|
69
79
|
}
|
|
70
80
|
|
|
71
81
|
override hideObjects(objects: Object3D | Object3D[]): this {
|
|
72
|
-
const handles =
|
|
82
|
+
const handles = this.getHandlesByObjects(objects);
|
|
73
83
|
this.gltfLoader.hideObjects(handles);
|
|
74
84
|
return this;
|
|
75
85
|
}
|
|
76
86
|
|
|
77
87
|
override isolateObjects(objects: Object3D | Object3D[]): this {
|
|
78
|
-
const handles =
|
|
88
|
+
const handles = this.getHandlesByObjects(objects);
|
|
79
89
|
this.gltfLoader.isolateObjects(new Set(handles));
|
|
80
90
|
return this;
|
|
81
91
|
}
|
|
82
92
|
|
|
83
93
|
override showObjects(objects: Object3D | Object3D[]): this {
|
|
84
|
-
const handles =
|
|
94
|
+
const handles = this.getHandlesByObjects(objects);
|
|
85
95
|
this.gltfLoader.showObjects(handles);
|
|
86
96
|
return this;
|
|
87
97
|
}
|
|
@@ -58,12 +58,15 @@ export class GltfStructure {
|
|
|
58
58
|
this.materials = new Map();
|
|
59
59
|
this.textureCache = new Map();
|
|
60
60
|
this.materialCache = new Map();
|
|
61
|
+
this.uri = "";
|
|
62
|
+
this._nextObjectId = 0;
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
async initialize(loader) {
|
|
64
66
|
this.json = await this.loadController.loadJson();
|
|
65
67
|
this.baseUrl = await this.loadController.baseUrl();
|
|
66
68
|
this.loader = loader;
|
|
69
|
+
this.uri = this.json.buffers[0].uri || "";
|
|
67
70
|
}
|
|
68
71
|
|
|
69
72
|
clear() {
|
|
@@ -166,7 +169,7 @@ export class GltfStructure {
|
|
|
166
169
|
|
|
167
170
|
try {
|
|
168
171
|
const length = range.end - range.start;
|
|
169
|
-
const buffer = await this.loadController.loadBinaryData([{ offset: range.start, length }]);
|
|
172
|
+
const buffer = await this.loadController.loadBinaryData([{ offset: range.start, length }], this.uri);
|
|
170
173
|
|
|
171
174
|
for (const req of range.requests) {
|
|
172
175
|
const relOffset = req.offset - range.start;
|