@inweb/viewer-three 26.11.0 → 26.12.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.
- package/dist/extensions/components/AxesHelperComponent.js +1 -1
- package/dist/extensions/components/AxesHelperComponent.js.map +1 -1
- package/dist/extensions/components/AxesHelperComponent.min.js +1 -1
- package/dist/extensions/components/AxesHelperComponent.module.js +1 -1
- package/dist/extensions/components/AxesHelperComponent.module.js.map +1 -1
- package/dist/extensions/components/InfoPanelComponent.js +170 -0
- package/dist/extensions/components/InfoPanelComponent.js.map +1 -0
- package/dist/extensions/components/InfoPanelComponent.min.js +24 -0
- package/dist/extensions/components/InfoPanelComponent.module.js +164 -0
- package/dist/extensions/components/InfoPanelComponent.module.js.map +1 -0
- package/dist/extensions/components/StatsPanelComponent.js +9 -3
- package/dist/extensions/components/StatsPanelComponent.js.map +1 -1
- package/dist/extensions/components/StatsPanelComponent.min.js +1 -1
- package/dist/extensions/components/StatsPanelComponent.module.js +9 -3
- package/dist/extensions/components/StatsPanelComponent.module.js.map +1 -1
- package/dist/extensions/loaders/PotreeLoader.js +55 -4
- package/dist/extensions/loaders/PotreeLoader.js.map +1 -1
- package/dist/extensions/loaders/PotreeLoader.min.js +1 -1
- package/dist/extensions/loaders/PotreeLoader.module.js +52 -0
- package/dist/extensions/loaders/PotreeLoader.module.js.map +1 -1
- package/dist/viewer-three.js +402 -5
- package/dist/viewer-three.js.map +1 -1
- package/dist/viewer-three.min.js +8 -3
- package/dist/viewer-three.module.js +358 -7
- package/dist/viewer-three.module.js.map +1 -1
- package/extensions/components/AxesHelperComponent.ts +1 -1
- package/extensions/components/InfoPanelComponent.ts +197 -0
- package/extensions/components/StatsPanelComponent.ts +10 -3
- package/extensions/loaders/Potree/PotreeModelImpl.ts +72 -0
- package/lib/Viewer/Viewer.d.ts +2 -1
- package/lib/Viewer/components/InfoComponent.d.ts +22 -0
- package/lib/Viewer/loaders/DynamicGltfLoader/DynamicModelImpl.d.ts +2 -0
- package/lib/Viewer/models/IModelImpl.d.ts +2 -1
- package/lib/Viewer/models/ModelImpl.d.ts +2 -0
- package/package.json +5 -5
- package/src/Viewer/Viewer.ts +7 -0
- package/src/Viewer/components/InfoComponent.ts +187 -0
- package/src/Viewer/components/index.ts +2 -0
- package/src/Viewer/loaders/DynamicGltfLoader/DynamicGltfLoader.js +16 -8
- package/src/Viewer/loaders/DynamicGltfLoader/DynamicModelImpl.ts +25 -0
- package/src/Viewer/loaders/DynamicGltfLoader/GltfStructure.js +67 -1
- package/src/Viewer/loaders/RangesLoader.ts +11 -1
- package/src/Viewer/models/IModelImpl.ts +3 -1
- package/src/Viewer/models/ModelImpl.ts +158 -0
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
// acknowledge and accept the above terms.
|
|
22
22
|
///////////////////////////////////////////////////////////////////////////////
|
|
23
23
|
|
|
24
|
-
import { draggersRegistry, commandsRegistry, Options, componentsRegistry, Loader, loadersRegistry, CANVAS_EVENTS } from '@inweb/viewer-core';
|
|
24
|
+
import { draggersRegistry, commandsRegistry, Options, componentsRegistry, Info, Loader, loadersRegistry, CANVAS_EVENTS } from '@inweb/viewer-core';
|
|
25
25
|
export * from '@inweb/viewer-core';
|
|
26
|
-
import { Line, Vector3, BufferGeometry, Float32BufferAttribute, LineBasicMaterial, Mesh, MeshBasicMaterial, DoubleSide, EventDispatcher, MOUSE, TOUCH, Spherical, Quaternion, Vector2, Plane, Object3D, Line3, Raycaster, MathUtils, EdgesGeometry, Matrix4, Vector4, Controls, Clock, Sphere, Box3, Color, PerspectiveCamera, OrthographicCamera, AmbientLight, DirectionalLight, HemisphereLight, MeshPhongMaterial, WebGLRenderTarget, UnsignedByteType, RGBAFormat, CylinderGeometry, Sprite, CanvasTexture, SRGBColorSpace, SpriteMaterial, TextureLoader, BufferAttribute, PointsMaterial, Points, TriangleStripDrawMode, TriangleFanDrawMode, LineSegments, LineLoop, Group, NormalBlending, LoadingManager, LoaderUtils, FileLoader, UniformsUtils, ShaderMaterial, AdditiveBlending, HalfFloatType, Scene, WebGLRenderer, LinearSRGBColorSpace } from 'three';
|
|
26
|
+
import { Line, Vector3, BufferGeometry, Float32BufferAttribute, LineBasicMaterial, Mesh, MeshBasicMaterial, DoubleSide, EventDispatcher, MOUSE, TOUCH, Spherical, Quaternion, Vector2, Plane, Object3D, Line3, Raycaster, MathUtils, EdgesGeometry, Matrix4, Vector4, Controls, Clock, Sphere, Box3, Color, PerspectiveCamera, OrthographicCamera, AmbientLight, DirectionalLight, HemisphereLight, REVISION, MeshPhongMaterial, WebGLRenderTarget, UnsignedByteType, RGBAFormat, CylinderGeometry, Sprite, CanvasTexture, SRGBColorSpace, SpriteMaterial, TextureLoader, BufferAttribute, PointsMaterial, Points, TriangleStripDrawMode, TriangleFanDrawMode, LineSegments, LineLoop, Group, NormalBlending, LoadingManager, LoaderUtils, FileLoader, UniformsUtils, ShaderMaterial, AdditiveBlending, HalfFloatType, Scene, WebGLRenderer, LinearSRGBColorSpace } from 'three';
|
|
27
27
|
import { TransformControls } from 'three/examples/jsm/controls/TransformControls.js';
|
|
28
28
|
import { LineSegmentsGeometry } from 'three/examples/jsm/lines/LineSegmentsGeometry.js';
|
|
29
29
|
import { Wireframe } from 'three/examples/jsm/lines/Wireframe.js';
|
|
@@ -2633,6 +2633,140 @@ class LightComponent {
|
|
|
2633
2633
|
}
|
|
2634
2634
|
}
|
|
2635
2635
|
|
|
2636
|
+
class InfoComponent {
|
|
2637
|
+
constructor(viewer) {
|
|
2638
|
+
this.initialize = () => {
|
|
2639
|
+
try {
|
|
2640
|
+
const gl = this.viewer.renderer.getContext();
|
|
2641
|
+
const dbgInfo = gl.getExtension("WEBGL_debug_renderer_info");
|
|
2642
|
+
if (dbgInfo) {
|
|
2643
|
+
this.viewer.info.system.webglRenderer = gl.getParameter(dbgInfo.UNMASKED_RENDERER_WEBGL);
|
|
2644
|
+
this.viewer.info.system.webglVendor = gl.getParameter(dbgInfo.UNMASKED_VENDOR_WEBGL);
|
|
2645
|
+
}
|
|
2646
|
+
}
|
|
2647
|
+
catch (error) {
|
|
2648
|
+
console.error("Error reading WebGL info.", error);
|
|
2649
|
+
}
|
|
2650
|
+
console.log("THREE.WebGLRenderer:", REVISION);
|
|
2651
|
+
console.log("WebGL Renderer:", this.viewer.info.system.webglRenderer);
|
|
2652
|
+
console.log("WebGL Vendor:", this.viewer.info.system.webglVendor);
|
|
2653
|
+
this.resize();
|
|
2654
|
+
this.optionsChange({ data: this.viewer.options });
|
|
2655
|
+
};
|
|
2656
|
+
this.clear = () => {
|
|
2657
|
+
this.viewer.info.performance.timeToFirstRender = 0;
|
|
2658
|
+
this.viewer.info.performance.loadTime = 0;
|
|
2659
|
+
this.viewer.info.scene.objects = 0;
|
|
2660
|
+
this.viewer.info.scene.triangles = 0;
|
|
2661
|
+
this.viewer.info.scene.points = 0;
|
|
2662
|
+
this.viewer.info.scene.lines = 0;
|
|
2663
|
+
this.viewer.info.scene.edges = 0;
|
|
2664
|
+
this.viewer.info.optimizedScene.objects = 0;
|
|
2665
|
+
this.viewer.info.optimizedScene.triangles = 0;
|
|
2666
|
+
this.viewer.info.optimizedScene.points = 0;
|
|
2667
|
+
this.viewer.info.optimizedScene.lines = 0;
|
|
2668
|
+
this.viewer.info.optimizedScene.edges = 0;
|
|
2669
|
+
this.viewer.info.memory.geometries = 0;
|
|
2670
|
+
this.viewer.info.memory.geometryBytes = 0;
|
|
2671
|
+
this.viewer.info.memory.textures = 0;
|
|
2672
|
+
this.viewer.info.memory.textureBytes = 0;
|
|
2673
|
+
this.viewer.info.memory.materials = 0;
|
|
2674
|
+
this.viewer.info.memory.totalEstimatedGpuBytes = 0;
|
|
2675
|
+
this.viewer.info.memory.usedJSHeapSize = 0;
|
|
2676
|
+
};
|
|
2677
|
+
this.optionsChange = ({ data: options }) => {
|
|
2678
|
+
if (options.antialiasing === false)
|
|
2679
|
+
this.viewer.info.render.antialiasing = "";
|
|
2680
|
+
else if (options.antialiasing === true)
|
|
2681
|
+
this.viewer.info.render.antialiasing = "mxaa";
|
|
2682
|
+
else
|
|
2683
|
+
this.viewer.info.render.antialiasing = options.antialiasing;
|
|
2684
|
+
};
|
|
2685
|
+
this.geometryStart = () => {
|
|
2686
|
+
this.startTime = performance.now();
|
|
2687
|
+
};
|
|
2688
|
+
this.databaseChunk = () => {
|
|
2689
|
+
this.viewer.info.performance.timeToFirstRender += performance.now() - this.startTime;
|
|
2690
|
+
console.log("Time to first render:", this.viewer.info.performance.timeToFirstRender, "ms");
|
|
2691
|
+
};
|
|
2692
|
+
this.geometryEnd = () => {
|
|
2693
|
+
const model = this.viewer.models[this.viewer.models.length - 1];
|
|
2694
|
+
const info = model.getInfo();
|
|
2695
|
+
this.viewer.info.scene.objects += info.scene.objects;
|
|
2696
|
+
this.viewer.info.scene.triangles += info.scene.triangles;
|
|
2697
|
+
this.viewer.info.scene.points += info.scene.points;
|
|
2698
|
+
this.viewer.info.scene.lines += info.scene.lines;
|
|
2699
|
+
this.viewer.info.scene.edges += info.scene.edges;
|
|
2700
|
+
this.viewer.info.optimizedScene.objects += info.optimizedScene.objects;
|
|
2701
|
+
this.viewer.info.optimizedScene.triangles += info.optimizedScene.triangles;
|
|
2702
|
+
this.viewer.info.optimizedScene.points += info.optimizedScene.points;
|
|
2703
|
+
this.viewer.info.optimizedScene.lines += info.optimizedScene.lines;
|
|
2704
|
+
this.viewer.info.optimizedScene.edges += info.optimizedScene.edges;
|
|
2705
|
+
this.viewer.info.memory.geometries += info.memory.geometries;
|
|
2706
|
+
this.viewer.info.memory.geometryBytes += info.memory.geometryBytes;
|
|
2707
|
+
this.viewer.info.memory.textures += info.memory.textures;
|
|
2708
|
+
this.viewer.info.memory.textureBytes += info.memory.textureBytes;
|
|
2709
|
+
this.viewer.info.memory.materials += info.memory.materials;
|
|
2710
|
+
this.viewer.info.memory.totalEstimatedGpuBytes += info.memory.totalEstimatedGpuBytes;
|
|
2711
|
+
const memory = performance["memory"];
|
|
2712
|
+
if (memory)
|
|
2713
|
+
this.viewer.info.memory.usedJSHeapSize = memory.usedJSHeapSize;
|
|
2714
|
+
this.viewer.info.performance.loadTime += performance.now() - this.startTime;
|
|
2715
|
+
console.log("Number of objects:", info.scene.objects);
|
|
2716
|
+
console.log("Number of objects after optimization:", info.optimizedScene.objects);
|
|
2717
|
+
console.log("Total geometry size:", info.memory.totalEstimatedGpuBytes / (1024 * 1024), "MB");
|
|
2718
|
+
console.log("File load time:", this.viewer.info.performance.loadTime, "ms");
|
|
2719
|
+
};
|
|
2720
|
+
this.resize = () => {
|
|
2721
|
+
const rendererSize = this.viewer.renderer.getSize(new Vector2());
|
|
2722
|
+
this.viewer.info.render.viewport.width = rendererSize.x;
|
|
2723
|
+
this.viewer.info.render.viewport.height = rendererSize.y;
|
|
2724
|
+
};
|
|
2725
|
+
this.render = () => {
|
|
2726
|
+
this.viewer.info.render.drawCalls = this.viewer.renderer.info.render.calls;
|
|
2727
|
+
this.viewer.info.render.triangles = this.viewer.renderer.info.render.triangles;
|
|
2728
|
+
this.viewer.info.render.points = this.viewer.renderer.info.render.points;
|
|
2729
|
+
this.viewer.info.render.lines = this.viewer.renderer.info.render.lines;
|
|
2730
|
+
};
|
|
2731
|
+
this.animate = () => {
|
|
2732
|
+
const time = performance.now();
|
|
2733
|
+
this.viewer.info.performance.frameTime = Math.round(time - this.beginTime);
|
|
2734
|
+
this.beginTime = time;
|
|
2735
|
+
this.frames++;
|
|
2736
|
+
if (time - this.prevTime >= 1000) {
|
|
2737
|
+
this.viewer.info.performance.fps = Math.round((this.frames * 1000) / (time - this.prevTime));
|
|
2738
|
+
this.prevTime = time;
|
|
2739
|
+
this.frames = 0;
|
|
2740
|
+
}
|
|
2741
|
+
};
|
|
2742
|
+
this.viewer = viewer;
|
|
2743
|
+
this.startTime = 0;
|
|
2744
|
+
this.beginTime = performance.now();
|
|
2745
|
+
this.prevTime = performance.now();
|
|
2746
|
+
this.frames = 0;
|
|
2747
|
+
this.viewer.addEventListener("initialize", this.initialize);
|
|
2748
|
+
this.viewer.addEventListener("clear", this.clear);
|
|
2749
|
+
this.viewer.addEventListener("optionschange", this.optionsChange);
|
|
2750
|
+
this.viewer.addEventListener("geometrystart", this.geometryStart);
|
|
2751
|
+
this.viewer.addEventListener("databasechunk", this.databaseChunk);
|
|
2752
|
+
this.viewer.addEventListener("geometryend", this.geometryEnd);
|
|
2753
|
+
this.viewer.addEventListener("resize", this.resize);
|
|
2754
|
+
this.viewer.addEventListener("render", this.render);
|
|
2755
|
+
this.viewer.addEventListener("animate", this.animate);
|
|
2756
|
+
}
|
|
2757
|
+
dispose() {
|
|
2758
|
+
this.viewer.removeEventListener("initialize", this.initialize);
|
|
2759
|
+
this.viewer.removeEventListener("clear", this.clear);
|
|
2760
|
+
this.viewer.removeEventListener("optionschange", this.optionsChange);
|
|
2761
|
+
this.viewer.removeEventListener("geometrystart", this.geometryStart);
|
|
2762
|
+
this.viewer.removeEventListener("databasechunk", this.databaseChunk);
|
|
2763
|
+
this.viewer.removeEventListener("geometryend", this.geometryEnd);
|
|
2764
|
+
this.viewer.removeEventListener("resize", this.resize);
|
|
2765
|
+
this.viewer.removeEventListener("render", this.render);
|
|
2766
|
+
this.viewer.addEventListener("animate", this.animate);
|
|
2767
|
+
}
|
|
2768
|
+
}
|
|
2769
|
+
|
|
2636
2770
|
class RenderLoopComponent {
|
|
2637
2771
|
constructor(viewer) {
|
|
2638
2772
|
this.animate = (time = 0) => {
|
|
@@ -3119,6 +3253,7 @@ components.registerComponent("ExtentsComponent", (viewer) => new ExtentsComponen
|
|
|
3119
3253
|
components.registerComponent("CameraComponent", (viewer) => new CameraComponent(viewer));
|
|
3120
3254
|
components.registerComponent("BackgroundComponent", (viewer) => new BackgroundComponent(viewer));
|
|
3121
3255
|
components.registerComponent("LightComponent", (viewer) => new LightComponent(viewer));
|
|
3256
|
+
components.registerComponent("InfoComponent", (viewer) => new InfoComponent(viewer));
|
|
3122
3257
|
components.registerComponent("ResizeCanvasComponent", (viewer) => new ResizeCanvasComponent(viewer));
|
|
3123
3258
|
components.registerComponent("RenderLoopComponent", (viewer) => new RenderLoopComponent(viewer));
|
|
3124
3259
|
components.registerComponent("HighlighterComponent", (viewer) => new HighlighterComponent(viewer));
|
|
@@ -3159,6 +3294,132 @@ class ModelImpl {
|
|
|
3159
3294
|
getPrecision() {
|
|
3160
3295
|
return 2;
|
|
3161
3296
|
}
|
|
3297
|
+
getInfo() {
|
|
3298
|
+
const geometries = new Set();
|
|
3299
|
+
const materials = new Set();
|
|
3300
|
+
const textures = new Set();
|
|
3301
|
+
let totalObjects = 0;
|
|
3302
|
+
let totalTriangles = 0;
|
|
3303
|
+
let totalPoints = 0;
|
|
3304
|
+
let totalLines = 0;
|
|
3305
|
+
let totalEdges = 0;
|
|
3306
|
+
let geometryBytes = 0;
|
|
3307
|
+
let textureBytes = 0;
|
|
3308
|
+
this.scene.traverse((object) => {
|
|
3309
|
+
totalObjects++;
|
|
3310
|
+
if (object.geometry) {
|
|
3311
|
+
const geometry = object.geometry;
|
|
3312
|
+
if (!geometries.has(geometry)) {
|
|
3313
|
+
geometries.add(geometry);
|
|
3314
|
+
if (geometry.attributes) {
|
|
3315
|
+
for (const name in geometry.attributes) {
|
|
3316
|
+
const attribute = geometry.attributes[name];
|
|
3317
|
+
if (attribute && attribute.array) {
|
|
3318
|
+
geometryBytes += attribute.array.byteLength;
|
|
3319
|
+
}
|
|
3320
|
+
}
|
|
3321
|
+
}
|
|
3322
|
+
if (geometry.index && geometry.index.array) {
|
|
3323
|
+
geometryBytes += geometry.index.array.byteLength;
|
|
3324
|
+
}
|
|
3325
|
+
}
|
|
3326
|
+
if (geometry.index) {
|
|
3327
|
+
const indexCount = geometry.index.count;
|
|
3328
|
+
if (object.isLine || object.isLineSegments) {
|
|
3329
|
+
totalLines += indexCount / 2;
|
|
3330
|
+
}
|
|
3331
|
+
else if (object.isPoints) {
|
|
3332
|
+
totalPoints += indexCount;
|
|
3333
|
+
}
|
|
3334
|
+
else {
|
|
3335
|
+
totalTriangles += indexCount / 3;
|
|
3336
|
+
}
|
|
3337
|
+
}
|
|
3338
|
+
else if (geometry.attributes && geometry.attributes.position) {
|
|
3339
|
+
const positionCount = geometry.attributes.position.count;
|
|
3340
|
+
if (object.isLine || object.isLineSegments) {
|
|
3341
|
+
totalLines += positionCount / 2;
|
|
3342
|
+
}
|
|
3343
|
+
else if (object.isPoints) {
|
|
3344
|
+
totalPoints += positionCount;
|
|
3345
|
+
}
|
|
3346
|
+
else {
|
|
3347
|
+
totalTriangles += positionCount / 3;
|
|
3348
|
+
}
|
|
3349
|
+
}
|
|
3350
|
+
if (object.isLineSegments && geometry.attributes.position) {
|
|
3351
|
+
totalEdges += geometry.attributes.position.count / 2;
|
|
3352
|
+
}
|
|
3353
|
+
}
|
|
3354
|
+
if (object.material) {
|
|
3355
|
+
const materialsArray = Array.isArray(object.material) ? object.material : [object.material];
|
|
3356
|
+
materialsArray.forEach((material) => {
|
|
3357
|
+
materials.add(material);
|
|
3358
|
+
if (material.map && !textures.has(material.map)) {
|
|
3359
|
+
textures.add(material.map);
|
|
3360
|
+
textureBytes += estimateTextureSize(material.map);
|
|
3361
|
+
}
|
|
3362
|
+
const textureProps = [
|
|
3363
|
+
"alphaMap",
|
|
3364
|
+
"aoMap",
|
|
3365
|
+
"bumpMap",
|
|
3366
|
+
"displacementMap",
|
|
3367
|
+
"emissiveMap",
|
|
3368
|
+
"envMap",
|
|
3369
|
+
"lightMap",
|
|
3370
|
+
"metalnessMap",
|
|
3371
|
+
"normalMap",
|
|
3372
|
+
"roughnessMap",
|
|
3373
|
+
"specularMap",
|
|
3374
|
+
"clearcoatMap",
|
|
3375
|
+
"clearcoatNormalMap",
|
|
3376
|
+
"clearcoatRoughnessMap",
|
|
3377
|
+
"iridescenceMap",
|
|
3378
|
+
"sheenColorMap",
|
|
3379
|
+
"sheenRoughnessMap",
|
|
3380
|
+
"thicknessMap",
|
|
3381
|
+
"transmissionMap",
|
|
3382
|
+
"anisotropyMap",
|
|
3383
|
+
"gradientMap",
|
|
3384
|
+
];
|
|
3385
|
+
textureProps.forEach((prop) => {
|
|
3386
|
+
const texture = material[prop];
|
|
3387
|
+
if (texture && !textures.has(texture)) {
|
|
3388
|
+
textures.add(texture);
|
|
3389
|
+
textureBytes += estimateTextureSize(texture);
|
|
3390
|
+
}
|
|
3391
|
+
});
|
|
3392
|
+
});
|
|
3393
|
+
}
|
|
3394
|
+
});
|
|
3395
|
+
function estimateTextureSize(texture) {
|
|
3396
|
+
if (!texture.image)
|
|
3397
|
+
return 0;
|
|
3398
|
+
const width = texture.image.width || 0;
|
|
3399
|
+
const height = texture.image.height || 0;
|
|
3400
|
+
const bytesPerPixel = 4;
|
|
3401
|
+
const mipmapMultiplier = texture.generateMipmaps ? 1.33 : 1;
|
|
3402
|
+
return width * height * bytesPerPixel * mipmapMultiplier;
|
|
3403
|
+
}
|
|
3404
|
+
const info = new Info();
|
|
3405
|
+
info.scene.objects = totalObjects;
|
|
3406
|
+
info.scene.triangles = Math.floor(totalTriangles);
|
|
3407
|
+
info.scene.points = Math.floor(totalPoints);
|
|
3408
|
+
info.scene.lines = Math.floor(totalLines);
|
|
3409
|
+
info.scene.edges = Math.floor(totalEdges);
|
|
3410
|
+
info.memory.geometries = geometries.size;
|
|
3411
|
+
info.memory.geometryBytes = geometryBytes;
|
|
3412
|
+
info.memory.textures = textures.size;
|
|
3413
|
+
info.memory.textureBytes = Math.floor(textureBytes);
|
|
3414
|
+
info.memory.materials = materials.size;
|
|
3415
|
+
info.memory.totalEstimatedGpuBytes = geometryBytes + Math.floor(textureBytes);
|
|
3416
|
+
info.optimizedScene.objects = info.scene.objects;
|
|
3417
|
+
info.optimizedScene.triangles = info.scene.triangles;
|
|
3418
|
+
info.optimizedScene.points = info.scene.points;
|
|
3419
|
+
info.optimizedScene.lines = info.scene.lines;
|
|
3420
|
+
info.optimizedScene.edges = info.scene.edges;
|
|
3421
|
+
return info;
|
|
3422
|
+
}
|
|
3162
3423
|
getExtents(target) {
|
|
3163
3424
|
this.scene.traverseVisible((object) => !object.children.length && target.expandByObject(object));
|
|
3164
3425
|
return target;
|
|
@@ -3291,6 +3552,24 @@ class ModelImpl {
|
|
|
3291
3552
|
}
|
|
3292
3553
|
|
|
3293
3554
|
class DynamicModelImpl extends ModelImpl {
|
|
3555
|
+
getInfo() {
|
|
3556
|
+
const stats = this.gltfLoader.getStats();
|
|
3557
|
+
const info = new Info();
|
|
3558
|
+
info.scene.objects = stats.scene.beforeOptimization.objects;
|
|
3559
|
+
info.scene.triangles = stats.scene.beforeOptimization.triangles;
|
|
3560
|
+
info.scene.lines = stats.scene.beforeOptimization.lines;
|
|
3561
|
+
info.scene.edges = stats.scene.beforeOptimization.edges;
|
|
3562
|
+
info.optimizedScene.objects = stats.scene.afterOptimization.objects;
|
|
3563
|
+
info.optimizedScene.triangles = stats.scene.afterOptimization.triangles;
|
|
3564
|
+
info.optimizedScene.lines = stats.scene.afterOptimization.lines;
|
|
3565
|
+
info.optimizedScene.edges = stats.scene.afterOptimization.edges;
|
|
3566
|
+
info.memory.geometries = stats.memory.geometries.count;
|
|
3567
|
+
info.memory.geometryBytes = stats.memory.geometries.bytes;
|
|
3568
|
+
info.memory.textures = stats.memory.textures.count;
|
|
3569
|
+
info.memory.materials = stats.memory.materials.count;
|
|
3570
|
+
info.memory.totalEstimatedGpuBytes = stats.memory.totalEstimatedGpuBytes;
|
|
3571
|
+
return info;
|
|
3572
|
+
}
|
|
3294
3573
|
getExtents(target) {
|
|
3295
3574
|
return target.union(this.gltfLoader.getTotalGeometryExtent());
|
|
3296
3575
|
}
|
|
@@ -3407,6 +3686,8 @@ class GltfStructure {
|
|
|
3407
3686
|
this.materialCache = new Map();
|
|
3408
3687
|
this.uri = "";
|
|
3409
3688
|
this._nextObjectId = 0;
|
|
3689
|
+
this.loadingAborted = false;
|
|
3690
|
+
this.criticalError = null;
|
|
3410
3691
|
}
|
|
3411
3692
|
async initialize(loader) {
|
|
3412
3693
|
this.json = await this.loadController.loadJson();
|
|
@@ -3428,12 +3709,18 @@ class GltfStructure {
|
|
|
3428
3709
|
this.materials.clear();
|
|
3429
3710
|
this.activeChunkLoads = 0;
|
|
3430
3711
|
this.chunkQueue = [];
|
|
3712
|
+
this.loadingAborted = false;
|
|
3713
|
+
this.criticalError = null;
|
|
3431
3714
|
}
|
|
3432
3715
|
getJson() {
|
|
3433
3716
|
return this.json;
|
|
3434
3717
|
}
|
|
3435
3718
|
scheduleRequest(request) {
|
|
3436
3719
|
return new Promise((resolve, reject) => {
|
|
3720
|
+
if (this.loadingAborted) {
|
|
3721
|
+
reject(this.criticalError || new Error("Structure loading has been aborted due to critical error"));
|
|
3722
|
+
return;
|
|
3723
|
+
}
|
|
3437
3724
|
this.pendingRequests.push({
|
|
3438
3725
|
...request,
|
|
3439
3726
|
_resolve: resolve,
|
|
@@ -3441,6 +3728,41 @@ class GltfStructure {
|
|
|
3441
3728
|
});
|
|
3442
3729
|
});
|
|
3443
3730
|
}
|
|
3731
|
+
isCriticalHttpError(error) {
|
|
3732
|
+
if (!error) return false;
|
|
3733
|
+
const status = error.status || error.statusCode || error.code;
|
|
3734
|
+
if (typeof status === "number") {
|
|
3735
|
+
return status >= 400 && status < 600;
|
|
3736
|
+
}
|
|
3737
|
+
if (error.message) {
|
|
3738
|
+
const match = error.message.match(/HTTP\s+(\d{3})/i);
|
|
3739
|
+
if (match) {
|
|
3740
|
+
const code = parseInt(match[1], 10);
|
|
3741
|
+
return code >= 400 && code < 600;
|
|
3742
|
+
}
|
|
3743
|
+
}
|
|
3744
|
+
return false;
|
|
3745
|
+
}
|
|
3746
|
+
abortLoading(error) {
|
|
3747
|
+
if (this.loadingAborted) {
|
|
3748
|
+
return;
|
|
3749
|
+
}
|
|
3750
|
+
this.loadingAborted = true;
|
|
3751
|
+
this.criticalError = error;
|
|
3752
|
+
const requests = [...this.pendingRequests];
|
|
3753
|
+
this.pendingRequests = [];
|
|
3754
|
+
for (const req of requests) {
|
|
3755
|
+
if (req._reject) {
|
|
3756
|
+
req._reject(error);
|
|
3757
|
+
}
|
|
3758
|
+
}
|
|
3759
|
+
console.error(
|
|
3760
|
+
`❌ Critical error for structure "${this.id}". All further loading aborted.`,
|
|
3761
|
+
`\n Error: ${error.message || error}`,
|
|
3762
|
+
`\n Rejected ${requests.length} pending chunk requests.`
|
|
3763
|
+
);
|
|
3764
|
+
throw error;
|
|
3765
|
+
}
|
|
3444
3766
|
async flushBufferRequests() {
|
|
3445
3767
|
if (!this.pendingRequests || this.pendingRequests.length === 0) return;
|
|
3446
3768
|
const requests = [...this.pendingRequests];
|
|
@@ -3503,6 +3825,12 @@ class GltfStructure {
|
|
|
3503
3825
|
}
|
|
3504
3826
|
}
|
|
3505
3827
|
const promises = finalRanges.map(async (range, index) => {
|
|
3828
|
+
if (this.loadingAborted) {
|
|
3829
|
+
for (const req of range.requests) {
|
|
3830
|
+
req._reject(this.criticalError || new Error("Structure loading aborted"));
|
|
3831
|
+
}
|
|
3832
|
+
return;
|
|
3833
|
+
}
|
|
3506
3834
|
await this.loader.waitForChunkSlot();
|
|
3507
3835
|
try {
|
|
3508
3836
|
const length = range.end - range.start;
|
|
@@ -3519,7 +3847,11 @@ class GltfStructure {
|
|
|
3519
3847
|
for (const req of range.requests) {
|
|
3520
3848
|
req._reject(error);
|
|
3521
3849
|
}
|
|
3522
|
-
|
|
3850
|
+
if (this.isCriticalHttpError(error)) {
|
|
3851
|
+
this.abortLoading(error);
|
|
3852
|
+
} else {
|
|
3853
|
+
console.warn(`Failed to load chunk ${index + 1}/${finalRanges.length} (${range.start}-${range.end}):`, error);
|
|
3854
|
+
}
|
|
3523
3855
|
} finally {
|
|
3524
3856
|
this.loader.releaseChunkSlot();
|
|
3525
3857
|
}
|
|
@@ -4310,10 +4642,14 @@ class DynamicGltfLoader {
|
|
|
4310
4642
|
onLoadFinishCb();
|
|
4311
4643
|
}
|
|
4312
4644
|
} catch (error) {
|
|
4313
|
-
if (error.name !== "AbortError") {
|
|
4314
|
-
console.error(`Error loading node ${nodeId}:`, error);
|
|
4315
|
-
}
|
|
4316
4645
|
node.loading = false;
|
|
4646
|
+
if (error.name === "AbortError") {
|
|
4647
|
+
return;
|
|
4648
|
+
}
|
|
4649
|
+
if (node.structure && node.structure.loadingAborted) {
|
|
4650
|
+
return;
|
|
4651
|
+
}
|
|
4652
|
+
console.error(`Error loading node ${nodeId}:`, error);
|
|
4317
4653
|
}
|
|
4318
4654
|
}
|
|
4319
4655
|
unloadNode(nodeId) {
|
|
@@ -5119,6 +5455,7 @@ class DynamicGltfLoader {
|
|
|
5119
5455
|
}
|
|
5120
5456
|
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
5121
5457
|
const mergedMesh = new Mesh(mergedGeometry, visibilityMaterial);
|
|
5458
|
+
mergedMesh.userData.isOptimized = true;
|
|
5122
5459
|
rootGroup.add(mergedMesh);
|
|
5123
5460
|
this.mergedMesh.add(mergedMesh);
|
|
5124
5461
|
this.optimizedOriginalMap.set(mergedMesh, optimizedObjects);
|
|
@@ -5225,6 +5562,7 @@ class DynamicGltfLoader {
|
|
|
5225
5562
|
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
5226
5563
|
const mergedLine = new LineSegments(geometry, visibilityMaterial);
|
|
5227
5564
|
mergedLine.userData.isEdge = isEdge;
|
|
5565
|
+
mergedLine.userData.isOptimized = true;
|
|
5228
5566
|
const mergedObjects = [mergedLine];
|
|
5229
5567
|
if (this.useVAO) {
|
|
5230
5568
|
this.createVAO(mergedLine);
|
|
@@ -5303,6 +5641,7 @@ class DynamicGltfLoader {
|
|
|
5303
5641
|
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
5304
5642
|
const mergedLine = new LineSegments(mergedGeometry, visibilityMaterial);
|
|
5305
5643
|
mergedLine.userData.isEdge = isEdge;
|
|
5644
|
+
mergedLine.userData.isOptimized = true;
|
|
5306
5645
|
if (this.useVAO) {
|
|
5307
5646
|
this.createVAO(mergedLine);
|
|
5308
5647
|
}
|
|
@@ -5362,6 +5701,7 @@ class DynamicGltfLoader {
|
|
|
5362
5701
|
if (geometries.length > 0) {
|
|
5363
5702
|
const mergedGeometry = mergeGeometries(geometries, false);
|
|
5364
5703
|
const mergedPoints = new Points(mergedGeometry, group.material);
|
|
5704
|
+
mergedPoints.userData.isOptimized = true;
|
|
5365
5705
|
if (this.useVAO) {
|
|
5366
5706
|
this.createVAO(mergedPoints);
|
|
5367
5707
|
}
|
|
@@ -5437,6 +5777,7 @@ class DynamicGltfLoader {
|
|
|
5437
5777
|
}
|
|
5438
5778
|
const mergedLine = new LineSegments(finalGeometry, material);
|
|
5439
5779
|
mergedLine.userData.structureId = structureId;
|
|
5780
|
+
mergedLine.userData.isOptimized = true;
|
|
5440
5781
|
rootGroup.add(mergedLine);
|
|
5441
5782
|
this.mergedLineSegments.add(mergedLine);
|
|
5442
5783
|
lineSegmentsArray.forEach((obj) => {
|
|
@@ -5706,6 +6047,13 @@ class GLTFBinaryExtension {
|
|
|
5706
6047
|
}
|
|
5707
6048
|
}
|
|
5708
6049
|
|
|
6050
|
+
class FetchError extends Error {
|
|
6051
|
+
constructor(status, message) {
|
|
6052
|
+
super(message);
|
|
6053
|
+
this.name = "FetchError";
|
|
6054
|
+
this.status = status;
|
|
6055
|
+
}
|
|
6056
|
+
}
|
|
5709
6057
|
class RangesLoader {
|
|
5710
6058
|
constructor() {
|
|
5711
6059
|
this.requestHeader = {};
|
|
@@ -5732,7 +6080,7 @@ class RangesLoader {
|
|
|
5732
6080
|
};
|
|
5733
6081
|
const response = await fetch(url, init);
|
|
5734
6082
|
if (!response.ok) {
|
|
5735
|
-
throw new
|
|
6083
|
+
throw new FetchError(response.status, `Failed to fetch "${url}", status ${response.status}`);
|
|
5736
6084
|
}
|
|
5737
6085
|
if (response.status !== 206) {
|
|
5738
6086
|
const arrayBuffer = await response.arrayBuffer();
|
|
@@ -6118,6 +6466,7 @@ class Viewer extends EventEmitter2 {
|
|
|
6118
6466
|
this.options = new Options(this);
|
|
6119
6467
|
this.loaders = [];
|
|
6120
6468
|
this.models = [];
|
|
6469
|
+
this.info = new Info();
|
|
6121
6470
|
this.canvasEvents = CANVAS_EVENTS.slice();
|
|
6122
6471
|
this.canvaseventlistener = (event) => this.emit(event);
|
|
6123
6472
|
this.selected = [];
|
|
@@ -6278,6 +6627,8 @@ class Viewer extends EventEmitter2 {
|
|
|
6278
6627
|
const deltaTime = (time - this._renderTime) / 1000;
|
|
6279
6628
|
this._renderTime = time;
|
|
6280
6629
|
this._renderNeeded = false;
|
|
6630
|
+
this.renderer.info.autoReset = false;
|
|
6631
|
+
this.renderer.info.reset();
|
|
6281
6632
|
if (this.options.antialiasing === true || this.options.antialiasing === "msaa") {
|
|
6282
6633
|
this.renderer.render(this.scene, this.camera);
|
|
6283
6634
|
this.renderer.render(this.helpers, this.camera);
|