@inweb/viewer-three 27.1.9 → 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 +94 -35
- package/dist/viewer-three.js.map +1 -1
- package/dist/viewer-three.min.js +3 -3
- package/dist/viewer-three.module.js +93 -35
- package/dist/viewer-three.module.js.map +1 -1
- package/lib/Viewer/Viewer.d.ts +1 -1
- package/lib/Viewer/controls/WalkControls.d.ts +6 -1
- package/package.json +5 -5
- package/src/Viewer/Viewer.ts +1 -1
- package/src/Viewer/components/CameraComponent.ts +1 -1
- package/src/Viewer/components/InfoComponent.ts +5 -1
- package/src/Viewer/controls/WalkControls.ts +24 -15
- 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,
|
|
@@ -35108,14 +35109,19 @@ void main() {
|
|
|
35108
35109
|
super(camera, canvas);
|
|
35109
35110
|
this.EYE_HEIGHT = 1.7;
|
|
35110
35111
|
this.FAILING_DISTANCE = 2;
|
|
35111
|
-
this.
|
|
35112
|
+
this.GROUND_FOLLOWING_SKIP_FRAMES = 3;
|
|
35113
|
+
this.GROUND_FOLLOWING_SPEED = 0.4;
|
|
35112
35114
|
this.LOOK_SPEED = 0.1;
|
|
35113
35115
|
this.WALK_SPEED_DELIMITER = 4;
|
|
35114
35116
|
this.WHEEL_SPEED_DELIMITER = 15000;
|
|
35115
35117
|
this.movementSpeed = 0.1;
|
|
35116
35118
|
this.multiplier = 3;
|
|
35119
|
+
this.groundFollowingSkippedFrames = 0;
|
|
35117
35120
|
this.moveWheel = 0;
|
|
35118
35121
|
this.mouseDragOn = false;
|
|
35122
|
+
this._up = new Vector3();
|
|
35123
|
+
this._forward = new Vector3();
|
|
35124
|
+
this._sideways = new Vector3();
|
|
35119
35125
|
this.onPointerDown = (event) => {
|
|
35120
35126
|
if (event.button !== 0)
|
|
35121
35127
|
return;
|
|
@@ -35185,6 +35191,14 @@ void main() {
|
|
|
35185
35191
|
this.raycaster = new Raycaster();
|
|
35186
35192
|
this.raycaster.near = 0;
|
|
35187
35193
|
this.raycaster.far = this.EYE_HEIGHT + this.FAILING_DISTANCE;
|
|
35194
|
+
this.raycaster.params = {
|
|
35195
|
+
Mesh: {},
|
|
35196
|
+
Line: { threshold: 0 },
|
|
35197
|
+
Line2: { threshold: 0 },
|
|
35198
|
+
LOD: { threshold: 0 },
|
|
35199
|
+
Points: { threshold: 0 },
|
|
35200
|
+
Sprite: { threshold: 0 },
|
|
35201
|
+
};
|
|
35188
35202
|
this.moveKeys = new Set();
|
|
35189
35203
|
this.moveClock = new Clock();
|
|
35190
35204
|
this.quaternion = camera.quaternion.clone();
|
|
@@ -35209,16 +35223,8 @@ void main() {
|
|
|
35209
35223
|
super.dispose();
|
|
35210
35224
|
}
|
|
35211
35225
|
updateGroundFollowing() {
|
|
35212
|
-
|
|
35213
|
-
this.raycaster.set(this.object.position,
|
|
35214
|
-
this.raycaster.params = this.raycaster.params = {
|
|
35215
|
-
Mesh: {},
|
|
35216
|
-
Line: { threshold: 0 },
|
|
35217
|
-
Line2: { threshold: 0 },
|
|
35218
|
-
LOD: { threshold: 0 },
|
|
35219
|
-
Points: { threshold: 0 },
|
|
35220
|
-
Sprite: { threshold: 0 },
|
|
35221
|
-
};
|
|
35226
|
+
this._up.copy(this.camera.up).negate();
|
|
35227
|
+
this.raycaster.set(this.object.position, this._up);
|
|
35222
35228
|
const intersects = this.raycaster.intersectObjects(this.groundObjects, false);
|
|
35223
35229
|
if (intersects.length > 0) {
|
|
35224
35230
|
const groundY = intersects[0].point.y;
|
|
@@ -35229,8 +35235,8 @@ void main() {
|
|
|
35229
35235
|
update() {
|
|
35230
35236
|
let moved = false;
|
|
35231
35237
|
let upgradeGroundFollowing = false;
|
|
35232
|
-
const forward =
|
|
35233
|
-
const sideways =
|
|
35238
|
+
const forward = this._forward;
|
|
35239
|
+
const sideways = this._sideways;
|
|
35234
35240
|
if (this.moveKeys.size > 0) {
|
|
35235
35241
|
upgradeGroundFollowing = true;
|
|
35236
35242
|
const timeDelta = this.moveClock.getDelta();
|
|
@@ -35282,8 +35288,11 @@ void main() {
|
|
|
35282
35288
|
this.moveWheel += -1 * Math.sign(this.moveWheel);
|
|
35283
35289
|
moved = true;
|
|
35284
35290
|
}
|
|
35285
|
-
|
|
35291
|
+
this.groundFollowingSkippedFrames++;
|
|
35292
|
+
if (upgradeGroundFollowing && this.groundFollowingSkippedFrames >= this.GROUND_FOLLOWING_SKIP_FRAMES) {
|
|
35293
|
+
this.groundFollowingSkippedFrames = 0;
|
|
35286
35294
|
this.updateGroundFollowing();
|
|
35295
|
+
}
|
|
35287
35296
|
if (moved) {
|
|
35288
35297
|
this.dispatchEvent({ type: "change" });
|
|
35289
35298
|
}
|
|
@@ -36093,7 +36102,7 @@ void main() {
|
|
|
36093
36102
|
camera = object;
|
|
36094
36103
|
});
|
|
36095
36104
|
if (camera) {
|
|
36096
|
-
camera.isDefaultCamera = true;
|
|
36105
|
+
camera.userData.isDefaultCamera = true;
|
|
36097
36106
|
camera.scale.set(1, 1, 1);
|
|
36098
36107
|
this.switchCamera(camera);
|
|
36099
36108
|
const mode = this.getCameraMode(camera);
|
|
@@ -36297,6 +36306,7 @@ void main() {
|
|
|
36297
36306
|
this.viewer.info.optimizedScene.edges = 0;
|
|
36298
36307
|
this.viewer.info.memory.geometries = 0;
|
|
36299
36308
|
this.viewer.info.memory.geometryBytes = 0;
|
|
36309
|
+
this.viewer.info.memory.optimizedGeometryBytes = 0;
|
|
36300
36310
|
this.viewer.info.memory.textures = 0;
|
|
36301
36311
|
this.viewer.info.memory.textureBytes = 0;
|
|
36302
36312
|
this.viewer.info.memory.materials = 0;
|
|
@@ -36333,6 +36343,7 @@ void main() {
|
|
|
36333
36343
|
this.viewer.info.optimizedScene.edges += info.optimizedScene.edges;
|
|
36334
36344
|
this.viewer.info.memory.geometries += info.memory.geometries;
|
|
36335
36345
|
this.viewer.info.memory.geometryBytes += info.memory.geometryBytes;
|
|
36346
|
+
this.viewer.info.memory.optimizedGeometryBytes += info.memory.optimizedGeometryBytes;
|
|
36336
36347
|
this.viewer.info.memory.textures += info.memory.textures;
|
|
36337
36348
|
this.viewer.info.memory.textureBytes += info.memory.textureBytes;
|
|
36338
36349
|
this.viewer.info.memory.materials += info.memory.materials;
|
|
@@ -36343,7 +36354,9 @@ void main() {
|
|
|
36343
36354
|
this.viewer.info.performance.loadTime += performance.now() - this.startTime;
|
|
36344
36355
|
console.log("Number of objects:", info.scene.objects);
|
|
36345
36356
|
console.log("Number of objects after optimization:", info.optimizedScene.objects);
|
|
36346
|
-
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");
|
|
36347
36360
|
console.log("File load time:", this.viewer.info.performance.loadTime, "ms");
|
|
36348
36361
|
};
|
|
36349
36362
|
this.resize = () => {
|
|
@@ -37725,6 +37738,7 @@ void main() {
|
|
|
37725
37738
|
info.scene.edges = Math.floor(totalEdges);
|
|
37726
37739
|
info.memory.geometries = geometries.size;
|
|
37727
37740
|
info.memory.geometryBytes = geometryBytes;
|
|
37741
|
+
info.memory.optimizedGeometryBytes = 0;
|
|
37728
37742
|
info.memory.textures = textures.size;
|
|
37729
37743
|
info.memory.textureBytes = Math.floor(textureBytes);
|
|
37730
37744
|
info.memory.materials = materials.size;
|
|
@@ -37897,6 +37911,7 @@ void main() {
|
|
|
37897
37911
|
info.optimizedScene.edges = stats.scene.afterOptimization.edges;
|
|
37898
37912
|
info.memory.geometries = stats.memory.geometries.count;
|
|
37899
37913
|
info.memory.geometryBytes = stats.memory.geometries.bytes;
|
|
37914
|
+
info.memory.optimizedGeometryBytes = stats.memory.geometries.optimizedBytes;
|
|
37900
37915
|
info.memory.textures = stats.memory.textures.count;
|
|
37901
37916
|
info.memory.materials = stats.memory.materials.count;
|
|
37902
37917
|
info.memory.totalEstimatedGpuBytes = stats.memory.totalEstimatedGpuBytes;
|
|
@@ -38717,11 +38732,14 @@ void main() {
|
|
|
38717
38732
|
this.structures = [];
|
|
38718
38733
|
this.structureRoots = new Map();
|
|
38719
38734
|
this.memoryLimit = this.getAvailableMemory();
|
|
38735
|
+
this.optimizationMemoryMultiplier = 5;
|
|
38736
|
+
this.memoryEstimationFactor = 1.7;
|
|
38720
38737
|
this.loadedGeometrySize = 0;
|
|
38721
38738
|
this.geometryCache = new Map();
|
|
38722
38739
|
this.materialCache = new Map();
|
|
38723
38740
|
this.textureCache = new Map();
|
|
38724
38741
|
this.currentMemoryUsage = 0;
|
|
38742
|
+
this.pendingMemoryUsage = 0;
|
|
38725
38743
|
this.updateMemoryIndicator();
|
|
38726
38744
|
this.loadedMaterials = new Map();
|
|
38727
38745
|
this.abortController = new AbortController();
|
|
@@ -38777,7 +38795,7 @@ void main() {
|
|
|
38777
38795
|
} catch (error) {
|
|
38778
38796
|
console.warn("Error detecting available memory:", error);
|
|
38779
38797
|
}
|
|
38780
|
-
return memoryLimit
|
|
38798
|
+
return memoryLimit;
|
|
38781
38799
|
}
|
|
38782
38800
|
getAbortController() {
|
|
38783
38801
|
return this.abortController;
|
|
@@ -38785,9 +38803,26 @@ void main() {
|
|
|
38785
38803
|
abortLoading() {
|
|
38786
38804
|
this.abortController.abort();
|
|
38787
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
|
+
}
|
|
38788
38817
|
updateMemoryIndicator() {
|
|
38818
|
+
const optimizedUsage = this.getOptimizedGeometrySize();
|
|
38819
|
+
const totalUsage = this.currentMemoryUsage + optimizedUsage;
|
|
38820
|
+
const totalUsageEstimate = Math.round(totalUsage * this.memoryEstimationFactor);
|
|
38789
38821
|
this.dispatchEvent("geometrymemory", {
|
|
38790
38822
|
currentUsage: this.currentMemoryUsage,
|
|
38823
|
+
optimizedUsage,
|
|
38824
|
+
totalUsage,
|
|
38825
|
+
totalUsageEstimate,
|
|
38791
38826
|
limit: this.memoryLimit,
|
|
38792
38827
|
});
|
|
38793
38828
|
}
|
|
@@ -38839,10 +38874,13 @@ void main() {
|
|
|
38839
38874
|
for (const geo of geometries) {
|
|
38840
38875
|
currentMemoryUsage += geo.size;
|
|
38841
38876
|
}
|
|
38842
|
-
|
|
38843
|
-
|
|
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
|
+
);
|
|
38844
38882
|
for (const geo of geometries) {
|
|
38845
|
-
if (currentMemoryUsage <=
|
|
38883
|
+
if (currentMemoryUsage <= effectiveLimitForEviction) break;
|
|
38846
38884
|
if (this.abortController.signal.aborted) {
|
|
38847
38885
|
throw new DOMException("Loading aborted", "AbortError");
|
|
38848
38886
|
}
|
|
@@ -38926,7 +38964,9 @@ void main() {
|
|
|
38926
38964
|
}
|
|
38927
38965
|
const materialCount = uniqueMaterialIds.size;
|
|
38928
38966
|
const textureCount = uniqueTextureIds.size;
|
|
38929
|
-
const
|
|
38967
|
+
const optimizedUsageBytes = this.getOptimizedGeometrySize();
|
|
38968
|
+
const totalUsageBytes = geometryMemoryBytes + optimizedUsageBytes;
|
|
38969
|
+
const estimatedGpuMemoryBytes = Math.round(totalUsageBytes * this.memoryEstimationFactor);
|
|
38930
38970
|
if (!this._webglInfoCache) {
|
|
38931
38971
|
try {
|
|
38932
38972
|
const gl = this.renderer.getContext();
|
|
@@ -38963,7 +39003,12 @@ void main() {
|
|
|
38963
39003
|
},
|
|
38964
39004
|
},
|
|
38965
39005
|
memory: {
|
|
38966
|
-
geometries: {
|
|
39006
|
+
geometries: {
|
|
39007
|
+
count: geometryCount,
|
|
39008
|
+
bytes: geometryMemoryBytes,
|
|
39009
|
+
optimizedBytes: optimizedUsageBytes,
|
|
39010
|
+
totalRawBytes: totalUsageBytes,
|
|
39011
|
+
},
|
|
38967
39012
|
textures: { count: textureCount },
|
|
38968
39013
|
materials: { count: materialCount },
|
|
38969
39014
|
totalEstimatedGpuBytes: estimatedGpuMemoryBytes,
|
|
@@ -38975,9 +39020,12 @@ void main() {
|
|
|
38975
39020
|
},
|
|
38976
39021
|
};
|
|
38977
39022
|
}
|
|
38978
|
-
async loadNode(nodeId, onLoadFinishCb) {
|
|
39023
|
+
async loadNode(nodeId, onLoadFinishCb, reservedEstimatedSize = 0) {
|
|
38979
39024
|
const node = this.nodes.get(nodeId);
|
|
38980
|
-
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
|
+
}
|
|
38981
39029
|
node.loading = true;
|
|
38982
39030
|
const meshDef = node.structure.getJson().meshes[node.meshIndex];
|
|
38983
39031
|
try {
|
|
@@ -39060,6 +39108,7 @@ void main() {
|
|
|
39060
39108
|
if (bufferRequests.length === 0) {
|
|
39061
39109
|
node.loaded = true;
|
|
39062
39110
|
node.loading = false;
|
|
39111
|
+
this.pendingMemoryUsage = Math.max(0, this.pendingMemoryUsage - reservedEstimatedSize);
|
|
39063
39112
|
return;
|
|
39064
39113
|
}
|
|
39065
39114
|
bufferRequests.sort((a, b) => a.offset - b.offset);
|
|
@@ -39171,6 +39220,7 @@ void main() {
|
|
|
39171
39220
|
}
|
|
39172
39221
|
node.loaded = true;
|
|
39173
39222
|
node.loading = false;
|
|
39223
|
+
this.pendingMemoryUsage = Math.max(0, this.pendingMemoryUsage - reservedEstimatedSize);
|
|
39174
39224
|
const geometrySize = this.estimateGeometrySize(node.object);
|
|
39175
39225
|
this.geometryCache.set(node.object.uuid, geometrySize);
|
|
39176
39226
|
this.currentMemoryUsage += geometrySize;
|
|
@@ -39179,6 +39229,7 @@ void main() {
|
|
|
39179
39229
|
}
|
|
39180
39230
|
} catch (error) {
|
|
39181
39231
|
node.loading = false;
|
|
39232
|
+
this.pendingMemoryUsage = Math.max(0, this.pendingMemoryUsage - reservedEstimatedSize);
|
|
39182
39233
|
if (error.name === "AbortError") {
|
|
39183
39234
|
return;
|
|
39184
39235
|
}
|
|
@@ -39394,15 +39445,18 @@ void main() {
|
|
|
39394
39445
|
let loadedCount = 0;
|
|
39395
39446
|
let lastLoadedCount = 0;
|
|
39396
39447
|
const totalNodes = nodesToLoad.length;
|
|
39448
|
+
const progressTotal = { value: totalNodes };
|
|
39397
39449
|
const loadProgress = async () => {
|
|
39398
39450
|
loadedCount++;
|
|
39451
|
+
const total = progressTotal.value;
|
|
39452
|
+
const percentage = total > 0 ? Math.min(100, Math.round((loadedCount / total) * 100)) : 0;
|
|
39399
39453
|
if (loadedCount - lastLoadedCount > 1000) {
|
|
39400
39454
|
lastLoadedCount = loadedCount;
|
|
39401
39455
|
this.updateMemoryIndicator();
|
|
39402
39456
|
this.dispatchEvent("geometryprogress", {
|
|
39403
|
-
percentage
|
|
39457
|
+
percentage,
|
|
39404
39458
|
loaded: loadedCount,
|
|
39405
|
-
total
|
|
39459
|
+
total,
|
|
39406
39460
|
});
|
|
39407
39461
|
this.dispatchEvent("update");
|
|
39408
39462
|
await new Promise((resolve) => {
|
|
@@ -39412,20 +39466,22 @@ void main() {
|
|
|
39412
39466
|
};
|
|
39413
39467
|
try {
|
|
39414
39468
|
const loadOperations = [];
|
|
39469
|
+
let memoryLimitReached = false;
|
|
39415
39470
|
for (const nodeId of nodesToLoad) {
|
|
39416
39471
|
if (this.abortController.signal.aborted) {
|
|
39417
39472
|
throw new DOMException("Loading aborted", "AbortError");
|
|
39418
39473
|
}
|
|
39419
39474
|
const estimatedSize = await this.estimateNodeSize(nodeId);
|
|
39420
|
-
|
|
39421
|
-
|
|
39422
|
-
|
|
39423
|
-
|
|
39424
|
-
|
|
39425
|
-
|
|
39426
|
-
|
|
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;
|
|
39427
39482
|
}
|
|
39428
|
-
|
|
39483
|
+
this.pendingMemoryUsage += estimated;
|
|
39484
|
+
loadOperations.push(this.loadNode(nodeId, loadProgress, estimated));
|
|
39429
39485
|
}
|
|
39430
39486
|
for (const structure of this.structures) {
|
|
39431
39487
|
loadOperations.push(structure.flushBufferRequests());
|
|
@@ -39433,7 +39489,8 @@ void main() {
|
|
|
39433
39489
|
await Promise.all(loadOperations);
|
|
39434
39490
|
this.dispatchEvent("geometryend", {
|
|
39435
39491
|
totalLoaded: loadedCount,
|
|
39436
|
-
totalNodes,
|
|
39492
|
+
totalNodes: progressTotal.value,
|
|
39493
|
+
memoryLimitReached,
|
|
39437
39494
|
});
|
|
39438
39495
|
return loadedCount;
|
|
39439
39496
|
} catch (error) {
|
|
@@ -39743,6 +39800,7 @@ void main() {
|
|
|
39743
39800
|
this.transformedGeometries.clear();
|
|
39744
39801
|
this.totalLoadedObjects = 0;
|
|
39745
39802
|
this.currentMemoryUsage = 0;
|
|
39803
|
+
this.pendingMemoryUsage = 0;
|
|
39746
39804
|
this.loadedGeometrySize = 0;
|
|
39747
39805
|
this.abortController = new AbortController();
|
|
39748
39806
|
this.updateMemoryIndicator();
|
|
@@ -39949,6 +40007,7 @@ void main() {
|
|
|
39949
40007
|
progress: 100,
|
|
39950
40008
|
message: `Optimization complete! ${this.maxObjectId} objects processed.`,
|
|
39951
40009
|
});
|
|
40010
|
+
this.updateMemoryIndicator();
|
|
39952
40011
|
this.dispatchEvent("update");
|
|
39953
40012
|
}
|
|
39954
40013
|
async mergeMeshGroups(materialGroups, rootGroup) {
|