@inweb/viewer-three 26.10.6 → 26.12.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/InfoPanelComponent.js +170 -0
- package/dist/extensions/components/InfoPanelComponent.js.map +1 -0
- package/dist/extensions/components/InfoPanelComponent.min.js +24 -0
- package/dist/extensions/components/InfoPanelComponent.module.js +164 -0
- package/dist/extensions/components/InfoPanelComponent.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/{plugins → extensions}/components/StatsPanelComponent.js +9 -3
- package/dist/extensions/components/StatsPanelComponent.js.map +1 -0
- package/dist/extensions/components/StatsPanelComponent.min.js +24 -0
- package/dist/{plugins → extensions}/components/StatsPanelComponent.module.js +9 -3
- 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 +56 -6
- package/dist/extensions/loaders/PotreeLoader.js.map +1 -0
- package/dist/extensions/loaders/PotreeLoader.min.js +24 -0
- package/dist/{plugins → extensions}/loaders/PotreeLoader.module.js +53 -2
- package/dist/extensions/loaders/PotreeLoader.module.js.map +1 -0
- package/dist/viewer-three.js +1416 -2930
- package/dist/viewer-three.js.map +1 -1
- package/dist/viewer-three.min.js +8 -3
- package/dist/viewer-three.module.js +1205 -363
- 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/extensions/components/InfoPanelComponent.ts +197 -0
- package/{plugins → extensions}/components/StatsPanelComponent.ts +10 -3
- 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/extensions/loaders/Potree/PotreeModelImpl.ts +108 -0
- package/lib/Viewer/Viewer.d.ts +28 -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/InfoComponent.d.ts +22 -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 +2 -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 +11 -8
- package/lib/Viewer/models/ModelImpl.d.ts +9 -5
- package/package.json +11 -11
- package/src/Viewer/Viewer.ts +127 -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/{plugins/loaders/Potree/PotreeModelImpl.ts → src/Viewer/commands/GetSelected2.ts} +7 -9
- 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/InfoComponent.ts +187 -0
- package/src/Viewer/components/SelectionComponent.ts +7 -30
- package/src/Viewer/components/index.ts +8 -6
- package/src/Viewer/draggers/MeasureLineDragger.ts +84 -226
- package/src/Viewer/loaders/DynamicGltfLoader/DynamicGltfLoader.js +276 -39
- package/src/Viewer/loaders/DynamicGltfLoader/DynamicModelImpl.ts +45 -10
- package/src/Viewer/loaders/DynamicGltfLoader/GltfStructure.js +71 -2
- 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 +105 -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 +17 -8
- package/src/Viewer/models/ModelImpl.ts +205 -16
- 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.min.js +0 -24
- 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.min.js +0 -24
- 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/{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}/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/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;
|
|
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();
|
|
@@ -464,10 +604,17 @@ export class DynamicGltfLoader {
|
|
|
464
604
|
onLoadFinishCb();
|
|
465
605
|
}
|
|
466
606
|
} catch (error) {
|
|
467
|
-
if (error.name !== "AbortError") {
|
|
468
|
-
console.error(`Error loading node ${nodeId}:`, error);
|
|
469
|
-
}
|
|
470
607
|
node.loading = false;
|
|
608
|
+
|
|
609
|
+
if (error.name === "AbortError") {
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
if (node.structure && node.structure.loadingAborted) {
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
console.error(`Error loading node ${nodeId}:`, error);
|
|
471
618
|
}
|
|
472
619
|
}
|
|
473
620
|
|
|
@@ -601,13 +748,17 @@ export class DynamicGltfLoader {
|
|
|
601
748
|
});
|
|
602
749
|
}
|
|
603
750
|
|
|
751
|
+
getFullHandle(structureId, originalHandle) {
|
|
752
|
+
return `${structureId}${STRUCTURE_ID_SEPARATOR}${originalHandle}`;
|
|
753
|
+
}
|
|
754
|
+
|
|
604
755
|
async processNodeHierarchy(structure, nodeId, parentGroup) {
|
|
605
756
|
const nodeDef = structure.json.nodes[nodeId];
|
|
606
757
|
let nodeGroup = null;
|
|
607
758
|
|
|
608
759
|
let handle = null;
|
|
609
760
|
if (nodeDef.extras?.handle) {
|
|
610
|
-
handle =
|
|
761
|
+
handle = this.getFullHandle(structure.id, nodeDef.extras.handle);
|
|
611
762
|
}
|
|
612
763
|
|
|
613
764
|
if (nodeDef.camera !== undefined) {
|
|
@@ -628,7 +779,7 @@ export class DynamicGltfLoader {
|
|
|
628
779
|
if (nodeDef.extras) {
|
|
629
780
|
nodeGroup.userData = { ...nodeDef.extras };
|
|
630
781
|
if (nodeGroup.userData.handle) {
|
|
631
|
-
nodeGroup.userData.handle =
|
|
782
|
+
nodeGroup.userData.handle = this.getFullHandle(structure.id, nodeGroup.userData.handle);
|
|
632
783
|
}
|
|
633
784
|
}
|
|
634
785
|
|
|
@@ -680,7 +831,7 @@ export class DynamicGltfLoader {
|
|
|
680
831
|
}
|
|
681
832
|
|
|
682
833
|
if (meshDef.extras && meshDef.extras.handle) {
|
|
683
|
-
handle =
|
|
834
|
+
handle = this.getFullHandle(structure.id, meshDef.extras.handle);
|
|
684
835
|
}
|
|
685
836
|
|
|
686
837
|
this.nodes.set(uniqueNodeId, {
|
|
@@ -694,7 +845,7 @@ export class DynamicGltfLoader {
|
|
|
694
845
|
structure,
|
|
695
846
|
extras: nodeDef.extras,
|
|
696
847
|
geometryExtents,
|
|
697
|
-
handle,
|
|
848
|
+
handle: handle || this.getFullHandle(structure.id, structure._nextObjectId++),
|
|
698
849
|
});
|
|
699
850
|
}
|
|
700
851
|
|
|
@@ -785,13 +936,13 @@ export class DynamicGltfLoader {
|
|
|
785
936
|
}
|
|
786
937
|
|
|
787
938
|
async loadNodes() {
|
|
788
|
-
console.time("
|
|
939
|
+
console.time("Process nodes");
|
|
789
940
|
await this.processNodes();
|
|
790
|
-
console.timeEnd("
|
|
941
|
+
console.timeEnd("Process nodes");
|
|
791
942
|
|
|
792
|
-
console.time("
|
|
943
|
+
console.time("Optimize scene");
|
|
793
944
|
await this.optimizeScene();
|
|
794
|
-
console.timeEnd("
|
|
945
|
+
console.timeEnd("Optimize scene");
|
|
795
946
|
}
|
|
796
947
|
|
|
797
948
|
cleanupPartialLoad() {
|
|
@@ -955,7 +1106,6 @@ export class DynamicGltfLoader {
|
|
|
955
1106
|
}
|
|
956
1107
|
|
|
957
1108
|
createVisibilityMaterial(material) {
|
|
958
|
-
// Применяем шейдер напрямую к оригинальному материалу
|
|
959
1109
|
material.onBeforeCompile = (shader) => {
|
|
960
1110
|
shader.vertexShader = shader.vertexShader.replace(
|
|
961
1111
|
"#include <common>",
|
|
@@ -990,8 +1140,6 @@ export class DynamicGltfLoader {
|
|
|
990
1140
|
`
|
|
991
1141
|
);
|
|
992
1142
|
};
|
|
993
|
-
|
|
994
|
-
// Принудительная перекомпиляция материала
|
|
995
1143
|
material.needsUpdate = true;
|
|
996
1144
|
|
|
997
1145
|
return material;
|
|
@@ -1026,7 +1174,6 @@ export class DynamicGltfLoader {
|
|
|
1026
1174
|
});
|
|
1027
1175
|
this.nodes.clear();
|
|
1028
1176
|
|
|
1029
|
-
// Clear all loaded meshes
|
|
1030
1177
|
this.loadedMeshes.forEach((mesh) => {
|
|
1031
1178
|
if (mesh.geometry) mesh.geometry.dispose();
|
|
1032
1179
|
if (mesh.material) {
|
|
@@ -1162,7 +1309,7 @@ export class DynamicGltfLoader {
|
|
|
1162
1309
|
}
|
|
1163
1310
|
this.handleToObjects.get(fullHandle).add(object);
|
|
1164
1311
|
|
|
1165
|
-
object.userData.structureId = object.userData.handle.split(
|
|
1312
|
+
object.userData.structureId = object.userData.handle.split(STRUCTURE_ID_SEPARATOR)[0];
|
|
1166
1313
|
}
|
|
1167
1314
|
|
|
1168
1315
|
getObjectsByHandle(handle) {
|
|
@@ -1237,11 +1384,32 @@ export class DynamicGltfLoader {
|
|
|
1237
1384
|
this.originalObjects.add(object);
|
|
1238
1385
|
}
|
|
1239
1386
|
|
|
1240
|
-
|
|
1387
|
+
yieldToUI() {
|
|
1388
|
+
return new Promise((resolve) => {
|
|
1389
|
+
requestAnimationFrame(() => {
|
|
1390
|
+
setTimeout(resolve, 0);
|
|
1391
|
+
});
|
|
1392
|
+
});
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
async optimizeScene() {
|
|
1396
|
+
console.log("Starting scene optimization...");
|
|
1397
|
+
this.dispatchEvent("optimizationprogress", {
|
|
1398
|
+
phase: "start",
|
|
1399
|
+
progress: 0,
|
|
1400
|
+
message: "Starting optimization...",
|
|
1401
|
+
});
|
|
1402
|
+
|
|
1241
1403
|
this.originalObjects.clear();
|
|
1242
1404
|
this.originalObjectsToSelection.clear();
|
|
1243
1405
|
const structureGroups = new Map();
|
|
1244
1406
|
|
|
1407
|
+
this.dispatchEvent("optimizationprogress", {
|
|
1408
|
+
phase: "collecting",
|
|
1409
|
+
progress: 5,
|
|
1410
|
+
message: "Collecting scene objects...",
|
|
1411
|
+
});
|
|
1412
|
+
|
|
1245
1413
|
this.scene.traverse((object) => {
|
|
1246
1414
|
if (object.userData.structureId) {
|
|
1247
1415
|
const structureId = object.userData.structureId;
|
|
@@ -1274,32 +1442,78 @@ export class DynamicGltfLoader {
|
|
|
1274
1442
|
}
|
|
1275
1443
|
});
|
|
1276
1444
|
|
|
1445
|
+
let processedGroups = 0;
|
|
1446
|
+
const totalGroups = structureGroups.size;
|
|
1447
|
+
|
|
1448
|
+
this.dispatchEvent("optimizationprogress", {
|
|
1449
|
+
phase: "merging",
|
|
1450
|
+
progress: 10,
|
|
1451
|
+
message: `Merging ${totalGroups} structure groups...`,
|
|
1452
|
+
current: 0,
|
|
1453
|
+
total: totalGroups,
|
|
1454
|
+
});
|
|
1455
|
+
|
|
1277
1456
|
for (const group of structureGroups.values()) {
|
|
1278
1457
|
group.mapMeshes.clear();
|
|
1279
1458
|
group.mapLines.clear();
|
|
1280
1459
|
group.mapLineSegments.clear();
|
|
1281
1460
|
group.mapPoints.clear();
|
|
1282
1461
|
|
|
1283
|
-
this.mergeMeshGroups(group.meshes, group.rootGroup);
|
|
1284
|
-
this.
|
|
1285
|
-
|
|
1286
|
-
this.
|
|
1462
|
+
await this.mergeMeshGroups(group.meshes, group.rootGroup);
|
|
1463
|
+
await this.yieldToUI();
|
|
1464
|
+
|
|
1465
|
+
await this.mergeLineGroups(group.lines, group.rootGroup);
|
|
1466
|
+
await this.yieldToUI();
|
|
1467
|
+
|
|
1468
|
+
await this.mergeLineSegmentGroups(group.lineSegments, group.rootGroup);
|
|
1469
|
+
await this.yieldToUI();
|
|
1470
|
+
|
|
1471
|
+
await this.mergePointsGroups(group.points, group.rootGroup);
|
|
1472
|
+
|
|
1473
|
+
processedGroups++;
|
|
1474
|
+
const progress = 10 + Math.round((processedGroups / totalGroups) * 80);
|
|
1475
|
+
|
|
1476
|
+
this.dispatchEvent("optimizationprogress", {
|
|
1477
|
+
phase: "merging",
|
|
1478
|
+
progress,
|
|
1479
|
+
message: `Processing structure ${processedGroups}/${totalGroups}...`,
|
|
1480
|
+
current: processedGroups,
|
|
1481
|
+
total: totalGroups,
|
|
1482
|
+
});
|
|
1483
|
+
|
|
1484
|
+
console.log(`Optimization progress: ${processedGroups}/${totalGroups} structure groups processed (${progress}%)`);
|
|
1485
|
+
|
|
1486
|
+
await this.yieldToUI();
|
|
1287
1487
|
}
|
|
1288
1488
|
|
|
1489
|
+
this.dispatchEvent("optimizationprogress", {
|
|
1490
|
+
phase: "finalizing",
|
|
1491
|
+
progress: 95,
|
|
1492
|
+
message: "Finalizing optimization...",
|
|
1493
|
+
});
|
|
1494
|
+
|
|
1289
1495
|
this.originalObjects.forEach((obj) => {
|
|
1290
1496
|
obj.visible = false;
|
|
1291
1497
|
if (!(obj instanceof Points) && !obj.userData.isEdge) {
|
|
1292
1498
|
this.originalObjectsToSelection.add(obj);
|
|
1293
1499
|
}
|
|
1294
1500
|
});
|
|
1501
|
+
|
|
1295
1502
|
this.initializeObjectVisibility();
|
|
1296
1503
|
|
|
1297
1504
|
console.log(`Optimization complete. Total objects: ${this.maxObjectId}`);
|
|
1298
1505
|
|
|
1506
|
+
this.dispatchEvent("optimizationprogress", {
|
|
1507
|
+
phase: "complete",
|
|
1508
|
+
progress: 100,
|
|
1509
|
+
message: `Optimization complete! ${this.maxObjectId} objects processed.`,
|
|
1510
|
+
});
|
|
1511
|
+
|
|
1299
1512
|
this.dispatchEvent("update");
|
|
1300
1513
|
}
|
|
1301
1514
|
|
|
1302
|
-
mergeMeshGroups(materialGroups, rootGroup) {
|
|
1515
|
+
async mergeMeshGroups(materialGroups, rootGroup) {
|
|
1516
|
+
let processedGroups = 0;
|
|
1303
1517
|
for (const group of materialGroups) {
|
|
1304
1518
|
if (!group.material) {
|
|
1305
1519
|
console.warn("Skipping mesh group with null material");
|
|
@@ -1315,8 +1529,6 @@ export class DynamicGltfLoader {
|
|
|
1315
1529
|
|
|
1316
1530
|
for (const mesh of group.objects) {
|
|
1317
1531
|
const geometry = mesh.geometry.clone();
|
|
1318
|
-
mesh.updateWorldMatrix(true, false);
|
|
1319
|
-
geometry.applyMatrix4(mesh.matrixWorld);
|
|
1320
1532
|
|
|
1321
1533
|
const handle = mesh.userData.handle;
|
|
1322
1534
|
if (!this.objectIdToIndex.has(handle)) {
|
|
@@ -1369,6 +1581,7 @@ export class DynamicGltfLoader {
|
|
|
1369
1581
|
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
1370
1582
|
|
|
1371
1583
|
const mergedMesh = new Mesh(mergedGeometry, visibilityMaterial);
|
|
1584
|
+
mergedMesh.userData.isOptimized = true;
|
|
1372
1585
|
rootGroup.add(mergedMesh);
|
|
1373
1586
|
|
|
1374
1587
|
this.mergedMesh.add(mergedMesh);
|
|
@@ -1399,6 +1612,11 @@ export class DynamicGltfLoader {
|
|
|
1399
1612
|
this.handleToOptimizedObjects.set(handle, mergedObjects);
|
|
1400
1613
|
}
|
|
1401
1614
|
});
|
|
1615
|
+
|
|
1616
|
+
processedGroups++;
|
|
1617
|
+
if (processedGroups % 5 === 0) {
|
|
1618
|
+
await this.yieldToUI();
|
|
1619
|
+
}
|
|
1402
1620
|
} catch (error) {
|
|
1403
1621
|
console.error("Failed to merge meshes for material:", error);
|
|
1404
1622
|
group.objects.forEach((mesh) => {
|
|
@@ -1408,7 +1626,8 @@ export class DynamicGltfLoader {
|
|
|
1408
1626
|
}
|
|
1409
1627
|
}
|
|
1410
1628
|
|
|
1411
|
-
mergeLineGroups(materialGroups, rootGroup) {
|
|
1629
|
+
async mergeLineGroups(materialGroups, rootGroup) {
|
|
1630
|
+
let processedGroups = 0;
|
|
1412
1631
|
for (const group of materialGroups) {
|
|
1413
1632
|
if (group.objects.length === 0) continue;
|
|
1414
1633
|
|
|
@@ -1433,7 +1652,9 @@ export class DynamicGltfLoader {
|
|
|
1433
1652
|
const indices = [];
|
|
1434
1653
|
let vertexOffset = 0;
|
|
1435
1654
|
|
|
1655
|
+
let isEdge = false;
|
|
1436
1656
|
group.objects.forEach((line) => {
|
|
1657
|
+
isEdge = line.userData.isEdge;
|
|
1437
1658
|
const geometry = line.geometry;
|
|
1438
1659
|
const positionAttr = geometry.attributes.position;
|
|
1439
1660
|
const vertexCount = positionAttr.count;
|
|
@@ -1442,21 +1663,16 @@ export class DynamicGltfLoader {
|
|
|
1442
1663
|
if (!this.objectIdToIndex.has(handle)) {
|
|
1443
1664
|
this.objectIdToIndex.set(handle, this.maxObjectId++);
|
|
1444
1665
|
}
|
|
1445
|
-
// const objectId = this.objectIdToIndex.get(handle);
|
|
1446
1666
|
|
|
1447
1667
|
objectMapping.set(line, {
|
|
1448
1668
|
startVertexIndex: currentVertexOffset,
|
|
1449
1669
|
vertexCount,
|
|
1450
1670
|
});
|
|
1451
1671
|
currentVertexOffset += vertexCount;
|
|
1452
|
-
|
|
1453
|
-
line.updateWorldMatrix(true, false);
|
|
1454
|
-
const matrix = line.matrixWorld;
|
|
1455
1672
|
const vector = new Vector3();
|
|
1456
1673
|
|
|
1457
1674
|
for (let i = 0; i < vertexCount; i++) {
|
|
1458
1675
|
vector.fromBufferAttribute(positionAttr, i);
|
|
1459
|
-
vector.applyMatrix4(matrix);
|
|
1460
1676
|
positions[posOffset++] = vector.x;
|
|
1461
1677
|
positions[posOffset++] = vector.y;
|
|
1462
1678
|
positions[posOffset++] = vector.z;
|
|
@@ -1497,6 +1713,9 @@ export class DynamicGltfLoader {
|
|
|
1497
1713
|
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
1498
1714
|
|
|
1499
1715
|
const mergedLine = new LineSegments(geometry, visibilityMaterial);
|
|
1716
|
+
mergedLine.userData.isEdge = isEdge;
|
|
1717
|
+
mergedLine.userData.isOptimized = true;
|
|
1718
|
+
|
|
1500
1719
|
const mergedObjects = [mergedLine];
|
|
1501
1720
|
if (this.useVAO) {
|
|
1502
1721
|
this.createVAO(mergedLine);
|
|
@@ -1522,10 +1741,16 @@ export class DynamicGltfLoader {
|
|
|
1522
1741
|
this.handleToOptimizedObjects.set(handle, mergedObjects);
|
|
1523
1742
|
}
|
|
1524
1743
|
});
|
|
1744
|
+
|
|
1745
|
+
processedGroups++;
|
|
1746
|
+
if (processedGroups % 5 === 0) {
|
|
1747
|
+
await this.yieldToUI();
|
|
1748
|
+
}
|
|
1525
1749
|
}
|
|
1526
1750
|
}
|
|
1527
1751
|
|
|
1528
|
-
mergeLineSegmentGroups(materialGroups, rootGroup) {
|
|
1752
|
+
async mergeLineSegmentGroups(materialGroups, rootGroup) {
|
|
1753
|
+
let processedGroups = 0;
|
|
1529
1754
|
for (const group of materialGroups) {
|
|
1530
1755
|
if (!group.material) {
|
|
1531
1756
|
console.warn("Skipping line segment group with null material");
|
|
@@ -1538,11 +1763,11 @@ export class DynamicGltfLoader {
|
|
|
1538
1763
|
const handles = new Set();
|
|
1539
1764
|
const objectMapping = new Map();
|
|
1540
1765
|
let currentVertexOffset = 0;
|
|
1766
|
+
let isEdge = false;
|
|
1541
1767
|
|
|
1542
1768
|
for (const line of group.objects) {
|
|
1769
|
+
isEdge = line.userData.isEdge;
|
|
1543
1770
|
const geometry = line.geometry.clone();
|
|
1544
|
-
line.updateWorldMatrix(true, false);
|
|
1545
|
-
geometry.applyMatrix4(line.matrixWorld);
|
|
1546
1771
|
|
|
1547
1772
|
const handle = line.userData.handle;
|
|
1548
1773
|
if (!this.objectIdToIndex.has(handle)) {
|
|
@@ -1585,6 +1810,8 @@ export class DynamicGltfLoader {
|
|
|
1585
1810
|
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
1586
1811
|
|
|
1587
1812
|
const mergedLine = new LineSegments(mergedGeometry, visibilityMaterial);
|
|
1813
|
+
mergedLine.userData.isEdge = isEdge;
|
|
1814
|
+
mergedLine.userData.isOptimized = true;
|
|
1588
1815
|
|
|
1589
1816
|
if (this.useVAO) {
|
|
1590
1817
|
this.createVAO(mergedLine);
|
|
@@ -1618,6 +1845,11 @@ export class DynamicGltfLoader {
|
|
|
1618
1845
|
this.handleToOptimizedObjects.set(handle, mergedObjects);
|
|
1619
1846
|
}
|
|
1620
1847
|
});
|
|
1848
|
+
|
|
1849
|
+
processedGroups++;
|
|
1850
|
+
if (processedGroups % 5 === 0) {
|
|
1851
|
+
await this.yieldToUI();
|
|
1852
|
+
}
|
|
1621
1853
|
} catch (error) {
|
|
1622
1854
|
console.warn("Failed to merge line segments for material:", error);
|
|
1623
1855
|
group.objects.forEach((line) => {
|
|
@@ -1627,7 +1859,8 @@ export class DynamicGltfLoader {
|
|
|
1627
1859
|
}
|
|
1628
1860
|
}
|
|
1629
1861
|
|
|
1630
|
-
mergePointsGroups(materialGroups, rootGroup) {
|
|
1862
|
+
async mergePointsGroups(materialGroups, rootGroup) {
|
|
1863
|
+
let processedGroups = 0;
|
|
1631
1864
|
for (const group of materialGroups) {
|
|
1632
1865
|
if (!group.material) {
|
|
1633
1866
|
console.warn("Skipping points group with null material");
|
|
@@ -1641,8 +1874,6 @@ export class DynamicGltfLoader {
|
|
|
1641
1874
|
|
|
1642
1875
|
for (const points of group.objects) {
|
|
1643
1876
|
const geometry = points.geometry.clone();
|
|
1644
|
-
points.updateWorldMatrix(true, false);
|
|
1645
|
-
geometry.applyMatrix4(points.matrixWorld);
|
|
1646
1877
|
geometries.push(geometry);
|
|
1647
1878
|
optimizedObjects.push(points);
|
|
1648
1879
|
handles.add(points.userData.handle);
|
|
@@ -1653,6 +1884,7 @@ export class DynamicGltfLoader {
|
|
|
1653
1884
|
if (geometries.length > 0) {
|
|
1654
1885
|
const mergedGeometry = mergeGeometries(geometries, false);
|
|
1655
1886
|
const mergedPoints = new Points(mergedGeometry, group.material);
|
|
1887
|
+
mergedPoints.userData.isOptimized = true;
|
|
1656
1888
|
|
|
1657
1889
|
if (this.useVAO) {
|
|
1658
1890
|
this.createVAO(mergedPoints);
|
|
@@ -1678,6 +1910,11 @@ export class DynamicGltfLoader {
|
|
|
1678
1910
|
this.handleToOptimizedObjects.set(handle, mergedObjects);
|
|
1679
1911
|
}
|
|
1680
1912
|
});
|
|
1913
|
+
|
|
1914
|
+
processedGroups++;
|
|
1915
|
+
if (processedGroups % 5 === 0) {
|
|
1916
|
+
await this.yieldToUI();
|
|
1917
|
+
}
|
|
1681
1918
|
} catch (error) {
|
|
1682
1919
|
console.warn("Failed to merge points for material:", error);
|
|
1683
1920
|
group.objects.forEach((points) => {
|
|
@@ -1700,7 +1937,6 @@ export class DynamicGltfLoader {
|
|
|
1700
1937
|
|
|
1701
1938
|
lineSegmentsArray.forEach((segment) => {
|
|
1702
1939
|
const clonedGeometry = segment.geometry.clone();
|
|
1703
|
-
segment.updateWorldMatrix(true, false);
|
|
1704
1940
|
clonedGeometry.applyMatrix4(segment.matrixWorld);
|
|
1705
1941
|
|
|
1706
1942
|
if (hasNormals && !clonedGeometry.attributes.normal) {
|
|
@@ -1741,6 +1977,7 @@ export class DynamicGltfLoader {
|
|
|
1741
1977
|
|
|
1742
1978
|
const mergedLine = new LineSegments(finalGeometry, material);
|
|
1743
1979
|
mergedLine.userData.structureId = structureId;
|
|
1980
|
+
mergedLine.userData.isOptimized = true;
|
|
1744
1981
|
rootGroup.add(mergedLine);
|
|
1745
1982
|
this.mergedLineSegments.add(mergedLine);
|
|
1746
1983
|
|