@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.
@@ -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.GROUND_FOLLOWING_SPEED = 0.05;
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
- const up = new Vector3().copy(this.camera.up);
35213
- this.raycaster.set(this.object.position, up.negate());
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 = new Vector3();
35233
- const sideways = new Vector3();
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
- if (upgradeGroundFollowing)
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("Total geometry size:", info.memory.totalEstimatedGpuBytes / (1024 * 1024), "MB");
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 / 3;
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
- if (currentMemoryUsage > this.memoryLimit) {
38843
- console.log(`Memory usage (${Math.round(currentMemoryUsage / (1024 * 1024))}MB) exceeds limit`);
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 <= this.memoryLimit) break;
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 estimatedGpuMemoryBytes = geometryMemoryBytes;
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: { count: geometryCount, bytes: geometryMemoryBytes },
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) return;
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: Math.round((loadedCount / totalNodes) * 100),
39457
+ percentage,
39404
39458
  loaded: loadedCount,
39405
- total: totalNodes,
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
- if (this.currentMemoryUsage + estimatedSize > this.memoryLimit) {
39421
- console.log(`Memory limit reached after loading ${loadedCount} nodes`);
39422
- this.dispatchEvent("geometryerror", {
39423
- message: "Memory limit reached",
39424
- });
39425
- this.dispatchEvent("update");
39426
- return loadedCount;
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
- loadOperations.push(this.loadNode(nodeId, loadProgress));
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) {