@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
package/dist/viewer-three.js
CHANGED
|
@@ -572,6 +572,7 @@
|
|
|
572
572
|
this.memory = {
|
|
573
573
|
geometries: 0,
|
|
574
574
|
geometryBytes: 0,
|
|
575
|
+
optimizedGeometryBytes: 0,
|
|
575
576
|
textures: 0,
|
|
576
577
|
textureBytes: 0,
|
|
577
578
|
materials: 0,
|
|
@@ -36101,7 +36102,7 @@ void main() {
|
|
|
36101
36102
|
camera = object;
|
|
36102
36103
|
});
|
|
36103
36104
|
if (camera) {
|
|
36104
|
-
camera.isDefaultCamera = true;
|
|
36105
|
+
camera.userData.isDefaultCamera = true;
|
|
36105
36106
|
camera.scale.set(1, 1, 1);
|
|
36106
36107
|
this.switchCamera(camera);
|
|
36107
36108
|
const mode = this.getCameraMode(camera);
|
|
@@ -36305,6 +36306,7 @@ void main() {
|
|
|
36305
36306
|
this.viewer.info.optimizedScene.edges = 0;
|
|
36306
36307
|
this.viewer.info.memory.geometries = 0;
|
|
36307
36308
|
this.viewer.info.memory.geometryBytes = 0;
|
|
36309
|
+
this.viewer.info.memory.optimizedGeometryBytes = 0;
|
|
36308
36310
|
this.viewer.info.memory.textures = 0;
|
|
36309
36311
|
this.viewer.info.memory.textureBytes = 0;
|
|
36310
36312
|
this.viewer.info.memory.materials = 0;
|
|
@@ -36341,6 +36343,7 @@ void main() {
|
|
|
36341
36343
|
this.viewer.info.optimizedScene.edges += info.optimizedScene.edges;
|
|
36342
36344
|
this.viewer.info.memory.geometries += info.memory.geometries;
|
|
36343
36345
|
this.viewer.info.memory.geometryBytes += info.memory.geometryBytes;
|
|
36346
|
+
this.viewer.info.memory.optimizedGeometryBytes += info.memory.optimizedGeometryBytes;
|
|
36344
36347
|
this.viewer.info.memory.textures += info.memory.textures;
|
|
36345
36348
|
this.viewer.info.memory.textureBytes += info.memory.textureBytes;
|
|
36346
36349
|
this.viewer.info.memory.materials += info.memory.materials;
|
|
@@ -36351,7 +36354,9 @@ void main() {
|
|
|
36351
36354
|
this.viewer.info.performance.loadTime += performance.now() - this.startTime;
|
|
36352
36355
|
console.log("Number of objects:", info.scene.objects);
|
|
36353
36356
|
console.log("Number of objects after optimization:", info.optimizedScene.objects);
|
|
36354
|
-
console.log("
|
|
36357
|
+
console.log("Geometry size:", info.memory.geometryBytes / (1024 * 1024), "MB");
|
|
36358
|
+
console.log("Optimized geometry size:", info.memory.optimizedGeometryBytes / (1024 * 1024), "MB");
|
|
36359
|
+
console.log("Estimated GPU used:", info.memory.totalEstimatedGpuBytes / (1024 * 1024), "MB");
|
|
36355
36360
|
console.log("File load time:", this.viewer.info.performance.loadTime, "ms");
|
|
36356
36361
|
};
|
|
36357
36362
|
this.resize = () => {
|
|
@@ -37733,6 +37738,7 @@ void main() {
|
|
|
37733
37738
|
info.scene.edges = Math.floor(totalEdges);
|
|
37734
37739
|
info.memory.geometries = geometries.size;
|
|
37735
37740
|
info.memory.geometryBytes = geometryBytes;
|
|
37741
|
+
info.memory.optimizedGeometryBytes = 0;
|
|
37736
37742
|
info.memory.textures = textures.size;
|
|
37737
37743
|
info.memory.textureBytes = Math.floor(textureBytes);
|
|
37738
37744
|
info.memory.materials = materials.size;
|
|
@@ -37905,6 +37911,7 @@ void main() {
|
|
|
37905
37911
|
info.optimizedScene.edges = stats.scene.afterOptimization.edges;
|
|
37906
37912
|
info.memory.geometries = stats.memory.geometries.count;
|
|
37907
37913
|
info.memory.geometryBytes = stats.memory.geometries.bytes;
|
|
37914
|
+
info.memory.optimizedGeometryBytes = stats.memory.geometries.optimizedBytes;
|
|
37908
37915
|
info.memory.textures = stats.memory.textures.count;
|
|
37909
37916
|
info.memory.materials = stats.memory.materials.count;
|
|
37910
37917
|
info.memory.totalEstimatedGpuBytes = stats.memory.totalEstimatedGpuBytes;
|
|
@@ -38725,11 +38732,14 @@ void main() {
|
|
|
38725
38732
|
this.structures = [];
|
|
38726
38733
|
this.structureRoots = new Map();
|
|
38727
38734
|
this.memoryLimit = this.getAvailableMemory();
|
|
38735
|
+
this.optimizationMemoryMultiplier = 5;
|
|
38736
|
+
this.memoryEstimationFactor = 1.7;
|
|
38728
38737
|
this.loadedGeometrySize = 0;
|
|
38729
38738
|
this.geometryCache = new Map();
|
|
38730
38739
|
this.materialCache = new Map();
|
|
38731
38740
|
this.textureCache = new Map();
|
|
38732
38741
|
this.currentMemoryUsage = 0;
|
|
38742
|
+
this.pendingMemoryUsage = 0;
|
|
38733
38743
|
this.updateMemoryIndicator();
|
|
38734
38744
|
this.loadedMaterials = new Map();
|
|
38735
38745
|
this.abortController = new AbortController();
|
|
@@ -38785,7 +38795,7 @@ void main() {
|
|
|
38785
38795
|
} catch (error) {
|
|
38786
38796
|
console.warn("Error detecting available memory:", error);
|
|
38787
38797
|
}
|
|
38788
|
-
return memoryLimit
|
|
38798
|
+
return memoryLimit;
|
|
38789
38799
|
}
|
|
38790
38800
|
getAbortController() {
|
|
38791
38801
|
return this.abortController;
|
|
@@ -38793,9 +38803,26 @@ void main() {
|
|
|
38793
38803
|
abortLoading() {
|
|
38794
38804
|
this.abortController.abort();
|
|
38795
38805
|
}
|
|
38806
|
+
getOptimizedGeometrySize() {
|
|
38807
|
+
let total = 0;
|
|
38808
|
+
const addSize = (obj) => {
|
|
38809
|
+
if (obj && obj.geometry) total += this.estimateGeometrySize(obj);
|
|
38810
|
+
};
|
|
38811
|
+
this.mergedMesh?.forEach(addSize);
|
|
38812
|
+
this.mergedLines?.forEach(addSize);
|
|
38813
|
+
this.mergedLineSegments?.forEach(addSize);
|
|
38814
|
+
this.mergedPoints?.forEach(addSize);
|
|
38815
|
+
return total;
|
|
38816
|
+
}
|
|
38796
38817
|
updateMemoryIndicator() {
|
|
38818
|
+
const optimizedUsage = this.getOptimizedGeometrySize();
|
|
38819
|
+
const totalUsage = this.currentMemoryUsage + optimizedUsage;
|
|
38820
|
+
const totalUsageEstimate = Math.round(totalUsage * this.memoryEstimationFactor);
|
|
38797
38821
|
this.dispatchEvent("geometrymemory", {
|
|
38798
38822
|
currentUsage: this.currentMemoryUsage,
|
|
38823
|
+
optimizedUsage,
|
|
38824
|
+
totalUsage,
|
|
38825
|
+
totalUsageEstimate,
|
|
38799
38826
|
limit: this.memoryLimit,
|
|
38800
38827
|
});
|
|
38801
38828
|
}
|
|
@@ -38847,10 +38874,13 @@ void main() {
|
|
|
38847
38874
|
for (const geo of geometries) {
|
|
38848
38875
|
currentMemoryUsage += geo.size;
|
|
38849
38876
|
}
|
|
38850
|
-
|
|
38851
|
-
|
|
38877
|
+
const effectiveLimitForEviction = this.memoryLimit / this.memoryEstimationFactor;
|
|
38878
|
+
if (currentMemoryUsage > effectiveLimitForEviction) {
|
|
38879
|
+
console.log(
|
|
38880
|
+
`Memory usage (${Math.round((currentMemoryUsage * this.memoryEstimationFactor) / (1024 * 1024))}MB est.) exceeds limit`
|
|
38881
|
+
);
|
|
38852
38882
|
for (const geo of geometries) {
|
|
38853
|
-
if (currentMemoryUsage <=
|
|
38883
|
+
if (currentMemoryUsage <= effectiveLimitForEviction) break;
|
|
38854
38884
|
if (this.abortController.signal.aborted) {
|
|
38855
38885
|
throw new DOMException("Loading aborted", "AbortError");
|
|
38856
38886
|
}
|
|
@@ -38934,7 +38964,9 @@ void main() {
|
|
|
38934
38964
|
}
|
|
38935
38965
|
const materialCount = uniqueMaterialIds.size;
|
|
38936
38966
|
const textureCount = uniqueTextureIds.size;
|
|
38937
|
-
const
|
|
38967
|
+
const optimizedUsageBytes = this.getOptimizedGeometrySize();
|
|
38968
|
+
const totalUsageBytes = geometryMemoryBytes + optimizedUsageBytes;
|
|
38969
|
+
const estimatedGpuMemoryBytes = Math.round(totalUsageBytes * this.memoryEstimationFactor);
|
|
38938
38970
|
if (!this._webglInfoCache) {
|
|
38939
38971
|
try {
|
|
38940
38972
|
const gl = this.renderer.getContext();
|
|
@@ -38971,7 +39003,12 @@ void main() {
|
|
|
38971
39003
|
},
|
|
38972
39004
|
},
|
|
38973
39005
|
memory: {
|
|
38974
|
-
geometries: {
|
|
39006
|
+
geometries: {
|
|
39007
|
+
count: geometryCount,
|
|
39008
|
+
bytes: geometryMemoryBytes,
|
|
39009
|
+
optimizedBytes: optimizedUsageBytes,
|
|
39010
|
+
totalRawBytes: totalUsageBytes,
|
|
39011
|
+
},
|
|
38975
39012
|
textures: { count: textureCount },
|
|
38976
39013
|
materials: { count: materialCount },
|
|
38977
39014
|
totalEstimatedGpuBytes: estimatedGpuMemoryBytes,
|
|
@@ -38983,9 +39020,12 @@ void main() {
|
|
|
38983
39020
|
},
|
|
38984
39021
|
};
|
|
38985
39022
|
}
|
|
38986
|
-
async loadNode(nodeId, onLoadFinishCb) {
|
|
39023
|
+
async loadNode(nodeId, onLoadFinishCb, reservedEstimatedSize = 0) {
|
|
38987
39024
|
const node = this.nodes.get(nodeId);
|
|
38988
|
-
if (!node || node.loaded || node.loading)
|
|
39025
|
+
if (!node || node.loaded || node.loading) {
|
|
39026
|
+
this.pendingMemoryUsage = Math.max(0, this.pendingMemoryUsage - reservedEstimatedSize);
|
|
39027
|
+
return;
|
|
39028
|
+
}
|
|
38989
39029
|
node.loading = true;
|
|
38990
39030
|
const meshDef = node.structure.getJson().meshes[node.meshIndex];
|
|
38991
39031
|
try {
|
|
@@ -39068,6 +39108,7 @@ void main() {
|
|
|
39068
39108
|
if (bufferRequests.length === 0) {
|
|
39069
39109
|
node.loaded = true;
|
|
39070
39110
|
node.loading = false;
|
|
39111
|
+
this.pendingMemoryUsage = Math.max(0, this.pendingMemoryUsage - reservedEstimatedSize);
|
|
39071
39112
|
return;
|
|
39072
39113
|
}
|
|
39073
39114
|
bufferRequests.sort((a, b) => a.offset - b.offset);
|
|
@@ -39179,6 +39220,7 @@ void main() {
|
|
|
39179
39220
|
}
|
|
39180
39221
|
node.loaded = true;
|
|
39181
39222
|
node.loading = false;
|
|
39223
|
+
this.pendingMemoryUsage = Math.max(0, this.pendingMemoryUsage - reservedEstimatedSize);
|
|
39182
39224
|
const geometrySize = this.estimateGeometrySize(node.object);
|
|
39183
39225
|
this.geometryCache.set(node.object.uuid, geometrySize);
|
|
39184
39226
|
this.currentMemoryUsage += geometrySize;
|
|
@@ -39187,6 +39229,7 @@ void main() {
|
|
|
39187
39229
|
}
|
|
39188
39230
|
} catch (error) {
|
|
39189
39231
|
node.loading = false;
|
|
39232
|
+
this.pendingMemoryUsage = Math.max(0, this.pendingMemoryUsage - reservedEstimatedSize);
|
|
39190
39233
|
if (error.name === "AbortError") {
|
|
39191
39234
|
return;
|
|
39192
39235
|
}
|
|
@@ -39402,15 +39445,18 @@ void main() {
|
|
|
39402
39445
|
let loadedCount = 0;
|
|
39403
39446
|
let lastLoadedCount = 0;
|
|
39404
39447
|
const totalNodes = nodesToLoad.length;
|
|
39448
|
+
const progressTotal = { value: totalNodes };
|
|
39405
39449
|
const loadProgress = async () => {
|
|
39406
39450
|
loadedCount++;
|
|
39451
|
+
const total = progressTotal.value;
|
|
39452
|
+
const percentage = total > 0 ? Math.min(100, Math.round((loadedCount / total) * 100)) : 0;
|
|
39407
39453
|
if (loadedCount - lastLoadedCount > 1000) {
|
|
39408
39454
|
lastLoadedCount = loadedCount;
|
|
39409
39455
|
this.updateMemoryIndicator();
|
|
39410
39456
|
this.dispatchEvent("geometryprogress", {
|
|
39411
|
-
percentage
|
|
39457
|
+
percentage,
|
|
39412
39458
|
loaded: loadedCount,
|
|
39413
|
-
total
|
|
39459
|
+
total,
|
|
39414
39460
|
});
|
|
39415
39461
|
this.dispatchEvent("update");
|
|
39416
39462
|
await new Promise((resolve) => {
|
|
@@ -39420,20 +39466,22 @@ void main() {
|
|
|
39420
39466
|
};
|
|
39421
39467
|
try {
|
|
39422
39468
|
const loadOperations = [];
|
|
39469
|
+
let memoryLimitReached = false;
|
|
39423
39470
|
for (const nodeId of nodesToLoad) {
|
|
39424
39471
|
if (this.abortController.signal.aborted) {
|
|
39425
39472
|
throw new DOMException("Loading aborted", "AbortError");
|
|
39426
39473
|
}
|
|
39427
39474
|
const estimatedSize = await this.estimateNodeSize(nodeId);
|
|
39428
|
-
|
|
39429
|
-
|
|
39430
|
-
|
|
39431
|
-
|
|
39432
|
-
|
|
39433
|
-
|
|
39434
|
-
|
|
39475
|
+
const estimated = Number(estimatedSize) || 0;
|
|
39476
|
+
const effectiveLimit = this.memoryLimit / this.optimizationMemoryMultiplier / this.memoryEstimationFactor;
|
|
39477
|
+
if (this.currentMemoryUsage + this.pendingMemoryUsage + estimated > effectiveLimit) {
|
|
39478
|
+
memoryLimitReached = true;
|
|
39479
|
+
progressTotal.value = loadOperations.length;
|
|
39480
|
+
console.log(`Memory limit reached after scheduling ${loadOperations.length} nodes`);
|
|
39481
|
+
break;
|
|
39435
39482
|
}
|
|
39436
|
-
|
|
39483
|
+
this.pendingMemoryUsage += estimated;
|
|
39484
|
+
loadOperations.push(this.loadNode(nodeId, loadProgress, estimated));
|
|
39437
39485
|
}
|
|
39438
39486
|
for (const structure of this.structures) {
|
|
39439
39487
|
loadOperations.push(structure.flushBufferRequests());
|
|
@@ -39441,7 +39489,8 @@ void main() {
|
|
|
39441
39489
|
await Promise.all(loadOperations);
|
|
39442
39490
|
this.dispatchEvent("geometryend", {
|
|
39443
39491
|
totalLoaded: loadedCount,
|
|
39444
|
-
totalNodes,
|
|
39492
|
+
totalNodes: progressTotal.value,
|
|
39493
|
+
memoryLimitReached,
|
|
39445
39494
|
});
|
|
39446
39495
|
return loadedCount;
|
|
39447
39496
|
} catch (error) {
|
|
@@ -39751,6 +39800,7 @@ void main() {
|
|
|
39751
39800
|
this.transformedGeometries.clear();
|
|
39752
39801
|
this.totalLoadedObjects = 0;
|
|
39753
39802
|
this.currentMemoryUsage = 0;
|
|
39803
|
+
this.pendingMemoryUsage = 0;
|
|
39754
39804
|
this.loadedGeometrySize = 0;
|
|
39755
39805
|
this.abortController = new AbortController();
|
|
39756
39806
|
this.updateMemoryIndicator();
|
|
@@ -39957,6 +40007,7 @@ void main() {
|
|
|
39957
40007
|
progress: 100,
|
|
39958
40008
|
message: `Optimization complete! ${this.maxObjectId} objects processed.`,
|
|
39959
40009
|
});
|
|
40010
|
+
this.updateMemoryIndicator();
|
|
39960
40011
|
this.dispatchEvent("update");
|
|
39961
40012
|
}
|
|
39962
40013
|
async mergeMeshGroups(materialGroups, rootGroup) {
|