@inweb/viewer-three 27.2.0 → 27.2.1
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/dist/viewer-three.js +72 -21
- package/dist/viewer-three.js.map +1 -1
- package/dist/viewer-three.min.js +3 -3
- package/dist/viewer-three.module.js +71 -21
- package/dist/viewer-three.module.js.map +1 -1
- package/package.json +5 -5
- package/src/Viewer/components/CameraComponent.ts +1 -1
- package/src/Viewer/components/InfoComponent.ts +5 -1
- package/src/Viewer/loaders/DynamicGltfLoader/DynamicGltfLoader.js +68 -21
- package/src/Viewer/loaders/DynamicGltfLoader/DynamicModelImpl.ts +1 -0
- package/src/Viewer/models/ModelImpl.ts +1 -0
|
@@ -2499,7 +2499,7 @@ class CameraComponent {
|
|
|
2499
2499
|
camera = object;
|
|
2500
2500
|
});
|
|
2501
2501
|
if (camera) {
|
|
2502
|
-
camera.isDefaultCamera = true;
|
|
2502
|
+
camera.userData.isDefaultCamera = true;
|
|
2503
2503
|
camera.scale.set(1, 1, 1);
|
|
2504
2504
|
this.switchCamera(camera);
|
|
2505
2505
|
const mode = this.getCameraMode(camera);
|
|
@@ -2703,6 +2703,7 @@ class InfoComponent {
|
|
|
2703
2703
|
this.viewer.info.optimizedScene.edges = 0;
|
|
2704
2704
|
this.viewer.info.memory.geometries = 0;
|
|
2705
2705
|
this.viewer.info.memory.geometryBytes = 0;
|
|
2706
|
+
this.viewer.info.memory.optimizedGeometryBytes = 0;
|
|
2706
2707
|
this.viewer.info.memory.textures = 0;
|
|
2707
2708
|
this.viewer.info.memory.textureBytes = 0;
|
|
2708
2709
|
this.viewer.info.memory.materials = 0;
|
|
@@ -2739,6 +2740,7 @@ class InfoComponent {
|
|
|
2739
2740
|
this.viewer.info.optimizedScene.edges += info.optimizedScene.edges;
|
|
2740
2741
|
this.viewer.info.memory.geometries += info.memory.geometries;
|
|
2741
2742
|
this.viewer.info.memory.geometryBytes += info.memory.geometryBytes;
|
|
2743
|
+
this.viewer.info.memory.optimizedGeometryBytes += info.memory.optimizedGeometryBytes;
|
|
2742
2744
|
this.viewer.info.memory.textures += info.memory.textures;
|
|
2743
2745
|
this.viewer.info.memory.textureBytes += info.memory.textureBytes;
|
|
2744
2746
|
this.viewer.info.memory.materials += info.memory.materials;
|
|
@@ -2749,7 +2751,9 @@ class InfoComponent {
|
|
|
2749
2751
|
this.viewer.info.performance.loadTime += performance.now() - this.startTime;
|
|
2750
2752
|
console.log("Number of objects:", info.scene.objects);
|
|
2751
2753
|
console.log("Number of objects after optimization:", info.optimizedScene.objects);
|
|
2752
|
-
console.log("
|
|
2754
|
+
console.log("Geometry size:", info.memory.geometryBytes / (1024 * 1024), "MB");
|
|
2755
|
+
console.log("Optimized geometry size:", info.memory.optimizedGeometryBytes / (1024 * 1024), "MB");
|
|
2756
|
+
console.log("Estimated GPU used:", info.memory.totalEstimatedGpuBytes / (1024 * 1024), "MB");
|
|
2753
2757
|
console.log("File load time:", this.viewer.info.performance.loadTime, "ms");
|
|
2754
2758
|
};
|
|
2755
2759
|
this.resize = () => {
|
|
@@ -3492,6 +3496,7 @@ class ModelImpl {
|
|
|
3492
3496
|
info.scene.edges = Math.floor(totalEdges);
|
|
3493
3497
|
info.memory.geometries = geometries.size;
|
|
3494
3498
|
info.memory.geometryBytes = geometryBytes;
|
|
3499
|
+
info.memory.optimizedGeometryBytes = 0;
|
|
3495
3500
|
info.memory.textures = textures.size;
|
|
3496
3501
|
info.memory.textureBytes = Math.floor(textureBytes);
|
|
3497
3502
|
info.memory.materials = materials.size;
|
|
@@ -3664,6 +3669,7 @@ class DynamicModelImpl extends ModelImpl {
|
|
|
3664
3669
|
info.optimizedScene.edges = stats.scene.afterOptimization.edges;
|
|
3665
3670
|
info.memory.geometries = stats.memory.geometries.count;
|
|
3666
3671
|
info.memory.geometryBytes = stats.memory.geometries.bytes;
|
|
3672
|
+
info.memory.optimizedGeometryBytes = stats.memory.geometries.optimizedBytes;
|
|
3667
3673
|
info.memory.textures = stats.memory.textures.count;
|
|
3668
3674
|
info.memory.materials = stats.memory.materials.count;
|
|
3669
3675
|
info.memory.totalEstimatedGpuBytes = stats.memory.totalEstimatedGpuBytes;
|
|
@@ -4335,11 +4341,14 @@ class DynamicGltfLoader {
|
|
|
4335
4341
|
this.structures = [];
|
|
4336
4342
|
this.structureRoots = new Map();
|
|
4337
4343
|
this.memoryLimit = this.getAvailableMemory();
|
|
4344
|
+
this.optimizationMemoryMultiplier = 5;
|
|
4345
|
+
this.memoryEstimationFactor = 1.7;
|
|
4338
4346
|
this.loadedGeometrySize = 0;
|
|
4339
4347
|
this.geometryCache = new Map();
|
|
4340
4348
|
this.materialCache = new Map();
|
|
4341
4349
|
this.textureCache = new Map();
|
|
4342
4350
|
this.currentMemoryUsage = 0;
|
|
4351
|
+
this.pendingMemoryUsage = 0;
|
|
4343
4352
|
this.updateMemoryIndicator();
|
|
4344
4353
|
this.loadedMaterials = new Map();
|
|
4345
4354
|
this.abortController = new AbortController();
|
|
@@ -4395,7 +4404,7 @@ class DynamicGltfLoader {
|
|
|
4395
4404
|
} catch (error) {
|
|
4396
4405
|
console.warn("Error detecting available memory:", error);
|
|
4397
4406
|
}
|
|
4398
|
-
return memoryLimit
|
|
4407
|
+
return memoryLimit;
|
|
4399
4408
|
}
|
|
4400
4409
|
getAbortController() {
|
|
4401
4410
|
return this.abortController;
|
|
@@ -4403,9 +4412,26 @@ class DynamicGltfLoader {
|
|
|
4403
4412
|
abortLoading() {
|
|
4404
4413
|
this.abortController.abort();
|
|
4405
4414
|
}
|
|
4415
|
+
getOptimizedGeometrySize() {
|
|
4416
|
+
let total = 0;
|
|
4417
|
+
const addSize = (obj) => {
|
|
4418
|
+
if (obj && obj.geometry) total += this.estimateGeometrySize(obj);
|
|
4419
|
+
};
|
|
4420
|
+
this.mergedMesh?.forEach(addSize);
|
|
4421
|
+
this.mergedLines?.forEach(addSize);
|
|
4422
|
+
this.mergedLineSegments?.forEach(addSize);
|
|
4423
|
+
this.mergedPoints?.forEach(addSize);
|
|
4424
|
+
return total;
|
|
4425
|
+
}
|
|
4406
4426
|
updateMemoryIndicator() {
|
|
4427
|
+
const optimizedUsage = this.getOptimizedGeometrySize();
|
|
4428
|
+
const totalUsage = this.currentMemoryUsage + optimizedUsage;
|
|
4429
|
+
const totalUsageEstimate = Math.round(totalUsage * this.memoryEstimationFactor);
|
|
4407
4430
|
this.dispatchEvent("geometrymemory", {
|
|
4408
4431
|
currentUsage: this.currentMemoryUsage,
|
|
4432
|
+
optimizedUsage,
|
|
4433
|
+
totalUsage,
|
|
4434
|
+
totalUsageEstimate,
|
|
4409
4435
|
limit: this.memoryLimit,
|
|
4410
4436
|
});
|
|
4411
4437
|
}
|
|
@@ -4457,10 +4483,13 @@ class DynamicGltfLoader {
|
|
|
4457
4483
|
for (const geo of geometries) {
|
|
4458
4484
|
currentMemoryUsage += geo.size;
|
|
4459
4485
|
}
|
|
4460
|
-
|
|
4461
|
-
|
|
4486
|
+
const effectiveLimitForEviction = this.memoryLimit / this.memoryEstimationFactor;
|
|
4487
|
+
if (currentMemoryUsage > effectiveLimitForEviction) {
|
|
4488
|
+
console.log(
|
|
4489
|
+
`Memory usage (${Math.round((currentMemoryUsage * this.memoryEstimationFactor) / (1024 * 1024))}MB est.) exceeds limit`
|
|
4490
|
+
);
|
|
4462
4491
|
for (const geo of geometries) {
|
|
4463
|
-
if (currentMemoryUsage <=
|
|
4492
|
+
if (currentMemoryUsage <= effectiveLimitForEviction) break;
|
|
4464
4493
|
if (this.abortController.signal.aborted) {
|
|
4465
4494
|
throw new DOMException("Loading aborted", "AbortError");
|
|
4466
4495
|
}
|
|
@@ -4544,7 +4573,9 @@ class DynamicGltfLoader {
|
|
|
4544
4573
|
}
|
|
4545
4574
|
const materialCount = uniqueMaterialIds.size;
|
|
4546
4575
|
const textureCount = uniqueTextureIds.size;
|
|
4547
|
-
const
|
|
4576
|
+
const optimizedUsageBytes = this.getOptimizedGeometrySize();
|
|
4577
|
+
const totalUsageBytes = geometryMemoryBytes + optimizedUsageBytes;
|
|
4578
|
+
const estimatedGpuMemoryBytes = Math.round(totalUsageBytes * this.memoryEstimationFactor);
|
|
4548
4579
|
if (!this._webglInfoCache) {
|
|
4549
4580
|
try {
|
|
4550
4581
|
const gl = this.renderer.getContext();
|
|
@@ -4581,7 +4612,12 @@ class DynamicGltfLoader {
|
|
|
4581
4612
|
},
|
|
4582
4613
|
},
|
|
4583
4614
|
memory: {
|
|
4584
|
-
geometries: {
|
|
4615
|
+
geometries: {
|
|
4616
|
+
count: geometryCount,
|
|
4617
|
+
bytes: geometryMemoryBytes,
|
|
4618
|
+
optimizedBytes: optimizedUsageBytes,
|
|
4619
|
+
totalRawBytes: totalUsageBytes,
|
|
4620
|
+
},
|
|
4585
4621
|
textures: { count: textureCount },
|
|
4586
4622
|
materials: { count: materialCount },
|
|
4587
4623
|
totalEstimatedGpuBytes: estimatedGpuMemoryBytes,
|
|
@@ -4593,9 +4629,12 @@ class DynamicGltfLoader {
|
|
|
4593
4629
|
},
|
|
4594
4630
|
};
|
|
4595
4631
|
}
|
|
4596
|
-
async loadNode(nodeId, onLoadFinishCb) {
|
|
4632
|
+
async loadNode(nodeId, onLoadFinishCb, reservedEstimatedSize = 0) {
|
|
4597
4633
|
const node = this.nodes.get(nodeId);
|
|
4598
|
-
if (!node || node.loaded || node.loading)
|
|
4634
|
+
if (!node || node.loaded || node.loading) {
|
|
4635
|
+
this.pendingMemoryUsage = Math.max(0, this.pendingMemoryUsage - reservedEstimatedSize);
|
|
4636
|
+
return;
|
|
4637
|
+
}
|
|
4599
4638
|
node.loading = true;
|
|
4600
4639
|
const meshDef = node.structure.getJson().meshes[node.meshIndex];
|
|
4601
4640
|
try {
|
|
@@ -4678,6 +4717,7 @@ class DynamicGltfLoader {
|
|
|
4678
4717
|
if (bufferRequests.length === 0) {
|
|
4679
4718
|
node.loaded = true;
|
|
4680
4719
|
node.loading = false;
|
|
4720
|
+
this.pendingMemoryUsage = Math.max(0, this.pendingMemoryUsage - reservedEstimatedSize);
|
|
4681
4721
|
return;
|
|
4682
4722
|
}
|
|
4683
4723
|
bufferRequests.sort((a, b) => a.offset - b.offset);
|
|
@@ -4789,6 +4829,7 @@ class DynamicGltfLoader {
|
|
|
4789
4829
|
}
|
|
4790
4830
|
node.loaded = true;
|
|
4791
4831
|
node.loading = false;
|
|
4832
|
+
this.pendingMemoryUsage = Math.max(0, this.pendingMemoryUsage - reservedEstimatedSize);
|
|
4792
4833
|
const geometrySize = this.estimateGeometrySize(node.object);
|
|
4793
4834
|
this.geometryCache.set(node.object.uuid, geometrySize);
|
|
4794
4835
|
this.currentMemoryUsage += geometrySize;
|
|
@@ -4797,6 +4838,7 @@ class DynamicGltfLoader {
|
|
|
4797
4838
|
}
|
|
4798
4839
|
} catch (error) {
|
|
4799
4840
|
node.loading = false;
|
|
4841
|
+
this.pendingMemoryUsage = Math.max(0, this.pendingMemoryUsage - reservedEstimatedSize);
|
|
4800
4842
|
if (error.name === "AbortError") {
|
|
4801
4843
|
return;
|
|
4802
4844
|
}
|
|
@@ -5012,15 +5054,18 @@ class DynamicGltfLoader {
|
|
|
5012
5054
|
let loadedCount = 0;
|
|
5013
5055
|
let lastLoadedCount = 0;
|
|
5014
5056
|
const totalNodes = nodesToLoad.length;
|
|
5057
|
+
const progressTotal = { value: totalNodes };
|
|
5015
5058
|
const loadProgress = async () => {
|
|
5016
5059
|
loadedCount++;
|
|
5060
|
+
const total = progressTotal.value;
|
|
5061
|
+
const percentage = total > 0 ? Math.min(100, Math.round((loadedCount / total) * 100)) : 0;
|
|
5017
5062
|
if (loadedCount - lastLoadedCount > 1000) {
|
|
5018
5063
|
lastLoadedCount = loadedCount;
|
|
5019
5064
|
this.updateMemoryIndicator();
|
|
5020
5065
|
this.dispatchEvent("geometryprogress", {
|
|
5021
|
-
percentage
|
|
5066
|
+
percentage,
|
|
5022
5067
|
loaded: loadedCount,
|
|
5023
|
-
total
|
|
5068
|
+
total,
|
|
5024
5069
|
});
|
|
5025
5070
|
this.dispatchEvent("update");
|
|
5026
5071
|
await new Promise((resolve) => {
|
|
@@ -5030,20 +5075,22 @@ class DynamicGltfLoader {
|
|
|
5030
5075
|
};
|
|
5031
5076
|
try {
|
|
5032
5077
|
const loadOperations = [];
|
|
5078
|
+
let memoryLimitReached = false;
|
|
5033
5079
|
for (const nodeId of nodesToLoad) {
|
|
5034
5080
|
if (this.abortController.signal.aborted) {
|
|
5035
5081
|
throw new DOMException("Loading aborted", "AbortError");
|
|
5036
5082
|
}
|
|
5037
5083
|
const estimatedSize = await this.estimateNodeSize(nodeId);
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5084
|
+
const estimated = Number(estimatedSize) || 0;
|
|
5085
|
+
const effectiveLimit = this.memoryLimit / this.optimizationMemoryMultiplier / this.memoryEstimationFactor;
|
|
5086
|
+
if (this.currentMemoryUsage + this.pendingMemoryUsage + estimated > effectiveLimit) {
|
|
5087
|
+
memoryLimitReached = true;
|
|
5088
|
+
progressTotal.value = loadOperations.length;
|
|
5089
|
+
console.log(`Memory limit reached after scheduling ${loadOperations.length} nodes`);
|
|
5090
|
+
break;
|
|
5045
5091
|
}
|
|
5046
|
-
|
|
5092
|
+
this.pendingMemoryUsage += estimated;
|
|
5093
|
+
loadOperations.push(this.loadNode(nodeId, loadProgress, estimated));
|
|
5047
5094
|
}
|
|
5048
5095
|
for (const structure of this.structures) {
|
|
5049
5096
|
loadOperations.push(structure.flushBufferRequests());
|
|
@@ -5051,7 +5098,8 @@ class DynamicGltfLoader {
|
|
|
5051
5098
|
await Promise.all(loadOperations);
|
|
5052
5099
|
this.dispatchEvent("geometryend", {
|
|
5053
5100
|
totalLoaded: loadedCount,
|
|
5054
|
-
totalNodes,
|
|
5101
|
+
totalNodes: progressTotal.value,
|
|
5102
|
+
memoryLimitReached,
|
|
5055
5103
|
});
|
|
5056
5104
|
return loadedCount;
|
|
5057
5105
|
} catch (error) {
|
|
@@ -5361,6 +5409,7 @@ class DynamicGltfLoader {
|
|
|
5361
5409
|
this.transformedGeometries.clear();
|
|
5362
5410
|
this.totalLoadedObjects = 0;
|
|
5363
5411
|
this.currentMemoryUsage = 0;
|
|
5412
|
+
this.pendingMemoryUsage = 0;
|
|
5364
5413
|
this.loadedGeometrySize = 0;
|
|
5365
5414
|
this.abortController = new AbortController();
|
|
5366
5415
|
this.updateMemoryIndicator();
|
|
@@ -5567,6 +5616,7 @@ class DynamicGltfLoader {
|
|
|
5567
5616
|
progress: 100,
|
|
5568
5617
|
message: `Optimization complete! ${this.maxObjectId} objects processed.`,
|
|
5569
5618
|
});
|
|
5619
|
+
this.updateMemoryIndicator();
|
|
5570
5620
|
this.dispatchEvent("update");
|
|
5571
5621
|
}
|
|
5572
5622
|
async mergeMeshGroups(materialGroups, rootGroup) {
|