@inweb/viewer-three 26.7.6 → 26.8.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.
@@ -59894,6 +59894,7 @@ void main() {
59894
59894
  selection.clearSelection();
59895
59895
  viewer.models.forEach((model) => {
59896
59896
  const objects = model.getObjectsByHandles(handles);
59897
+ model.showObjects(objects);
59897
59898
  selection.select(objects, model);
59898
59899
  });
59899
59900
  viewer.update();
@@ -60074,9 +60075,9 @@ void main() {
60074
60075
  commands.registerCommand("clearMarkup", clearMarkup);
60075
60076
  commands.registerCommand("clearSelected", clearSelected);
60076
60077
  commands.registerCommand("clearSlices", clearSlices);
60078
+ commands.registerCommand("collect", collect);
60077
60079
  commands.registerCommand("createPreview", createPreview);
60078
60080
  commands.registerCommand("explode", explode);
60079
- commands.registerCommand("collect", collect);
60080
60081
  commands.registerCommand("getDefaultViewPositions", getDefaultViewPositions);
60081
60082
  commands.registerCommand("getModels", getModels);
60082
60083
  commands.registerCommand("getSelected", getSelected);
@@ -60309,30 +60310,29 @@ void main() {
60309
60310
  const extentsCenter = this.viewer.extents.getCenter(new Vector3());
60310
60311
  const extentsSize = this.viewer.extents.getBoundingSphere(new Sphere()).radius;
60311
60312
  this.directionalLight.position
60312
- .set(0.5, 0, 0.866)
60313
+ .set(0.5, 0.866, 0) // ~60º
60313
60314
  .multiplyScalar(extentsSize * 2)
60314
60315
  .add(extentsCenter);
60315
60316
  this.directionalLight.target.position.copy(extentsCenter);
60316
- this.frontLight.position.set(0, extentsSize * 2, 0).add(extentsCenter);
60317
+ this.frontLight.position
60318
+ .set(0, 0, 1)
60319
+ .multiplyScalar(extentsSize * 2)
60320
+ .add(extentsCenter);
60317
60321
  this.frontLight.target.position.copy(extentsCenter);
60318
- this.hemisphereLight.position.set(0, extentsSize * 3, 0).add(extentsCenter);
60322
+ this.hemisphereLight.position
60323
+ .set(0, 0, 1)
60324
+ .multiplyScalar(extentsSize * 3)
60325
+ .add(extentsCenter);
60319
60326
  this.viewer.scene.add(this.ambientLight);
60320
60327
  this.viewer.scene.add(this.directionalLight);
60321
60328
  this.viewer.scene.add(this.frontLight);
60322
60329
  this.viewer.scene.add(this.hemisphereLight);
60323
60330
  };
60324
60331
  this.viewer = viewer;
60325
- this.ambientLight = new AmbientLight(0xffffff, 1);
60326
- this.viewer.scene.add(this.ambientLight);
60327
- this.directionalLight = new DirectionalLight(0xffffff, 1);
60328
- this.directionalLight.position.set(0.5, 0, 0.866); // ~60º
60329
- this.viewer.scene.add(this.directionalLight);
60332
+ this.ambientLight = new AmbientLight(0xffffff, 1.0);
60333
+ this.directionalLight = new DirectionalLight(0xffffff, 1.0);
60330
60334
  this.frontLight = new DirectionalLight(0xffffff, 1.25);
60331
- this.frontLight.position.set(0, 1, 0);
60332
- this.viewer.scene.add(this.frontLight);
60333
60335
  this.hemisphereLight = new HemisphereLight(0xffffff, 0x444444, 1.25);
60334
- this.hemisphereLight.position.set(0, 0, 1);
60335
- this.viewer.scene.add(this.hemisphereLight);
60336
60336
  this.viewer.addEventListener("databasechunk", this.geometryEnd);
60337
60337
  this.viewer.addEventListener("clear", this.geometryEnd);
60338
60338
  }
@@ -61430,19 +61430,25 @@ void main() {
61430
61430
  class HighlighterComponent {
61431
61431
  constructor(viewer) {
61432
61432
  this.geometryEnd = () => {
61433
- const { facesColor, facesTransparancy, edgesColor } = this.viewer.options;
61434
- this.highlightMaterial = new MeshBasicMaterial({
61433
+ const { facesColor, facesTransparancy, edgesColor, edgesOverlap, facesOverlap } = this.viewer.options;
61434
+ this.highlightMaterial = new MeshPhongMaterial({
61435
61435
  color: new Color(facesColor.r / 255, facesColor.g / 255, facesColor.b / 255),
61436
61436
  transparent: true,
61437
61437
  opacity: (255 - facesTransparancy) / 255,
61438
- depthTest: false,
61439
- depthWrite: false,
61438
+ depthTest: !facesOverlap,
61439
+ depthWrite: !facesOverlap,
61440
+ specular: 0x222222,
61441
+ shininess: 10,
61442
+ reflectivity: 0.05,
61443
+ polygonOffset: true,
61444
+ polygonOffsetFactor: 1,
61445
+ polygonOffsetUnits: 1,
61440
61446
  });
61441
61447
  this.outlineMaterial = new LineMaterial({
61442
61448
  color: new Color(edgesColor.r / 255, edgesColor.g / 255, edgesColor.b / 255),
61443
61449
  linewidth: 1.5,
61444
- depthTest: false,
61445
- depthWrite: false,
61450
+ depthTest: !edgesOverlap,
61451
+ depthWrite: !edgesOverlap,
61446
61452
  resolution: new Vector2(window.innerWidth, window.innerHeight),
61447
61453
  });
61448
61454
  this.highlightLineMaterial = new LineBasicMaterial({
@@ -61455,18 +61461,27 @@ void main() {
61455
61461
  linewidth: 5,
61456
61462
  transparent: true,
61457
61463
  opacity: 0.8,
61458
- depthTest: true,
61459
- depthWrite: true,
61464
+ depthTest: !edgesOverlap,
61465
+ depthWrite: !edgesOverlap,
61460
61466
  resolution: new Vector2(window.innerWidth, window.innerHeight),
61461
61467
  });
61462
61468
  };
61463
61469
  this.optionsChange = () => {
61464
- const { facesColor, facesTransparancy, edgesColor } = this.viewer.options;
61470
+ const { facesColor, facesTransparancy, edgesColor, edgesVisibility, edgesOverlap, facesOverlap } = this.viewer.options;
61465
61471
  this.highlightMaterial.color.setRGB(facesColor.r / 255, facesColor.g / 255, facesColor.b / 255);
61466
61472
  this.highlightMaterial.opacity = (255 - facesTransparancy) / 255;
61473
+ this.highlightMaterial.depthTest = !facesOverlap;
61474
+ this.highlightMaterial.depthWrite = !facesOverlap;
61467
61475
  this.outlineMaterial.color.setRGB(edgesColor.r / 255, edgesColor.g / 255, edgesColor.b / 255);
61476
+ this.outlineMaterial.depthTest = !edgesOverlap;
61477
+ this.outlineMaterial.depthWrite = !edgesOverlap;
61468
61478
  this.highlightLineMaterial.color.setRGB(facesColor.r / 255, facesColor.g / 255, facesColor.b / 255);
61469
61479
  this.highlightLineGlowMaterial.color.setRGB(facesColor.r / 255, facesColor.g / 255, facesColor.b / 255);
61480
+ this.viewer.selected.forEach((selected) => {
61481
+ const wireframe = selected.userData.highlightWireframe;
61482
+ if (wireframe)
61483
+ wireframe.visible = edgesVisibility;
61484
+ });
61470
61485
  this.viewer.update();
61471
61486
  };
61472
61487
  this.viewer = viewer;
@@ -61491,6 +61506,7 @@ void main() {
61491
61506
  this.viewer.removeEventListener("resize", this.viewerResize);
61492
61507
  }
61493
61508
  highlight(objects) {
61509
+ const { edgesVisibility } = this.viewer.options;
61494
61510
  if (!Array.isArray(objects))
61495
61511
  objects = [objects];
61496
61512
  if (!objects.length)
@@ -61508,21 +61524,23 @@ void main() {
61508
61524
  wireframe.position.copy(object.position);
61509
61525
  wireframe.rotation.copy(object.rotation);
61510
61526
  wireframe.scale.copy(object.scale);
61527
+ wireframe.visible = edgesVisibility;
61511
61528
  object.parent.add(wireframe);
61512
- object.userData.highlightwireframe = wireframe;
61529
+ object.userData.highlightWireframe = wireframe;
61513
61530
  object.userData.originalMaterial = object.material;
61514
61531
  object.material = this.highlightLineMaterial;
61515
61532
  object.isHighlighted = true;
61516
61533
  }
61517
61534
  else if (object.isMesh) {
61518
- const edgesGeometry = new EdgesGeometry(object.geometry, 30);
61535
+ const edgesGeometry = new EdgesGeometry(object.geometry, 60);
61519
61536
  const lineGeometry = new LineSegmentsGeometry().fromEdgesGeometry(edgesGeometry);
61520
61537
  const wireframe = new Wireframe(lineGeometry, this.outlineMaterial);
61521
61538
  wireframe.position.copy(object.position);
61522
61539
  wireframe.rotation.copy(object.rotation);
61523
61540
  wireframe.scale.copy(object.scale);
61541
+ wireframe.visible = edgesVisibility;
61524
61542
  object.parent.add(wireframe);
61525
- object.userData.highlightwireframe = wireframe;
61543
+ object.userData.highlightWireframe = wireframe;
61526
61544
  object.userData.originalMaterial = object.material;
61527
61545
  object.material = this.highlightMaterial;
61528
61546
  object.isHighlighted = true;
@@ -61539,9 +61557,9 @@ void main() {
61539
61557
  return;
61540
61558
  object.isHighlighted = false;
61541
61559
  object.material = object.userData.originalMaterial;
61542
- object.userData.highlightwireframe.removeFromParent();
61560
+ object.userData.highlightWireframe.removeFromParent();
61543
61561
  delete object.userData.originalMaterial;
61544
- delete object.userData.highlightwireframe;
61562
+ delete object.userData.highlightWireframe;
61545
61563
  });
61546
61564
  }
61547
61565
  viewerResize(event) {
@@ -61590,7 +61608,8 @@ void main() {
61590
61608
  this.viewer.models.forEach((model) => {
61591
61609
  const objects = model.getVisibleObjects();
61592
61610
  const intersects = this.getPointerIntersects(upPosition, objects);
61593
- intersections.push(...intersects.map((x) => ({ ...x, model })));
61611
+ if (intersects.length > 0)
61612
+ intersections.push({ ...intersects[0], model });
61594
61613
  });
61595
61614
  intersections = intersections.sort((a, b) => a.distance - b.distance);
61596
61615
  if (!event.shiftKey)
@@ -61657,7 +61676,6 @@ void main() {
61657
61676
  objects = [objects];
61658
61677
  if (!objects.length)
61659
61678
  return;
61660
- model.showObjects(objects);
61661
61679
  model.showOriginalObjects(objects);
61662
61680
  this.highlighter.highlight(objects);
61663
61681
  objects.forEach((object) => this.viewer.selected.push(object));
@@ -67313,10 +67331,8 @@ void main() {
67313
67331
  return objects;
67314
67332
  }
67315
67333
  hideObjects(objects) {
67316
- this.getOwnObjects(objects)
67317
- .map((object) => object.userData.handle)
67318
- .forEach((handle) => this.gltfLoader.hiddenHandles.add(handle));
67319
- this.gltfLoader.syncHiddenObjects();
67334
+ const handles = this.getHandlesByObjects(objects);
67335
+ this.gltfLoader.hideObjects(handles);
67320
67336
  return this;
67321
67337
  }
67322
67338
  isolateObjects(objects) {
@@ -67325,23 +67341,20 @@ void main() {
67325
67341
  return this;
67326
67342
  }
67327
67343
  showObjects(objects) {
67328
- this.getOwnObjects(objects)
67329
- .map((object) => object.userData.handle)
67330
- .forEach((handle) => this.gltfLoader.hiddenHandles.delete(handle));
67331
- this.gltfLoader.syncHiddenObjects();
67344
+ const handles = this.getHandlesByObjects(objects);
67345
+ this.gltfLoader.showObjects(handles);
67332
67346
  return this;
67333
67347
  }
67334
67348
  showAllObjects() {
67335
- this.gltfLoader.hiddenHandles.clear();
67336
- this.gltfLoader.syncHiddenObjects();
67349
+ this.gltfLoader.showAllHiddenObjects();
67337
67350
  return this;
67338
67351
  }
67339
67352
  showOriginalObjects(objects) {
67340
- this.getOwnObjects(objects).forEach((object) => (object.visible = true));
67353
+ this.gltfLoader.showOriginalObjects(objects);
67341
67354
  return this;
67342
67355
  }
67343
67356
  hideOriginalObjects(objects) {
67344
- this.getOwnObjects(objects).forEach((object) => (object.visible = false));
67357
+ this.gltfLoader.hideOriginalObjects(objects);
67345
67358
  return this;
67346
67359
  }
67347
67360
  }
@@ -67364,24 +67377,20 @@ void main() {
67364
67377
  TRIANGLE_STRIP: 5,
67365
67378
  TRIANGLE_FAN: 6};
67366
67379
 
67380
+ const MAX_GAP = 128 * 1024; // 128 KB
67381
+ const MAX_CHUNK = 30 * 1024 * 1024; // 100 MB
67382
+
67367
67383
  class GltfStructure {
67368
67384
  constructor(id) {
67369
67385
  this.id = `${id}`;
67370
67386
  this.json = null;
67371
67387
  this.baseUrl = "";
67372
-
67373
- // Binary manager properties
67374
67388
  this.loadController = null;
67375
- // Request batching parameters
67376
67389
  this.batchDelay = 10;
67377
67390
  this.maxBatchSize = 5 * 1024 * 1024;
67378
67391
  this.maxRangesPerRequest = 512;
67379
-
67380
- // Request queue
67381
67392
  this.pendingRequests = [];
67382
67393
  this.batchTimeout = null;
67383
-
67384
- // Material and texture properties
67385
67394
  this.textureLoader = new TextureLoader();
67386
67395
  this.materials = new Map();
67387
67396
  this.textureCache = new Map();
@@ -67413,57 +67422,110 @@ void main() {
67413
67422
  return this.json;
67414
67423
  }
67415
67424
 
67416
- // Schedule a request for processing
67417
67425
  scheduleRequest(request) {
67418
- this.pendingRequests.push(request);
67419
-
67420
- // Clear existing timeout
67421
- if (this.batchTimeout) {
67422
- clearTimeout(this.batchTimeout);
67423
- }
67424
-
67425
- // Set new timeout for batch processing
67426
- this.batchTimeout = setTimeout(() => this.processBatch(), this.batchDelay);
67427
-
67428
- // Return a promise that will resolve when the data is available
67429
67426
  return new Promise((resolve, reject) => {
67430
- request.resolve = resolve;
67431
- request.reject = reject;
67427
+ this.pendingRequests.push({
67428
+ ...request,
67429
+ _resolve: resolve,
67430
+ _reject: reject,
67431
+ });
67432
67432
  });
67433
67433
  }
67434
67434
 
67435
- async processBatch() {
67436
- if (this.pendingRequests.length === 0) return;
67437
-
67438
- // Take current batch of requests and clear timeout
67439
- const currentBatch = [...this.pendingRequests];
67435
+ async flushBufferRequests() {
67436
+ if (!this.pendingRequests || this.pendingRequests.length === 0) return;
67437
+ const requests = [...this.pendingRequests];
67440
67438
  this.pendingRequests = [];
67441
67439
 
67442
- if (this.batchTimeout) {
67443
- clearTimeout(this.batchTimeout);
67444
- this.batchTimeout = null;
67440
+ requests.sort((a, b) => a.offset - b.offset);
67441
+ const mergedRanges = [];
67442
+ let current = {
67443
+ start: requests[0].offset,
67444
+ end: requests[0].offset + requests[0].length,
67445
+ requests: [requests[0]],
67446
+ };
67447
+ for (let i = 1; i < requests.length; i++) {
67448
+ const req = requests[i];
67449
+ const gap = req.offset - current.end;
67450
+ const newEnd = Math.max(current.end, req.offset + req.length);
67451
+ const projectedSize = newEnd - current.start;
67452
+ if (gap <= MAX_GAP && projectedSize <= MAX_CHUNK) {
67453
+ current.end = newEnd;
67454
+ current.requests.push(req);
67455
+ } else {
67456
+ mergedRanges.push(current);
67457
+ current = {
67458
+ start: req.offset,
67459
+ end: req.offset + req.length,
67460
+ requests: [req],
67461
+ };
67462
+ }
67445
67463
  }
67446
- try {
67447
- // Split requests into smaller groups
67448
- for (let i = 0; i < currentBatch.length; i += this.maxRangesPerRequest) {
67449
- const batchRequests = currentBatch.slice(i, i + this.maxRangesPerRequest);
67450
- const buffer = await this.loadController.loadBinaryData(batchRequests);
67451
-
67452
- let currentOffset = 0;
67453
- batchRequests.forEach((request) => {
67454
- const view = this.createTypedArray(buffer, currentOffset, request.length, request.componentType);
67455
- request.resolve(view);
67456
- currentOffset += request.length;
67464
+ mergedRanges.push(current);
67465
+ const finalRanges = [];
67466
+ for (const range of mergedRanges) {
67467
+ let { start, end, requests } = range;
67468
+ while (end - start > MAX_CHUNK) {
67469
+ let splitIdx = 0;
67470
+ for (let i = 0; i < requests.length; i++) {
67471
+ if (requests[i].offset + requests[i].length - start > MAX_CHUNK) {
67472
+ break;
67473
+ }
67474
+ splitIdx = i;
67475
+ }
67476
+ const chunkRequests = requests.slice(0, splitIdx + 1);
67477
+ const chunkEnd =
67478
+ chunkRequests[chunkRequests.length - 1].offset + chunkRequests[chunkRequests.length - 1].length;
67479
+ finalRanges.push({
67480
+ start,
67481
+ end: chunkEnd,
67482
+ requests: chunkRequests,
67457
67483
  });
67484
+ requests = requests.slice(splitIdx + 1);
67485
+ if (requests.length > 0) {
67486
+ start = requests[0].offset;
67487
+ end = requests[0].offset + requests[0].length;
67488
+ for (let i = 1; i < requests.length; i++) {
67489
+ end = Math.max(end, requests[i].offset + requests[i].length);
67490
+ }
67491
+ }
67492
+ }
67493
+ if (requests.length > 0) {
67494
+ finalRanges.push({ start, end, requests });
67458
67495
  }
67459
- } catch (error) {
67460
- console.error("Error processing batch:", error);
67461
- currentBatch.forEach((request) => request.reject(error));
67462
67496
  }
67463
-
67464
- if (this.pendingRequests.length > 0) {
67465
- this.batchTimeout = setTimeout(() => this.processBatch(), this.batchDelay);
67497
+ /*
67498
+ for (const range of finalRanges) {
67499
+ const length = range.end - range.start;
67500
+ const buffer = await this.loadController.loadBinaryData([
67501
+ { offset: range.start, length: length }
67502
+ ]);
67503
+ for (const req of range.requests) {
67504
+ const relOffset = req.offset - range.start;
67505
+ try {
67506
+ req._resolve({ buffer, relOffset, length: req.length });
67507
+ } catch (e) {
67508
+ req._reject(e);
67509
+ }
67510
+ }
67466
67511
  }
67512
+ */
67513
+
67514
+ const promises = finalRanges.map(async (range) => {
67515
+ const length = range.end - range.start;
67516
+ const buffer = await this.loadController.loadBinaryData([{ offset: range.start, length }]);
67517
+ for (const req of range.requests) {
67518
+ const relOffset = req.offset - range.start;
67519
+ try {
67520
+ req._resolve({ buffer, relOffset, length: req.length });
67521
+ } catch (e) {
67522
+ req._reject(e);
67523
+ }
67524
+ }
67525
+ });
67526
+ await Promise.all(promises);
67527
+
67528
+ this.pendingRequests = [];
67467
67529
  }
67468
67530
 
67469
67531
  getBufferView(byteOffset, byteLength, componentType) {
@@ -67476,12 +67538,10 @@ void main() {
67476
67538
 
67477
67539
  createTypedArray(buffer, offset, length, componentType) {
67478
67540
  try {
67479
- // Validate parameters
67480
67541
  if (!buffer || !(buffer instanceof ArrayBuffer)) {
67481
67542
  throw new Error("Invalid buffer");
67482
67543
  }
67483
67544
 
67484
- // Calculate element size for given type
67485
67545
  let elementSize;
67486
67546
  switch (componentType) {
67487
67547
  case 5120:
@@ -67500,18 +67560,15 @@ void main() {
67500
67560
  throw new Error(`Unsupported component type: ${componentType}`);
67501
67561
  }
67502
67562
 
67503
- // Check if requested length is correct
67504
67563
  const numElements = length / elementSize;
67505
67564
  if (!Number.isInteger(numElements)) {
67506
67565
  throw new Error(`Invalid length ${length} for component type ${componentType}`);
67507
67566
  }
67508
67567
 
67509
- // Check if buffer is large enough
67510
67568
  if (length > buffer.byteLength) {
67511
67569
  throw new Error(`Buffer too small: need ${length} bytes, but buffer is ${buffer.byteLength} bytes`);
67512
67570
  }
67513
67571
 
67514
- // Create appropriate typed array
67515
67572
  const ArrayType = GL_COMPONENT_TYPES[componentType];
67516
67573
  return new ArrayType(buffer, offset, numElements);
67517
67574
  } catch (error) {
@@ -67608,7 +67665,6 @@ void main() {
67608
67665
  const image = this.json.images[imageIndex];
67609
67666
 
67610
67667
  if (image.uri) {
67611
- // Handle base64 or URL
67612
67668
  if (image.uri.startsWith("data:")) {
67613
67669
  return await this.textureLoader.loadAsync(image.uri);
67614
67670
  } else {
@@ -67616,23 +67672,17 @@ void main() {
67616
67672
  return await this.textureLoader.loadAsync(fullUrl);
67617
67673
  }
67618
67674
  } else if (image.bufferView !== undefined) {
67619
- // Handle embedded binary data
67620
67675
  const bufferView = this.json.bufferViews[image.bufferView];
67621
- const array = await this.getBufferView(
67622
- bufferView.byteOffset || 0,
67623
- bufferView.byteLength,
67624
- 5121 // UNSIGNED_BYTE
67625
- );
67676
+ const array = await this.getBufferView(bufferView.byteOffset || 0, bufferView.byteLength, 5121);
67626
67677
  const blob = new Blob([array], { type: image.mimeType });
67627
67678
  const url = URL.createObjectURL(blob);
67628
67679
  const texture = await this.textureLoader.loadAsync(url);
67629
67680
  URL.revokeObjectURL(url);
67630
- texture.flipY = false; // GLTF standard
67681
+ texture.flipY = false;
67631
67682
  return texture;
67632
67683
  }
67633
67684
  };
67634
67685
 
67635
- // Load all textures
67636
67686
  const texturePromises = [];
67637
67687
  for (let i = 0; i < this.json.textures.length; i++) {
67638
67688
  texturePromises.push(
@@ -67642,82 +67692,56 @@ void main() {
67642
67692
  await Promise.all(texturePromises);
67643
67693
  }
67644
67694
 
67645
- loadMaterials() {
67695
+ async loadMaterials() {
67646
67696
  if (!this.json.materials) return this.materials;
67647
67697
 
67648
67698
  for (let i = 0; i < this.json.materials.length; i++) {
67649
67699
  const materialDef = this.json.materials[i];
67650
- const material = this.createMaterial(materialDef);
67700
+ const material = await this.createMaterial(materialDef);
67701
+ material.name = materialDef.name;
67651
67702
  this.materials.set(i, material);
67652
67703
  }
67653
67704
  return this.materials;
67654
67705
  }
67655
67706
 
67656
67707
  createMaterial(materialDef) {
67657
- const material = new MeshStandardMaterial();
67708
+ const params = {};
67658
67709
 
67659
- // Base color
67660
67710
  if (materialDef.pbrMetallicRoughness) {
67661
67711
  const pbr = materialDef.pbrMetallicRoughness;
67662
-
67663
67712
  if (pbr.baseColorFactor) {
67664
- material.color.fromArray(pbr.baseColorFactor);
67665
- material.opacity = pbr.baseColorFactor[3];
67713
+ params.color = new Color().fromArray(pbr.baseColorFactor);
67714
+ params.opacity = pbr.baseColorFactor[3];
67715
+ if (params.opacity < 1.0) params.transparent = true;
67666
67716
  }
67667
-
67668
67717
  if (pbr.baseColorTexture) {
67669
- material.map = this.textureCache.get(pbr.baseColorTexture.index);
67670
- }
67671
-
67672
- // Metallic and roughness
67673
- if (pbr.metallicFactor !== undefined) {
67674
- material.metalness = pbr.metallicFactor;
67675
- }
67676
- if (pbr.roughnessFactor !== undefined) {
67677
- material.roughness = pbr.roughnessFactor;
67678
- }
67679
- if (pbr.metallicRoughnessTexture) {
67680
- material.metalnessMap = this.textureCache.get(pbr.metallicRoughnessTexture.index);
67681
- material.roughnessMap = material.metalnessMap;
67718
+ params.map = this.textureCache.get(pbr.baseColorTexture.index);
67682
67719
  }
67683
67720
  }
67684
67721
 
67685
- // Normal map
67686
- if (materialDef.normalTexture) {
67687
- material.normalMap = this.textureCache.get(materialDef.normalTexture.index);
67688
- if (materialDef.normalTexture.scale !== undefined) {
67689
- material.normalScale.set(materialDef.normalTexture.scale, materialDef.normalTexture.scale);
67690
- }
67691
- }
67722
+ params.specular = 0x222222;
67723
+ params.shininess = 10;
67724
+ params.reflectivity = 0.05;
67725
+ params.polygonOffset = true;
67726
+ params.polygonOffsetFactor = 1;
67727
+ params.polygonOffsetUnits = 1;
67692
67728
 
67693
- // Emissive
67694
67729
  if (materialDef.emissiveFactor) {
67695
- material.emissive.fromArray(materialDef.emissiveFactor);
67696
- }
67697
- if (materialDef.emissiveTexture) {
67698
- material.emissiveMap = this.textureCache.get(materialDef.emissiveTexture.index);
67730
+ params.emissive = new Color().fromArray(materialDef.emissiveFactor);
67699
67731
  }
67700
67732
 
67701
- // Occlusion
67702
- if (materialDef.occlusionTexture) {
67703
- material.aoMap = this.textureCache.get(materialDef.occlusionTexture.index);
67704
- if (materialDef.occlusionTexture.strength !== undefined) {
67705
- material.aoMapIntensity = materialDef.occlusionTexture.strength;
67706
- }
67733
+ if (materialDef.normalTexture) {
67734
+ params.normalMap = this.textureCache.get(materialDef.normalTexture.index);
67707
67735
  }
67708
67736
 
67709
- // Alpha mode
67710
67737
  if (materialDef.alphaMode === "BLEND") {
67711
- material.transparent = true;
67712
- } else if (materialDef.alphaMode === "MASK") {
67713
- material.alphaTest = materialDef.alphaCutoff !== undefined ? materialDef.alphaCutoff : 0.5;
67738
+ params.transparent = true;
67714
67739
  }
67715
67740
 
67716
- // Double sided
67717
- material.side = materialDef.doubleSided ? DoubleSide : FrontSide;
67718
-
67719
- material.name = materialDef.name;
67720
-
67741
+ if (materialDef.doubleSided) {
67742
+ params.side = DoubleSide;
67743
+ }
67744
+ const material = new MeshPhongMaterial(params);
67721
67745
  return material;
67722
67746
  }
67723
67747
 
@@ -67750,12 +67774,8 @@ void main() {
67750
67774
  if (!meshDef || !meshDef.primitives) return 0;
67751
67775
 
67752
67776
  let totalSize = 0;
67753
-
67754
- // Estimate size for each primitive
67755
67777
  for (const primitive of meshDef.primitives) {
67756
- // Check for attributes
67757
67778
  if (primitive.attributes) {
67758
- // Calculate attributes size
67759
67779
  for (const [, accessorIndex] of Object.entries(primitive.attributes)) {
67760
67780
  if (accessorIndex === undefined) continue;
67761
67781
 
@@ -67768,7 +67788,6 @@ void main() {
67768
67788
  }
67769
67789
  }
67770
67790
 
67771
- // Calculate indices size if present
67772
67791
  if (primitive.indices !== undefined) {
67773
67792
  const accessor = this.json.accessors[primitive.indices];
67774
67793
  if (accessor) {
@@ -67841,7 +67860,9 @@ void main() {
67841
67860
  this.mergedPoints = new Set();
67842
67861
 
67843
67862
  this.isolatedObjects = [];
67844
- this.useVAO = !!window.WebGL2RenderingContext && this.renderer.getContext() instanceof WebGL2RenderingContext;
67863
+ //!!window.WebGL2RenderingContext && this.renderer.getContext() instanceof WebGL2RenderingContext
67864
+ this.useVAO = false;
67865
+ this.visibleEdges = true;
67845
67866
 
67846
67867
  this.handleToOptimizedObjects = new Map();
67847
67868
 
@@ -67850,6 +67871,10 @@ void main() {
67850
67871
  this.oldOptimizeObjects = new Set();
67851
67872
  }
67852
67873
 
67874
+ setVisibleEdges(visible) {
67875
+ this.visibleEdges = visible;
67876
+ }
67877
+
67853
67878
  getAvailableMemory() {
67854
67879
  let memoryLimit = 6 * 1024 * 1024 * 1024;
67855
67880
  try {
@@ -67870,7 +67895,7 @@ void main() {
67870
67895
  console.warn("Error detecting available memory:", error);
67871
67896
  }
67872
67897
 
67873
- return memoryLimit;
67898
+ return memoryLimit / 3;
67874
67899
  }
67875
67900
 
67876
67901
  getAbortController() {
@@ -67975,7 +68000,7 @@ void main() {
67975
68000
  console.log(`Final memory usage: ${Math.round(currentMemoryUsage / (1024 * 1024))}MB`);
67976
68001
  }
67977
68002
 
67978
- async loadNode(nodeId) {
68003
+ async loadNode(nodeId, onLoadFinishCb) {
67979
68004
  const node = this.nodes.get(nodeId);
67980
68005
  if (!node || node.loaded || node.loading) return;
67981
68006
 
@@ -67983,38 +68008,138 @@ void main() {
67983
68008
  const meshDef = node.structure.getJson().meshes[node.meshIndex];
67984
68009
 
67985
68010
  try {
67986
- for (const primitive of meshDef.primitives) {
67987
- const positionAccessor = primitive.attributes.POSITION;
67988
- const geometry = new BufferGeometry();
67989
- const attributes = new Map();
67990
-
67991
- attributes.set("position", node.structure.createBufferAttribute(positionAccessor));
68011
+ const bufferRequests = [];
68012
+ const primitiveReqMap = new Map();
68013
+ for (let primIdx = 0; primIdx < meshDef.primitives.length; primIdx++) {
68014
+ const primitive = meshDef.primitives[primIdx];
68015
+ const reqs = [];
68016
+
68017
+ if (primitive.attributes.POSITION !== undefined) {
68018
+ const accessorIndex = primitive.attributes.POSITION;
68019
+ const accessor = node.structure.json.accessors[accessorIndex];
68020
+ const bufferView = node.structure.json.bufferViews[accessor.bufferView];
68021
+ const byteOffset = (bufferView.byteOffset || 0) + (accessor.byteOffset || 0);
68022
+ const components = node.structure.getNumComponents(accessor.type);
68023
+ const count = accessor.count;
68024
+ const byteLength = count * components * node.structure.getComponentSize(accessor.componentType);
68025
+ reqs.push({
68026
+ offset: byteOffset,
68027
+ length: byteLength,
68028
+ componentType: accessor.componentType,
68029
+ accessorIndex,
68030
+ type: "position",
68031
+ primIdx,
68032
+ });
68033
+ }
67992
68034
 
67993
68035
  if (primitive.attributes.NORMAL !== undefined) {
67994
- attributes.set("normal", node.structure.createBufferAttribute(primitive.attributes.NORMAL));
68036
+ const accessorIndex = primitive.attributes.NORMAL;
68037
+ const accessor = node.structure.json.accessors[accessorIndex];
68038
+ const bufferView = node.structure.json.bufferViews[accessor.bufferView];
68039
+ const byteOffset = (bufferView.byteOffset || 0) + (accessor.byteOffset || 0);
68040
+ const components = node.structure.getNumComponents(accessor.type);
68041
+ const count = accessor.count;
68042
+ const byteLength = count * components * node.structure.getComponentSize(accessor.componentType);
68043
+ reqs.push({
68044
+ offset: byteOffset,
68045
+ length: byteLength,
68046
+ componentType: accessor.componentType,
68047
+ accessorIndex,
68048
+ type: "normal",
68049
+ primIdx,
68050
+ });
67995
68051
  }
67996
68052
 
67997
68053
  if (primitive.attributes.TEXCOORD_0 !== undefined) {
67998
- attributes.set("uv", node.structure.createBufferAttribute(primitive.attributes.TEXCOORD_0));
68054
+ const accessorIndex = primitive.attributes.TEXCOORD_0;
68055
+ const accessor = node.structure.json.accessors[accessorIndex];
68056
+ const bufferView = node.structure.json.bufferViews[accessor.bufferView];
68057
+ const byteOffset = (bufferView.byteOffset || 0) + (accessor.byteOffset || 0);
68058
+ const components = node.structure.getNumComponents(accessor.type);
68059
+ const count = accessor.count;
68060
+ const byteLength = count * components * node.structure.getComponentSize(accessor.componentType);
68061
+ reqs.push({
68062
+ offset: byteOffset,
68063
+ length: byteLength,
68064
+ componentType: accessor.componentType,
68065
+ accessorIndex,
68066
+ type: "uv",
68067
+ primIdx,
68068
+ });
67999
68069
  }
68000
68070
 
68001
- const loadedAttributes = await Promise.all(
68002
- [...attributes.entries()].map(async ([name, promise]) => {
68003
- const attribute = await promise;
68004
- return [name, attribute];
68005
- })
68006
- );
68071
+ if (primitive.indices !== undefined) {
68072
+ const accessorIndex = primitive.indices;
68073
+ const accessor = node.structure.json.accessors[accessorIndex];
68074
+ const bufferView = node.structure.json.bufferViews[accessor.bufferView];
68075
+ const byteOffset = (bufferView.byteOffset || 0) + (accessor.byteOffset || 0);
68076
+ const components = node.structure.getNumComponents(accessor.type);
68077
+ const count = accessor.count;
68078
+ const byteLength = count * components * node.structure.getComponentSize(accessor.componentType);
68079
+ reqs.push({
68080
+ offset: byteOffset,
68081
+ length: byteLength,
68082
+ componentType: accessor.componentType,
68083
+ accessorIndex,
68084
+ type: "index",
68085
+ primIdx,
68086
+ });
68087
+ }
68088
+ primitiveReqMap.set(primIdx, reqs);
68089
+ bufferRequests.push(...reqs);
68090
+ }
68007
68091
 
68008
- loadedAttributes.forEach(([name, attribute]) => {
68009
- geometry.setAttribute(name, attribute);
68010
- });
68092
+ if (bufferRequests.length === 0) {
68093
+ node.loaded = true;
68094
+ node.loading = false;
68095
+ return;
68096
+ }
68097
+ bufferRequests.sort((a, b) => a.offset - b.offset);
68098
+ const minOffset = bufferRequests[0].offset;
68099
+ const maxOffset = Math.max(...bufferRequests.map((r) => r.offset + r.length));
68100
+ const totalLength = maxOffset - minOffset;
68101
+
68102
+ const { buffer, relOffset: baseRelOffset } = await node.structure.scheduleRequest({
68103
+ offset: minOffset,
68104
+ length: totalLength,
68105
+ componentType: null,
68106
+ });
68011
68107
 
68012
- if (primitive.indices !== undefined) {
68013
- const indexAttribute = await node.structure.createBufferAttribute(primitive.indices);
68014
- geometry.setIndex(indexAttribute);
68108
+ for (const req of bufferRequests) {
68109
+ const relOffset = req.offset - minOffset;
68110
+ req.data = node.structure.createTypedArray(buffer, baseRelOffset + relOffset, req.length, req.componentType);
68111
+ }
68112
+
68113
+ for (let primIdx = 0; primIdx < meshDef.primitives.length; primIdx++) {
68114
+ const primitive = meshDef.primitives[primIdx];
68115
+ const geometry = new BufferGeometry();
68116
+ const reqs = primitiveReqMap.get(primIdx);
68117
+
68118
+ if (primitive.attributes.POSITION !== undefined) {
68119
+ const req = reqs.find((r) => r.type === "position" && r.accessorIndex === primitive.attributes.POSITION);
68120
+ const accessor = node.structure.json.accessors[primitive.attributes.POSITION];
68121
+ const components = node.structure.getNumComponents(accessor.type);
68122
+ geometry.setAttribute("position", new BufferAttribute(req.data, components));
68123
+ }
68124
+
68125
+ if (primitive.attributes.NORMAL !== undefined) {
68126
+ const req = reqs.find((r) => r.type === "normal" && r.accessorIndex === primitive.attributes.NORMAL);
68127
+ const accessor = node.structure.json.accessors[primitive.attributes.NORMAL];
68128
+ const components = node.structure.getNumComponents(accessor.type);
68129
+ geometry.setAttribute("normal", new BufferAttribute(req.data, components));
68015
68130
  }
68016
68131
 
68017
- this.currentPrimitiveMode = primitive.mode;
68132
+ if (primitive.attributes.TEXCOORD_0 !== undefined) {
68133
+ const req = reqs.find((r) => r.type === "uv" && r.accessorIndex === primitive.attributes.TEXCOORD_0);
68134
+ const accessor = node.structure.json.accessors[primitive.attributes.TEXCOORD_0];
68135
+ const components = node.structure.getNumComponents(accessor.type);
68136
+ geometry.setAttribute("uv", new BufferAttribute(req.data, components));
68137
+ }
68138
+
68139
+ if (primitive.indices !== undefined) {
68140
+ const req = reqs.find((r) => r.type === "index" && r.accessorIndex === primitive.indices);
68141
+ geometry.setIndex(new BufferAttribute(req.data, 1));
68142
+ }
68018
68143
 
68019
68144
  let material;
68020
68145
  if (primitive.material !== undefined) {
@@ -68029,8 +68154,7 @@ void main() {
68029
68154
  Material.prototype.copy.call(pointsMaterial, material);
68030
68155
  pointsMaterial.color.copy(material.color);
68031
68156
  pointsMaterial.map = material.map;
68032
- pointsMaterial.sizeAttenuation = false; // glTF spec says points should be 1px
68033
-
68157
+ pointsMaterial.sizeAttenuation = false;
68034
68158
  mesh = new Points(geometry, pointsMaterial);
68035
68159
  } else if (
68036
68160
  primitive.mode === GL_CONSTANTS.TRIANGLES ||
@@ -68039,7 +68163,6 @@ void main() {
68039
68163
  primitive.mode === undefined
68040
68164
  ) {
68041
68165
  mesh = new Mesh(geometry, material);
68042
-
68043
68166
  if (primitive.mode === GL_CONSTANTS.TRIANGLE_STRIP) {
68044
68167
  mesh.drawMode = TriangleStripDrawMode;
68045
68168
  } else if (primitive.mode === GL_CONSTANTS.TRIANGLE_FAN) {
@@ -68052,39 +68175,30 @@ void main() {
68052
68175
  } else if (primitive.mode === GL_CONSTANTS.LINE_LOOP) {
68053
68176
  mesh = new LineLoop(geometry, material);
68054
68177
  }
68055
-
68056
68178
  if (node.extras) {
68057
68179
  mesh.userData = { ...mesh.userData, ...node.extras };
68058
68180
  }
68059
-
68060
68181
  if (meshDef.extras) {
68061
68182
  mesh.userData = { ...mesh.userData, ...meshDef.extras };
68062
68183
  }
68063
-
68064
68184
  if (primitive.extras) {
68065
68185
  mesh.userData = { ...mesh.userData, ...primitive.extras };
68066
68186
  }
68067
-
68068
68187
  if (node.handle) {
68069
68188
  mesh.userData.handle = node.handle;
68070
68189
  } else {
68071
68190
  mesh.userData.handle = `${node.structure.id}_${mesh.userData.handle}`;
68072
68191
  }
68073
-
68074
68192
  if (mesh.material.name === "edges") {
68075
68193
  mesh.userData.isEdge = true;
68076
68194
  } else {
68077
68195
  mesh.userData.isEdge = false;
68078
68196
  }
68079
-
68080
68197
  this.registerObjectWithHandle(mesh, mesh.userData.handle);
68081
-
68082
68198
  mesh.position.copy(node.position);
68083
-
68084
68199
  if (!geometry.attributes.normal) {
68085
68200
  geometry.computeVertexNormals();
68086
68201
  }
68087
-
68088
68202
  if (material.aoMap && geometry.attributes.uv) {
68089
68203
  geometry.setAttribute("uv2", geometry.attributes.uv);
68090
68204
  }
@@ -68094,17 +68208,17 @@ void main() {
68094
68208
  this.scene.add(mesh);
68095
68209
  }
68096
68210
  node.object = mesh;
68097
-
68098
68211
  this.totalLoadedObjects++;
68099
68212
  mesh.visible = this.totalLoadedObjects < this.graphicsObjectLimit;
68100
68213
  }
68101
-
68102
68214
  node.loaded = true;
68103
68215
  node.loading = false;
68104
-
68105
68216
  const geometrySize = this.estimateGeometrySize(node.object);
68106
68217
  this.geometryCache.set(node.object.uuid, geometrySize);
68107
68218
  this.currentMemoryUsage += geometrySize;
68219
+ if (onLoadFinishCb) {
68220
+ onLoadFinishCb();
68221
+ }
68108
68222
  } catch (error) {
68109
68223
  if (error.name !== "AbortError") {
68110
68224
  console.error(`Error loading node ${nodeId}:`, error);
@@ -68229,7 +68343,7 @@ void main() {
68229
68343
  return volumeB - volumeA;
68230
68344
  });
68231
68345
 
68232
- if (!ignoreEdges) {
68346
+ if (!ignoreEdges && this.visibleEdges) {
68233
68347
  this.nodesToLoad.push(...this.edgeNodes);
68234
68348
  }
68235
68349
 
@@ -68356,33 +68470,13 @@ void main() {
68356
68470
  async processNodes() {
68357
68471
  const nodesToLoad = this.nodesToLoad;
68358
68472
  let loadedCount = 0;
68473
+ let lastLoadedCount = 0;
68359
68474
  const totalNodes = nodesToLoad.length;
68360
68475
 
68361
- try {
68362
- while (loadedCount < totalNodes) {
68363
- const batch = nodesToLoad.slice(loadedCount, loadedCount + this.batchSize);
68364
- const batchPromises = [];
68365
-
68366
- for (const nodeId of batch) {
68367
- if (this.abortController.signal.aborted) {
68368
- throw new DOMException("Loading aborted", "AbortError");
68369
- }
68370
-
68371
- const estimatedSize = await this.estimateNodeSize(nodeId);
68372
-
68373
- if (this.currentMemoryUsage + estimatedSize > this.memoryLimit) {
68374
- console.log(`Memory limit reached after loading ${loadedCount} nodes`);
68375
- this.dispatchEvent("geometryerror", { message: "Memory limit reached" });
68376
- this.dispatchEvent("update");
68377
- return loadedCount;
68378
- }
68379
-
68380
- batchPromises.push(this.loadNode(nodeId));
68381
- }
68382
-
68383
- await Promise.all(batchPromises);
68384
- loadedCount += batch.length;
68385
-
68476
+ const loadProgress = async () => {
68477
+ loadedCount++;
68478
+ if (loadedCount - lastLoadedCount > 1000) {
68479
+ lastLoadedCount = loadedCount;
68386
68480
  this.updateMemoryIndicator();
68387
68481
  this.dispatchEvent("geometryprogress", {
68388
68482
  percentage: Math.round((loadedCount / totalNodes) * 100),
@@ -68400,6 +68494,34 @@ void main() {
68400
68494
  setTimeout(resolve, 0);
68401
68495
  });
68402
68496
  }
68497
+ };
68498
+
68499
+ try {
68500
+ const loadOperations = [];
68501
+ for (const nodeId of nodesToLoad) {
68502
+ if (this.abortController.signal.aborted) {
68503
+ throw new DOMException("Loading aborted", "AbortError");
68504
+ }
68505
+
68506
+ const estimatedSize = await this.estimateNodeSize(nodeId);
68507
+
68508
+ if (this.currentMemoryUsage + estimatedSize > this.memoryLimit) {
68509
+ console.log(`Memory limit reached after loading ${loadedCount} nodes`);
68510
+ this.dispatchEvent("geometryerror", {
68511
+ message: "Memory limit reached",
68512
+ });
68513
+ this.dispatchEvent("update");
68514
+ return loadedCount;
68515
+ }
68516
+
68517
+ loadOperations.push(this.loadNode(nodeId, loadProgress));
68518
+ }
68519
+
68520
+ for (const structure of this.structures) {
68521
+ loadOperations.push(structure.flushBufferRequests());
68522
+ }
68523
+
68524
+ await Promise.all(loadOperations);
68403
68525
 
68404
68526
  this.dispatchEvent("geometryend", {
68405
68527
  totalLoaded: loadedCount,
@@ -69380,6 +69502,25 @@ void main() {
69380
69502
  }
69381
69503
  });
69382
69504
  }
69505
+
69506
+ // Возвращает bounding box для конкретной структуры
69507
+ getStructureGeometryExtent(structureId) {
69508
+ const extent = new Box3();
69509
+ for (const [nodeId, node] of this.nodes.entries()) {
69510
+ if (!node.geometryExtents) continue;
69511
+ if (!nodeId.startsWith(structureId + "_")) continue;
69512
+ if (node.object && this.hiddenHandles && this.hiddenHandles.has(node.object.userData.handle)) continue;
69513
+ const transformedBox = node.geometryExtents.clone();
69514
+ if (node.group && node.group.matrix) {
69515
+ transformedBox.applyMatrix4(node.group.matrix);
69516
+ if (node.group.parent && node.group.parent.matrix) {
69517
+ transformedBox.applyMatrix4(node.group.parent.matrix);
69518
+ }
69519
+ }
69520
+ extent.union(transformedBox);
69521
+ }
69522
+ return extent;
69523
+ }
69383
69524
  }
69384
69525
 
69385
69526
  ///////////////////////////////////////////////////////////////////////////////
@@ -69408,7 +69549,6 @@ void main() {
69408
69549
  constructor(viewer) {
69409
69550
  this.requestId = 0;
69410
69551
  this.viewer = viewer;
69411
- this.scene = new Group$1();
69412
69552
  }
69413
69553
  dispose() {
69414
69554
  if (this.gltfLoader)
@@ -69422,27 +69562,25 @@ void main() {
69422
69562
  /.gltf$/i.test(file.database));
69423
69563
  }
69424
69564
  async load(model, format, params) {
69425
- this.gltfLoader = new DynamicGltfLoader(this.viewer.camera, this.viewer.scene, this.viewer.renderer);
69565
+ const scene = new Group$1();
69566
+ this.gltfLoader = new DynamicGltfLoader(this.viewer.camera, scene, this.viewer.renderer);
69426
69567
  this.gltfLoader.memoryLimit = this.viewer.options.memoryLimit;
69427
69568
  this.gltfLoader.addEventListener("databasechunk", (data) => {
69428
- const modelImpl = new DynamicModelImpl(this.scene);
69569
+ const modelImpl = new DynamicModelImpl(scene);
69429
69570
  modelImpl.loader = this;
69430
69571
  modelImpl.gltfLoader = this.gltfLoader;
69431
69572
  modelImpl.viewer = this.viewer;
69432
- this.viewer.scene.add(this.scene);
69573
+ this.viewer.scene.add(scene);
69433
69574
  this.viewer.models.push(modelImpl);
69434
69575
  this.viewer.syncOptions();
69435
69576
  this.viewer.syncOverlay();
69436
69577
  this.viewer.update();
69437
- this.viewer.emitEvent({ type: "databasechunk", data, file: model.file, model });
69578
+ this.viewer.emitEvent({ type: "databasechunk", data: scene, file: model.file, model });
69438
69579
  });
69439
69580
  this.gltfLoader.addEventListener("geometryprogress", (data) => {
69440
69581
  const progress = data.loaded / data.total;
69441
69582
  this.viewer.emitEvent({ type: "geometryprogress", data: progress, file: model.file, model });
69442
69583
  });
69443
- this.gltfLoader.addEventListener("geometrymemory", (data) => {
69444
- this.viewer.emit({ type: "geometryprogress", data });
69445
- });
69446
69584
  this.gltfLoader.addEventListener("geometryerror", (data) => {
69447
69585
  this.viewer.emitEvent({ type: "geometryerror", data, file: model.file, model });
69448
69586
  });
@@ -69476,9 +69614,8 @@ void main() {
69476
69614
  return this;
69477
69615
  }
69478
69616
  cancel() {
69479
- if (this.gltfLoader) {
69617
+ if (this.gltfLoader)
69480
69618
  this.gltfLoader.abortLoading();
69481
- }
69482
69619
  }
69483
69620
  }
69484
69621
 
@@ -69516,7 +69653,7 @@ void main() {
69516
69653
  *
69517
69654
  * The loader should do:
69518
69655
  *
69519
- * - Load scene from file. The scene must be a Three.js object of type `Object3D` or a descendant of it.
69656
+ * - Load raw data from file and convert it to the `Three.js` scene.
69520
69657
  * - Add scene to the viewer `scene`.
69521
69658
  * - Create `ModelImpl` for the scene and to the viewer `models` list.
69522
69659
  * - Synchronize viewer options and overlay.