@inweb/viewer-three 27.4.6 → 27.5.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 +3 -0
- 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 +3 -0
- package/dist/extensions/components/AxesHelperComponent.module.js.map +1 -1
- package/dist/extensions/components/ExtentsHelperComponent.js +6 -2
- package/dist/extensions/components/ExtentsHelperComponent.js.map +1 -1
- package/dist/extensions/components/ExtentsHelperComponent.min.js +1 -1
- package/dist/extensions/components/ExtentsHelperComponent.module.js +6 -2
- package/dist/extensions/components/ExtentsHelperComponent.module.js.map +1 -1
- package/dist/extensions/components/GridHelperComponent.js +1 -0
- package/dist/extensions/components/GridHelperComponent.js.map +1 -1
- package/dist/extensions/components/GridHelperComponent.min.js +1 -1
- package/dist/extensions/components/GridHelperComponent.module.js +1 -0
- package/dist/extensions/components/GridHelperComponent.module.js.map +1 -1
- package/dist/extensions/components/LightHelperComponent.js +1 -0
- package/dist/extensions/components/LightHelperComponent.js.map +1 -1
- package/dist/extensions/components/LightHelperComponent.min.js +1 -1
- package/dist/extensions/components/LightHelperComponent.module.js +1 -0
- package/dist/extensions/components/LightHelperComponent.module.js.map +1 -1
- package/dist/viewer-three.js +1765 -438
- package/dist/viewer-three.js.map +1 -1
- package/dist/viewer-three.min.js +4 -4
- package/dist/viewer-three.module.js +1302 -403
- package/dist/viewer-three.module.js.map +1 -1
- package/extensions/components/AxesHelperComponent.ts +3 -0
- package/extensions/components/ExtentsHelperComponent.ts +5 -2
- package/extensions/components/GridHelperComponent.ts +1 -0
- package/extensions/components/LightHelperComponent.ts +1 -0
- package/lib/Viewer/Viewer.d.ts +5 -7
- package/lib/Viewer/components/CameraComponent.d.ts +1 -1
- package/lib/Viewer/components/ClippingPlaneComponent.d.ts +8 -0
- package/lib/Viewer/components/HighlighterComponent.d.ts +2 -2
- package/lib/Viewer/components/InfoComponent.d.ts +1 -1
- package/lib/Viewer/components/SectionsComponent.d.ts +15 -0
- package/lib/Viewer/components/WCSHelperComponent.d.ts +2 -2
- package/lib/Viewer/draggers/CuttingPlaneDragger.d.ts +6 -6
- package/lib/Viewer/draggers/OrbitDragger.d.ts +1 -1
- package/lib/Viewer/measurement/Snapper.d.ts +3 -3
- package/package.json +5 -5
- package/src/Viewer/Viewer.ts +50 -37
- package/src/Viewer/commands/index.ts +1 -1
- package/src/Viewer/components/BackgroundComponent.ts +1 -0
- package/src/Viewer/components/CameraComponent.ts +5 -6
- package/src/Viewer/{scenes/Helpers.ts → components/ClippingPlaneComponent.ts} +22 -12
- package/src/Viewer/components/HighlighterComponent.ts +9 -5
- package/src/Viewer/components/InfoComponent.ts +4 -4
- package/src/Viewer/components/SectionsComponent.ts +119 -0
- package/src/Viewer/components/SelectionComponent.ts +1 -1
- package/src/Viewer/components/WCSHelperComponent.ts +8 -6
- package/src/Viewer/components/index.ts +4 -0
- package/src/Viewer/draggers/CuttingPlaneDragger.ts +57 -34
- package/src/Viewer/draggers/MeasureLineDragger.ts +1 -1
- package/src/Viewer/draggers/OrbitDragger.ts +3 -3
- package/src/Viewer/helpers/SectionsHelper.js +1065 -0
- package/src/Viewer/helpers/WCSHelper.ts +24 -0
- package/src/Viewer/loaders/DynamicGltfLoader/DynamicGltfLoader.js +417 -92
- package/src/Viewer/loaders/DynamicGltfLoader/GltfStructure.js +75 -9
- package/src/Viewer/loaders/GLTFCloudDynamicLoader.ts +3 -2
- package/src/Viewer/loaders/GLTFFileDynamicLoader.ts +4 -2
- package/src/Viewer/measurement/Snapper.ts +4 -5
- package/src/Viewer/models/ModelImpl.ts +27 -3
- package/lib/Viewer/scenes/Helpers.d.ts +0 -7
- package/src/Viewer/postprocessing/SSAARenderPass.js +0 -245
|
@@ -23,19 +23,19 @@
|
|
|
23
23
|
|
|
24
24
|
import { draggersRegistry, commandsRegistry, Options, componentsRegistry, Info, Loader, loadersRegistry, CANVAS_EVENTS } from '@inweb/viewer-core';
|
|
25
25
|
export * from '@inweb/viewer-core';
|
|
26
|
-
import { EventDispatcher, Vector3, MOUSE, TOUCH, Spherical, Quaternion, Vector2, Object3D, BufferGeometry, Float32BufferAttribute, Line, LineBasicMaterial, Mesh, MeshBasicMaterial, DoubleSide, Line3, Raycaster, MathUtils, EdgesGeometry, Plane, Matrix4, Vector4, Controls, Box3, Clock, Color, PerspectiveCamera, OrthographicCamera, AmbientLight, DirectionalLight, HemisphereLight, REVISION, MeshPhongMaterial, WebGLRenderTarget, UnsignedByteType, RGBAFormat, CylinderGeometry, Sprite, CanvasTexture, SRGBColorSpace, SpriteMaterial, TextureLoader, BufferAttribute, LinearMipmapLinearFilter, NearestMipmapLinearFilter, LinearMipmapNearestFilter, NearestMipmapNearestFilter, LinearFilter, NearestFilter, RepeatWrapping, MirroredRepeatWrapping, ClampToEdgeWrapping,
|
|
26
|
+
import { EventDispatcher, Vector3, MOUSE, TOUCH, Spherical, Quaternion, Vector2, Object3D, BufferGeometry, Float32BufferAttribute, Line, LineBasicMaterial, Mesh, MeshBasicMaterial, DoubleSide, Line3, Raycaster, MathUtils, EdgesGeometry, Plane, Matrix4, Vector4, Controls, Box3, Clock, Color, PerspectiveCamera, OrthographicCamera, AmbientLight, DirectionalLight, HemisphereLight, REVISION, MeshPhongMaterial, WebGLRenderTarget, UnsignedByteType, RGBAFormat, ShaderMaterial, PointsMaterial, Points, Sphere, ShapeUtils, CylinderGeometry, Sprite, CanvasTexture, SRGBColorSpace, SpriteMaterial, TextureLoader, BufferAttribute, LinearMipmapLinearFilter, NearestMipmapLinearFilter, LinearMipmapNearestFilter, NearestMipmapNearestFilter, LinearFilter, NearestFilter, RepeatWrapping, MirroredRepeatWrapping, ClampToEdgeWrapping, MeshStandardMaterial, DataTexture, FloatType, TriangleStripDrawMode, TriangleFanDrawMode, LineSegments, LineLoop, Group, NormalBlending, LoadingManager, LoaderUtils, FileLoader, 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';
|
|
30
30
|
import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js';
|
|
31
|
+
import { LineSegments2 } from 'three/examples/jsm/lines/LineSegments2.js';
|
|
31
32
|
import { mergeGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils.js';
|
|
32
33
|
import { JSONParser } from '@streamparser/json';
|
|
33
34
|
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
|
|
34
35
|
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
|
|
35
36
|
import { FXAAPass } from 'three/examples/jsm/postprocessing/FXAAPass.js';
|
|
36
37
|
import { SMAAPass } from 'three/examples/jsm/postprocessing/SMAAPass.js';
|
|
37
|
-
import {
|
|
38
|
-
import { CopyShader } from 'three/examples/jsm/shaders/CopyShader.js';
|
|
38
|
+
import { SSAARenderPass } from 'three/examples/jsm/postprocessing/SSAARenderPass.js';
|
|
39
39
|
import { OutputPass } from 'three/examples/jsm/postprocessing/OutputPass.js';
|
|
40
40
|
import { EventEmitter2 } from '@inweb/eventemitter2';
|
|
41
41
|
import { Markup } from '@inweb/markup';
|
|
@@ -751,9 +751,9 @@ const _line = new Line3();
|
|
|
751
751
|
const _center = new Vector3();
|
|
752
752
|
const _projection = new Vector3();
|
|
753
753
|
class Snapper {
|
|
754
|
-
constructor(camera,
|
|
754
|
+
constructor(camera, clippingPlanes, canvas) {
|
|
755
755
|
this.camera = camera;
|
|
756
|
-
this.
|
|
756
|
+
this.clippingPlanes = clippingPlanes;
|
|
757
757
|
this.canvas = canvas;
|
|
758
758
|
this.threshold = 0.0001;
|
|
759
759
|
this.raycaster = new Raycaster();
|
|
@@ -784,7 +784,7 @@ class Snapper {
|
|
|
784
784
|
};
|
|
785
785
|
let intersects = this.raycaster.intersectObjects(objects, recursive);
|
|
786
786
|
if (clip) {
|
|
787
|
-
const clippingPlanes = this.
|
|
787
|
+
const clippingPlanes = this.clippingPlanes;
|
|
788
788
|
clippingPlanes.forEach((plane) => {
|
|
789
789
|
intersects = intersects.filter((intersect) => plane.distanceToPoint(intersect.point) >= 0);
|
|
790
790
|
});
|
|
@@ -871,7 +871,7 @@ class OrbitDragger {
|
|
|
871
871
|
this.orbit.object = this.viewer.camera;
|
|
872
872
|
this.orbit.update();
|
|
873
873
|
};
|
|
874
|
-
this.
|
|
874
|
+
this.updateZoomSpeed = ({ data: options }) => {
|
|
875
875
|
this.orbit.zoomSpeed = Math.abs(this.orbit.zoomSpeed) * (options.reverseZoomWheel ? -1 : 1);
|
|
876
876
|
};
|
|
877
877
|
this.controlsStart = () => {
|
|
@@ -930,7 +930,7 @@ class OrbitDragger {
|
|
|
930
930
|
this.viewer.addEventListener("zoom", this.updateControls);
|
|
931
931
|
this.viewer.addEventListener("drawviewpoint", this.updateControls);
|
|
932
932
|
this.viewer.addEventListener("changecameramode", this.updateControlsCamera);
|
|
933
|
-
this.viewer.addEventListener("optionschange", this.
|
|
933
|
+
this.viewer.addEventListener("optionschange", this.updateZoomSpeed);
|
|
934
934
|
this.viewer.addEventListener("contextmenu", this.stopContextMenu);
|
|
935
935
|
this.updateControls();
|
|
936
936
|
this.updateControlsCamera();
|
|
@@ -942,7 +942,7 @@ class OrbitDragger {
|
|
|
942
942
|
this.viewer.removeEventListener("zoom", this.updateControls);
|
|
943
943
|
this.viewer.removeEventListener("drawviewpoint", this.updateControls);
|
|
944
944
|
this.viewer.removeEventListener("changecameramode", this.updateControlsCamera);
|
|
945
|
-
this.viewer.removeEventListener("optionschange", this.
|
|
945
|
+
this.viewer.removeEventListener("optionschange", this.updateZoomSpeed);
|
|
946
946
|
this.viewer.removeEventListener("contextmenu", this.stopContextMenu);
|
|
947
947
|
this.orbit.removeEventListener("start", this.controlsStart);
|
|
948
948
|
this.orbit.removeEventListener("change", this.controlsChange);
|
|
@@ -954,13 +954,17 @@ class CuttingPlaneDragger extends OrbitDragger {
|
|
|
954
954
|
constructor(viewer) {
|
|
955
955
|
super(viewer);
|
|
956
956
|
this.helpers = [];
|
|
957
|
-
this.activeHelper =
|
|
957
|
+
this.activeHelper = undefined;
|
|
958
|
+
this.transformUpdate = () => {
|
|
959
|
+
this.viewer.update();
|
|
960
|
+
};
|
|
958
961
|
this.transformChange = () => {
|
|
959
962
|
if (!this.activeHelper)
|
|
960
963
|
return;
|
|
961
964
|
const plane = this.activeHelper.plane;
|
|
962
965
|
plane.normal.copy(new Vector3(0, 0, -1)).applyQuaternion(this.activeHelper.quaternion);
|
|
963
966
|
plane.constant = -this.activeHelper.position.dot(plane.normal);
|
|
967
|
+
this.viewer.emitEvent({ type: "changecuttingplanes" });
|
|
964
968
|
this.viewer.update();
|
|
965
969
|
this.changed = true;
|
|
966
970
|
};
|
|
@@ -972,25 +976,29 @@ class CuttingPlaneDragger extends OrbitDragger {
|
|
|
972
976
|
this.orbit.enabled = !event.value;
|
|
973
977
|
this.translate.enabled = !event.value;
|
|
974
978
|
};
|
|
975
|
-
this.
|
|
979
|
+
this.syncHelpers = () => {
|
|
976
980
|
const extentsSize = this.viewer.extents.getSize(new Vector3()).length() || 1;
|
|
977
|
-
this.
|
|
981
|
+
const extentsCenter = this.viewer.extents.getCenter(new Vector3());
|
|
982
|
+
this.helpers.forEach((planeHelper) => {
|
|
983
|
+
planeHelper.size = extentsSize;
|
|
984
|
+
planeHelper.position.copy(planeHelper.plane.projectPoint(extentsCenter, new Vector3()));
|
|
985
|
+
});
|
|
978
986
|
this.viewer.update();
|
|
979
987
|
};
|
|
980
|
-
this.updateTransformCamera = () => {
|
|
981
|
-
this.translate.camera = this.viewer.camera;
|
|
982
|
-
this.rotate.camera = this.viewer.camera;
|
|
983
|
-
this.snapper.camera = this.viewer.camera;
|
|
984
|
-
};
|
|
985
988
|
this.clearHelpers = () => {
|
|
986
989
|
this.setActiveHelper();
|
|
987
990
|
this.helpers.forEach((helper) => {
|
|
988
991
|
helper.removeFromParent();
|
|
989
992
|
helper.dispose();
|
|
990
993
|
});
|
|
991
|
-
this.helpers =
|
|
994
|
+
this.helpers.length = 0;
|
|
992
995
|
this.viewer.update();
|
|
993
996
|
};
|
|
997
|
+
this.updateTransformCamera = () => {
|
|
998
|
+
this.translate.camera = this.viewer.camera;
|
|
999
|
+
this.rotate.camera = this.viewer.camera;
|
|
1000
|
+
this.snapper.camera = this.viewer.camera;
|
|
1001
|
+
};
|
|
994
1002
|
this.onKeyDown = (event) => {
|
|
995
1003
|
if (event.key === "Shift")
|
|
996
1004
|
this.rotate.setRotationSnap(Math.PI / 4);
|
|
@@ -1034,12 +1042,9 @@ class CuttingPlaneDragger extends OrbitDragger {
|
|
|
1034
1042
|
this.transformChange();
|
|
1035
1043
|
event.stopPropagation();
|
|
1036
1044
|
};
|
|
1037
|
-
|
|
1038
|
-
viewer.renderer.clippingPlanes = [];
|
|
1039
|
-
this.clippingPlanes = viewer.renderer.clippingPlanes;
|
|
1040
|
-
this.clippingPlanes.forEach((plane) => this.addHelper(plane));
|
|
1045
|
+
viewer.clippingPlanes.forEach((plane) => this.addHelper(plane));
|
|
1041
1046
|
const extentsSize = viewer.extents.getSize(new Vector3()).length() || 1;
|
|
1042
|
-
this.snapper = new Snapper(viewer.camera, viewer.
|
|
1047
|
+
this.snapper = new Snapper(viewer.camera, viewer.clippingPlanes, viewer.canvas);
|
|
1043
1048
|
this.snapper.threshold = extentsSize / 10000;
|
|
1044
1049
|
this.downPosition = new Vector2();
|
|
1045
1050
|
this.position0 = new Vector3();
|
|
@@ -1050,7 +1055,8 @@ class CuttingPlaneDragger extends OrbitDragger {
|
|
|
1050
1055
|
this.translate.showX = false;
|
|
1051
1056
|
this.translate.showY = false;
|
|
1052
1057
|
this.translate.showZ = true;
|
|
1053
|
-
this.translate.addEventListener("change", this.
|
|
1058
|
+
this.translate.addEventListener("change", this.transformUpdate);
|
|
1059
|
+
this.translate.addEventListener("objectChange", this.transformChange);
|
|
1054
1060
|
this.translate.addEventListener("dragging-changed", this.translateDrag);
|
|
1055
1061
|
this.viewer.helpers.add(this.translate.getHelper());
|
|
1056
1062
|
this.rotate = new TransformControls(viewer.camera, viewer.canvas);
|
|
@@ -1059,15 +1065,18 @@ class CuttingPlaneDragger extends OrbitDragger {
|
|
|
1059
1065
|
this.rotate.showX = true;
|
|
1060
1066
|
this.rotate.showY = true;
|
|
1061
1067
|
this.rotate.showZ = false;
|
|
1062
|
-
this.rotate.addEventListener("change", this.
|
|
1068
|
+
this.rotate.addEventListener("change", this.transformUpdate);
|
|
1069
|
+
this.rotate.addEventListener("objectChange", this.transformChange);
|
|
1063
1070
|
this.rotate.addEventListener("dragging-changed", this.rotateDrag);
|
|
1064
1071
|
this.viewer.helpers.add(this.rotate.getHelper());
|
|
1065
1072
|
this.setActiveHelper(this.helpers[this.helpers.length - 1]);
|
|
1066
|
-
this.viewer.addEventListener("explode", this.
|
|
1067
|
-
this.viewer.addEventListener("
|
|
1068
|
-
this.viewer.addEventListener("
|
|
1069
|
-
this.viewer.addEventListener("
|
|
1073
|
+
this.viewer.addEventListener("explode", this.syncHelpers);
|
|
1074
|
+
this.viewer.addEventListener("hide", this.syncHelpers);
|
|
1075
|
+
this.viewer.addEventListener("isolate", this.syncHelpers);
|
|
1076
|
+
this.viewer.addEventListener("show", this.syncHelpers);
|
|
1077
|
+
this.viewer.addEventListener("showall", this.syncHelpers);
|
|
1070
1078
|
this.viewer.addEventListener("clearslices", this.clearHelpers);
|
|
1079
|
+
this.viewer.addEventListener("changecameramode", this.updateTransformCamera);
|
|
1071
1080
|
this.viewer.canvas.addEventListener("pointerdown", this.onPointerDown, true);
|
|
1072
1081
|
this.viewer.canvas.addEventListener("pointerup", this.onPointerUp, true);
|
|
1073
1082
|
this.viewer.canvas.addEventListener("pointercancel", this.onPointerCancel, true);
|
|
@@ -1077,23 +1086,27 @@ class CuttingPlaneDragger extends OrbitDragger {
|
|
|
1077
1086
|
this.viewer.update();
|
|
1078
1087
|
}
|
|
1079
1088
|
dispose() {
|
|
1080
|
-
this.viewer.removeEventListener("explode", this.
|
|
1081
|
-
this.viewer.removeEventListener("
|
|
1082
|
-
this.viewer.removeEventListener("
|
|
1083
|
-
this.viewer.removeEventListener("
|
|
1089
|
+
this.viewer.removeEventListener("explode", this.syncHelpers);
|
|
1090
|
+
this.viewer.removeEventListener("hide", this.syncHelpers);
|
|
1091
|
+
this.viewer.removeEventListener("isolate", this.syncHelpers);
|
|
1092
|
+
this.viewer.removeEventListener("show", this.syncHelpers);
|
|
1093
|
+
this.viewer.removeEventListener("showall", this.syncHelpers);
|
|
1084
1094
|
this.viewer.removeEventListener("clearslices", this.clearHelpers);
|
|
1095
|
+
this.viewer.removeEventListener("changecameramode", this.updateTransformCamera);
|
|
1085
1096
|
this.viewer.canvas.removeEventListener("pointerdown", this.onPointerDown, true);
|
|
1086
1097
|
this.viewer.canvas.removeEventListener("pointerup", this.onPointerUp, true);
|
|
1087
1098
|
this.viewer.canvas.removeEventListener("pointercancel", this.onPointerCancel, true);
|
|
1088
1099
|
this.viewer.canvas.removeEventListener("dblclick", this.onDoubleClick, true);
|
|
1089
1100
|
window.removeEventListener("keydown", this.onKeyDown);
|
|
1090
1101
|
window.removeEventListener("keyup", this.onKeyUp);
|
|
1091
|
-
this.translate.removeEventListener("change", this.
|
|
1102
|
+
this.translate.removeEventListener("change", this.transformUpdate);
|
|
1103
|
+
this.translate.removeEventListener("objectChange", this.transformChange);
|
|
1092
1104
|
this.translate.removeEventListener("dragging-changed", this.translateDrag);
|
|
1093
1105
|
this.translate.getHelper().removeFromParent();
|
|
1094
1106
|
this.translate.detach();
|
|
1095
1107
|
this.translate.dispose();
|
|
1096
|
-
this.rotate.removeEventListener("change", this.
|
|
1108
|
+
this.rotate.removeEventListener("change", this.transformUpdate);
|
|
1109
|
+
this.rotate.removeEventListener("objectChange", this.transformChange);
|
|
1097
1110
|
this.rotate.removeEventListener("dragging-changed", this.rotateDrag);
|
|
1098
1111
|
this.rotate.getHelper().removeFromParent();
|
|
1099
1112
|
this.rotate.detach();
|
|
@@ -1102,8 +1115,8 @@ class CuttingPlaneDragger extends OrbitDragger {
|
|
|
1102
1115
|
helper.removeFromParent();
|
|
1103
1116
|
helper.dispose();
|
|
1104
1117
|
});
|
|
1105
|
-
this.helpers =
|
|
1106
|
-
this.activeHelper =
|
|
1118
|
+
this.helpers.length = 0;
|
|
1119
|
+
this.activeHelper = undefined;
|
|
1107
1120
|
super.dispose();
|
|
1108
1121
|
}
|
|
1109
1122
|
addHelper(plane) {
|
|
@@ -1155,9 +1168,10 @@ class CuttingPlaneDragger extends OrbitDragger {
|
|
|
1155
1168
|
const extentsCenter = this.viewer.extents.getCenter(new Vector3());
|
|
1156
1169
|
const constant = -extentsCenter.dot(normal);
|
|
1157
1170
|
const plane = new Plane(normal, constant);
|
|
1158
|
-
this.clippingPlanes.push(plane);
|
|
1171
|
+
this.viewer.clippingPlanes.push(plane);
|
|
1159
1172
|
const helper = this.addHelper(plane);
|
|
1160
1173
|
this.setActiveHelper(helper);
|
|
1174
|
+
this.viewer.emitEvent({ type: "changecuttingplanes" });
|
|
1161
1175
|
}
|
|
1162
1176
|
addPlaneX() {
|
|
1163
1177
|
this.addPlane(new Vector3(-1, 0, 0));
|
|
@@ -1172,13 +1186,14 @@ class CuttingPlaneDragger extends OrbitDragger {
|
|
|
1172
1186
|
if (!this.activeHelper)
|
|
1173
1187
|
return;
|
|
1174
1188
|
const helper = this.activeHelper;
|
|
1175
|
-
const index = this.clippingPlanes.indexOf(helper.plane);
|
|
1189
|
+
const index = this.viewer.clippingPlanes.indexOf(helper.plane);
|
|
1176
1190
|
if (index !== -1)
|
|
1177
|
-
this.clippingPlanes.splice(index, 1);
|
|
1191
|
+
this.viewer.clippingPlanes.splice(index, 1);
|
|
1178
1192
|
this.helpers = this.helpers.filter((x) => x !== helper);
|
|
1179
1193
|
helper.removeFromParent();
|
|
1180
1194
|
helper.dispose();
|
|
1181
1195
|
this.setActiveHelper(this.helpers[this.helpers.length - 1]);
|
|
1196
|
+
this.viewer.emitEvent({ type: "changecuttingplanes" });
|
|
1182
1197
|
}
|
|
1183
1198
|
}
|
|
1184
1199
|
|
|
@@ -1372,7 +1387,7 @@ class MeasureLineDragger extends OrbitDragger {
|
|
|
1372
1387
|
this.line = new MeasureLine(this.overlay, this.scale, this.units, this.precision);
|
|
1373
1388
|
this.overlay.addLine(this.line);
|
|
1374
1389
|
const extentsSize = this.viewer.extents.getSize(new Vector3()).length() || 1;
|
|
1375
|
-
this.snapper = new Snapper(viewer.camera, viewer.
|
|
1390
|
+
this.snapper = new Snapper(viewer.camera, viewer.clippingPlanes, viewer.canvas);
|
|
1376
1391
|
this.snapper.threshold = extentsSize / 10000;
|
|
1377
1392
|
this.objects = [];
|
|
1378
1393
|
this.updateObjects();
|
|
@@ -2651,8 +2666,8 @@ commands.registerCommand("left", (viewer) => setDefaultViewPosition(viewer, "lef
|
|
|
2651
2666
|
commands.registerCommand("right", (viewer) => setDefaultViewPosition(viewer, "right"));
|
|
2652
2667
|
commands.registerCommand("front", (viewer) => setDefaultViewPosition(viewer, "front"));
|
|
2653
2668
|
commands.registerCommand("back", (viewer) => setDefaultViewPosition(viewer, "back"));
|
|
2654
|
-
commands.registerCommand("sw", (viewer) => setDefaultViewPosition(viewer, "sw"));
|
|
2655
2669
|
commands.registerCommand("se", (viewer) => setDefaultViewPosition(viewer, "se"));
|
|
2670
|
+
commands.registerCommand("sw", (viewer) => setDefaultViewPosition(viewer, "sw"));
|
|
2656
2671
|
commands.registerCommand("ne", (viewer) => setDefaultViewPosition(viewer, "ne"));
|
|
2657
2672
|
commands.registerCommand("nw", (viewer) => setDefaultViewPosition(viewer, "nw"));
|
|
2658
2673
|
commands.registerCommandAlias("clearMarkup", "clearOverlay");
|
|
@@ -2675,6 +2690,7 @@ class BackgroundComponent {
|
|
|
2675
2690
|
this.syncOptions = () => {
|
|
2676
2691
|
this.backgroundColor.setHex(0xffffff);
|
|
2677
2692
|
this.viewer.renderer.setClearColor(this.backgroundColor);
|
|
2693
|
+
this.viewer.update();
|
|
2678
2694
|
};
|
|
2679
2695
|
this.viewer = viewer;
|
|
2680
2696
|
this.backgroundColor = new Color(0xffffff);
|
|
@@ -2690,7 +2706,7 @@ class BackgroundComponent {
|
|
|
2690
2706
|
|
|
2691
2707
|
class CameraComponent {
|
|
2692
2708
|
constructor(viewer) {
|
|
2693
|
-
this.
|
|
2709
|
+
this.syncOptions = () => {
|
|
2694
2710
|
this.switchCameraMode(this.viewer.options.cameraMode);
|
|
2695
2711
|
};
|
|
2696
2712
|
this.geometryEnd = () => {
|
|
@@ -2721,13 +2737,13 @@ class CameraComponent {
|
|
|
2721
2737
|
};
|
|
2722
2738
|
this.viewer = viewer;
|
|
2723
2739
|
this.viewer.addEventListener("databasechunk", this.geometryEnd);
|
|
2724
|
-
this.viewer.addEventListener("optionschange", this.
|
|
2725
|
-
this.viewer.addEventListener("initialize", this.
|
|
2740
|
+
this.viewer.addEventListener("optionschange", this.syncOptions);
|
|
2741
|
+
this.viewer.addEventListener("initialize", this.syncOptions);
|
|
2726
2742
|
}
|
|
2727
2743
|
dispose() {
|
|
2728
2744
|
this.viewer.removeEventListener("databasechunk", this.geometryEnd);
|
|
2729
|
-
this.viewer.removeEventListener("optionschange", this.
|
|
2730
|
-
this.viewer.removeEventListener("initialize", this.
|
|
2745
|
+
this.viewer.removeEventListener("optionschange", this.syncOptions);
|
|
2746
|
+
this.viewer.removeEventListener("initialize", this.syncOptions);
|
|
2731
2747
|
}
|
|
2732
2748
|
getCameraMode(camera) {
|
|
2733
2749
|
return camera.isOrthographicCamera ? "orthographic" : "perspective";
|
|
@@ -2750,7 +2766,6 @@ class CameraComponent {
|
|
|
2750
2766
|
camera.updateProjectionMatrix();
|
|
2751
2767
|
this.viewer.camera = camera;
|
|
2752
2768
|
this.viewer.renderPass.camera = camera;
|
|
2753
|
-
this.viewer.helpersPass.camera = camera;
|
|
2754
2769
|
this.viewer.ssaaRenderPass.camera = camera;
|
|
2755
2770
|
this.viewer.update();
|
|
2756
2771
|
}
|
|
@@ -2894,7 +2909,7 @@ class InfoComponent {
|
|
|
2894
2909
|
console.log("WebGL Renderer:", this.viewer.info.system.webglRenderer);
|
|
2895
2910
|
console.log("WebGL Vendor:", this.viewer.info.system.webglVendor);
|
|
2896
2911
|
this.resize();
|
|
2897
|
-
this.
|
|
2912
|
+
this.syncOptions({ data: this.viewer.options });
|
|
2898
2913
|
};
|
|
2899
2914
|
this.clear = () => {
|
|
2900
2915
|
this.viewer.info.performance.timeToFirstRender = 0;
|
|
@@ -2918,7 +2933,7 @@ class InfoComponent {
|
|
|
2918
2933
|
this.viewer.info.memory.totalEstimatedGpuBytes = 0;
|
|
2919
2934
|
this.viewer.info.memory.usedJSHeapSize = 0;
|
|
2920
2935
|
};
|
|
2921
|
-
this.
|
|
2936
|
+
this.syncOptions = ({ data: options }) => {
|
|
2922
2937
|
if (options.antialiasing === false)
|
|
2923
2938
|
this.viewer.info.render.antialiasing = "";
|
|
2924
2939
|
else if (options.antialiasing === true)
|
|
@@ -2993,7 +3008,7 @@ class InfoComponent {
|
|
|
2993
3008
|
this.frames = 0;
|
|
2994
3009
|
this.viewer.addEventListener("initialize", this.initialize);
|
|
2995
3010
|
this.viewer.addEventListener("clear", this.clear);
|
|
2996
|
-
this.viewer.addEventListener("optionschange", this.
|
|
3011
|
+
this.viewer.addEventListener("optionschange", this.syncOptions);
|
|
2997
3012
|
this.viewer.addEventListener("geometrystart", this.geometryStart);
|
|
2998
3013
|
this.viewer.addEventListener("databasechunk", this.databaseChunk);
|
|
2999
3014
|
this.viewer.addEventListener("geometryend", this.geometryEnd);
|
|
@@ -3004,7 +3019,7 @@ class InfoComponent {
|
|
|
3004
3019
|
dispose() {
|
|
3005
3020
|
this.viewer.removeEventListener("initialize", this.initialize);
|
|
3006
3021
|
this.viewer.removeEventListener("clear", this.clear);
|
|
3007
|
-
this.viewer.removeEventListener("optionschange", this.
|
|
3022
|
+
this.viewer.removeEventListener("optionschange", this.syncOptions);
|
|
3008
3023
|
this.viewer.removeEventListener("geometrystart", this.geometryStart);
|
|
3009
3024
|
this.viewer.removeEventListener("databasechunk", this.databaseChunk);
|
|
3010
3025
|
this.viewer.removeEventListener("geometryend", this.geometryEnd);
|
|
@@ -3142,28 +3157,38 @@ class HighlighterComponent {
|
|
|
3142
3157
|
polygonOffset: true,
|
|
3143
3158
|
polygonOffsetFactor: 1,
|
|
3144
3159
|
polygonOffsetUnits: 1,
|
|
3160
|
+
clippingPlanes: this.viewer.clippingPlanes,
|
|
3145
3161
|
});
|
|
3146
3162
|
this.edgesMaterial = new LineMaterial({
|
|
3147
3163
|
linewidth: 1.5,
|
|
3148
3164
|
resolution: new Vector2(window.innerWidth, window.innerHeight),
|
|
3165
|
+
clippingPlanes: this.viewer.clippingPlanes,
|
|
3149
3166
|
});
|
|
3150
3167
|
this.lineMaterial = new LineBasicMaterial({
|
|
3151
3168
|
transparent: true,
|
|
3152
3169
|
depthTest: true,
|
|
3153
3170
|
depthWrite: true,
|
|
3171
|
+
clippingPlanes: this.viewer.clippingPlanes,
|
|
3154
3172
|
});
|
|
3155
3173
|
this.lineGlowMaterial = new LineMaterial({
|
|
3156
3174
|
linewidth: 1.5,
|
|
3157
3175
|
transparent: true,
|
|
3158
3176
|
opacity: 0.8,
|
|
3159
3177
|
resolution: new Vector2(window.innerWidth, window.innerHeight),
|
|
3178
|
+
clippingPlanes: this.viewer.clippingPlanes,
|
|
3160
3179
|
});
|
|
3161
3180
|
this.syncHighlightColors();
|
|
3162
3181
|
};
|
|
3163
|
-
this.
|
|
3182
|
+
this.syncOptions = () => {
|
|
3164
3183
|
this.syncHighlightColors();
|
|
3165
3184
|
this.viewer.update();
|
|
3166
3185
|
};
|
|
3186
|
+
this.viewerResize = (event) => {
|
|
3187
|
+
var _a, _b, _c;
|
|
3188
|
+
(_a = this.renderTarget) === null || _a === void 0 ? void 0 : _a.setSize(event.width, event.height);
|
|
3189
|
+
(_b = this.edgesMaterial) === null || _b === void 0 ? void 0 : _b.resolution.set(event.width, event.height);
|
|
3190
|
+
(_c = this.lineGlowMaterial) === null || _c === void 0 ? void 0 : _c.resolution.set(event.width, event.height);
|
|
3191
|
+
};
|
|
3167
3192
|
this.viewer = viewer;
|
|
3168
3193
|
const gl2 = viewer.canvas.getContext("webgl2");
|
|
3169
3194
|
if (gl2) {
|
|
@@ -3176,13 +3201,13 @@ class HighlighterComponent {
|
|
|
3176
3201
|
});
|
|
3177
3202
|
}
|
|
3178
3203
|
this.viewer.addEventListener("databasechunk", this.geometryEnd);
|
|
3179
|
-
this.viewer.addEventListener("optionschange", this.
|
|
3204
|
+
this.viewer.addEventListener("optionschange", this.syncOptions);
|
|
3180
3205
|
this.viewer.addEventListener("resize", this.viewerResize);
|
|
3181
3206
|
this.geometryEnd();
|
|
3182
3207
|
}
|
|
3183
3208
|
dispose() {
|
|
3184
3209
|
this.viewer.removeEventListener("databasechunk", this.geometryEnd);
|
|
3185
|
-
this.viewer.removeEventListener("optionschange", this.
|
|
3210
|
+
this.viewer.removeEventListener("optionschange", this.syncOptions);
|
|
3186
3211
|
this.viewer.removeEventListener("resize", this.viewerResize);
|
|
3187
3212
|
}
|
|
3188
3213
|
highlight(objects) {
|
|
@@ -3261,12 +3286,6 @@ class HighlighterComponent {
|
|
|
3261
3286
|
wireframe.visible = edgesVisibility;
|
|
3262
3287
|
});
|
|
3263
3288
|
}
|
|
3264
|
-
viewerResize(event) {
|
|
3265
|
-
var _a, _b, _c;
|
|
3266
|
-
(_a = this.renderTarget) === null || _a === void 0 ? void 0 : _a.setSize(event.width, event.height);
|
|
3267
|
-
(_b = this.edgesMaterial) === null || _b === void 0 ? void 0 : _b.resolution.set(event.width, event.height);
|
|
3268
|
-
(_c = this.lineGlowMaterial) === null || _c === void 0 ? void 0 : _c.resolution.set(event.width, event.height);
|
|
3269
|
-
}
|
|
3270
3289
|
}
|
|
3271
3290
|
|
|
3272
3291
|
class SelectionComponent {
|
|
@@ -3283,7 +3302,7 @@ class SelectionComponent {
|
|
|
3283
3302
|
if (upPosition.distanceTo(this.downPosition) !== 0)
|
|
3284
3303
|
return;
|
|
3285
3304
|
const extentsSize = this.viewer.extents.getSize(new Vector3()).length() || 1;
|
|
3286
|
-
const snapper = new Snapper(this.viewer.camera, this.viewer.
|
|
3305
|
+
const snapper = new Snapper(this.viewer.camera, this.viewer.clippingPlanes, this.viewer.canvas);
|
|
3287
3306
|
snapper.threshold = extentsSize / 10000;
|
|
3288
3307
|
let intersections = [];
|
|
3289
3308
|
this.viewer.models.forEach((model) => {
|
|
@@ -3380,9 +3399,824 @@ class SelectionComponent {
|
|
|
3380
3399
|
}
|
|
3381
3400
|
}
|
|
3382
3401
|
|
|
3402
|
+
class ClippingPlaneComponent {
|
|
3403
|
+
constructor(viewer) {
|
|
3404
|
+
this.applyClippingPlanes = () => {
|
|
3405
|
+
this.viewer.models.forEach((model) => {
|
|
3406
|
+
model.scene.traverse((object) => {
|
|
3407
|
+
if (object.material) {
|
|
3408
|
+
const materials = Array.isArray(object.material) ? object.material : [object.material];
|
|
3409
|
+
materials.forEach((material) => (material.clippingPlanes = this.viewer.clippingPlanes));
|
|
3410
|
+
}
|
|
3411
|
+
});
|
|
3412
|
+
});
|
|
3413
|
+
};
|
|
3414
|
+
this.viewer = viewer;
|
|
3415
|
+
this.viewer.addEventListener("geometryend", this.applyClippingPlanes);
|
|
3416
|
+
this.viewer.addEventListener("changecuttingplanes", this.applyClippingPlanes);
|
|
3417
|
+
}
|
|
3418
|
+
dispose() {
|
|
3419
|
+
this.viewer.removeEventListener("geometryend", this.applyClippingPlanes);
|
|
3420
|
+
this.viewer.removeEventListener("changecuttingplanes", this.applyClippingPlanes);
|
|
3421
|
+
}
|
|
3422
|
+
}
|
|
3423
|
+
|
|
3424
|
+
class PointHashGrid {
|
|
3425
|
+
constructor(tolerance = 1e-5) {
|
|
3426
|
+
this.tolerance = tolerance;
|
|
3427
|
+
this.points = [];
|
|
3428
|
+
this.grid = new Map();
|
|
3429
|
+
}
|
|
3430
|
+
_hash(hx, hy, hz) {
|
|
3431
|
+
return `${hx},${hy},${hz}`;
|
|
3432
|
+
}
|
|
3433
|
+
add(v) {
|
|
3434
|
+
const hx = Math.round(v.x / this.tolerance);
|
|
3435
|
+
const hy = Math.round(v.y / this.tolerance);
|
|
3436
|
+
const hz = Math.round(v.z / this.tolerance);
|
|
3437
|
+
for (let i = -1; i <= 1; i++) {
|
|
3438
|
+
for (let j = -1; j <= 1; j++) {
|
|
3439
|
+
for (let k = -1; k <= 1; k++) {
|
|
3440
|
+
const hash = this._hash(hx + i, hy + j, hz + k);
|
|
3441
|
+
const cell = this.grid.get(hash);
|
|
3442
|
+
if (cell) {
|
|
3443
|
+
for (const id of cell) {
|
|
3444
|
+
if (this.points[id].distanceTo(v) <= this.tolerance) return id;
|
|
3445
|
+
}
|
|
3446
|
+
}
|
|
3447
|
+
}
|
|
3448
|
+
}
|
|
3449
|
+
}
|
|
3450
|
+
const id = this.points.length;
|
|
3451
|
+
this.points.push(v.clone());
|
|
3452
|
+
const centerHash = this._hash(hx, hy, hz);
|
|
3453
|
+
if (!this.grid.has(centerHash)) this.grid.set(centerHash, []);
|
|
3454
|
+
this.grid.get(centerHash).push(id);
|
|
3455
|
+
return id;
|
|
3456
|
+
}
|
|
3457
|
+
}
|
|
3458
|
+
class SectionsHelper extends Object3D {
|
|
3459
|
+
constructor() {
|
|
3460
|
+
super();
|
|
3461
|
+
this.type = "SectionsHelper";
|
|
3462
|
+
this.flags = {
|
|
3463
|
+
fillEnabled: true,
|
|
3464
|
+
fillColor: "#fffde7",
|
|
3465
|
+
hatchEnabled: true,
|
|
3466
|
+
hatchColor: "#000000",
|
|
3467
|
+
hatchScale: 8.0,
|
|
3468
|
+
outlineEnabled: true,
|
|
3469
|
+
outlineColor: "#000000",
|
|
3470
|
+
outlineWidth: 2,
|
|
3471
|
+
boundaryOnly: true,
|
|
3472
|
+
showDebugSeams: false,
|
|
3473
|
+
showDebugPoints: false,
|
|
3474
|
+
showDebugSegments: false,
|
|
3475
|
+
showDebugGaps: false,
|
|
3476
|
+
showDebugInfo: false,
|
|
3477
|
+
useObjFillColor: false,
|
|
3478
|
+
useObjOutlineColor: false,
|
|
3479
|
+
};
|
|
3480
|
+
this._caps = [];
|
|
3481
|
+
this._outlines = [];
|
|
3482
|
+
this._debugPoints = [];
|
|
3483
|
+
this._debugSegments = [];
|
|
3484
|
+
this._debugGaps = [];
|
|
3485
|
+
this._vA = new Vector3();
|
|
3486
|
+
this._vB = new Vector3();
|
|
3487
|
+
this._vC = new Vector3();
|
|
3488
|
+
this._worldBox = new Box3();
|
|
3489
|
+
}
|
|
3490
|
+
dispose() {
|
|
3491
|
+
const disposeMesh = (item) => {
|
|
3492
|
+
if (item.geometry) item.geometry.dispose();
|
|
3493
|
+
if (item.material) item.material.dispose();
|
|
3494
|
+
this.remove(item);
|
|
3495
|
+
};
|
|
3496
|
+
this._caps.forEach(disposeMesh);
|
|
3497
|
+
this._outlines.forEach(disposeMesh);
|
|
3498
|
+
this._debugPoints.forEach(disposeMesh);
|
|
3499
|
+
this._debugSegments.forEach(disposeMesh);
|
|
3500
|
+
this._debugGaps.forEach(disposeMesh);
|
|
3501
|
+
this._caps.length = 0;
|
|
3502
|
+
this._outlines.length = 0;
|
|
3503
|
+
this._debugPoints.length = 0;
|
|
3504
|
+
this._debugSegments.length = 0;
|
|
3505
|
+
this._debugGaps.length = 0;
|
|
3506
|
+
}
|
|
3507
|
+
setSize(width, height) {
|
|
3508
|
+
this._outlines.forEach((o) => {
|
|
3509
|
+
if (o.material.resolution) o.material.resolution.set(width, height);
|
|
3510
|
+
});
|
|
3511
|
+
this._debugSegments.forEach((s) => {
|
|
3512
|
+
if (s.material.resolution) s.material.resolution.set(width, height);
|
|
3513
|
+
});
|
|
3514
|
+
}
|
|
3515
|
+
_ensureHelpersCount(count) {
|
|
3516
|
+
const hatchVertexShader = `
|
|
3517
|
+
#include <common>
|
|
3518
|
+
#include <logdepthbuf_pars_vertex>
|
|
3519
|
+
#include <clipping_planes_pars_vertex>
|
|
3520
|
+
|
|
3521
|
+
attribute float aHatchDir;
|
|
3522
|
+
attribute vec3 aFillColor;
|
|
3523
|
+
|
|
3524
|
+
varying vec3 vWP;
|
|
3525
|
+
varying float vHatchDir;
|
|
3526
|
+
varying vec3 vFillColor;
|
|
3527
|
+
|
|
3528
|
+
void main() {
|
|
3529
|
+
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
|
|
3530
|
+
#include <clipping_planes_vertex>
|
|
3531
|
+
|
|
3532
|
+
vWP = (modelMatrix * vec4(position, 1.0)).xyz;
|
|
3533
|
+
vHatchDir = aHatchDir;
|
|
3534
|
+
vFillColor = aFillColor;
|
|
3535
|
+
|
|
3536
|
+
gl_Position = projectionMatrix * mvPosition;
|
|
3537
|
+
#include <logdepthbuf_vertex>
|
|
3538
|
+
}
|
|
3539
|
+
`;
|
|
3540
|
+
const hatchFragmentShader = `
|
|
3541
|
+
#include <common>
|
|
3542
|
+
#include <logdepthbuf_pars_fragment>
|
|
3543
|
+
#include <clipping_planes_pars_fragment>
|
|
3544
|
+
|
|
3545
|
+
uniform vec3 lineColor;
|
|
3546
|
+
uniform float uHatchScale;
|
|
3547
|
+
uniform float uHatchEnabled;
|
|
3548
|
+
|
|
3549
|
+
varying vec3 vWP;
|
|
3550
|
+
varying float vHatchDir;
|
|
3551
|
+
varying vec3 vFillColor;
|
|
3552
|
+
|
|
3553
|
+
void main() {
|
|
3554
|
+
#include <clipping_planes_fragment>
|
|
3555
|
+
#include <logdepthbuf_fragment>
|
|
3556
|
+
|
|
3557
|
+
float v1 = mod(gl_FragCoord.x + gl_FragCoord.y, uHatchScale);
|
|
3558
|
+
float v2 = mod(gl_FragCoord.x - gl_FragCoord.y, uHatchScale);
|
|
3559
|
+
float v = mix(v1, v2, vHatchDir);
|
|
3560
|
+
|
|
3561
|
+
float hatchMask = step(v, 1.5) * uHatchEnabled;
|
|
3562
|
+
gl_FragColor = vec4(mix(vFillColor, lineColor, hatchMask), 1.0);
|
|
3563
|
+
}
|
|
3564
|
+
`;
|
|
3565
|
+
while (this._caps.length < count) {
|
|
3566
|
+
const capMat = new ShaderMaterial({
|
|
3567
|
+
uniforms: {
|
|
3568
|
+
lineColor: { value: new Color() },
|
|
3569
|
+
uHatchScale: { value: 10.0 },
|
|
3570
|
+
uHatchEnabled: { value: 1.0 },
|
|
3571
|
+
},
|
|
3572
|
+
vertexShader: hatchVertexShader,
|
|
3573
|
+
fragmentShader: hatchFragmentShader,
|
|
3574
|
+
side: DoubleSide,
|
|
3575
|
+
clipping: true,
|
|
3576
|
+
depthTest: true,
|
|
3577
|
+
depthWrite: false,
|
|
3578
|
+
});
|
|
3579
|
+
const capMesh = new Mesh(new BufferGeometry(), capMat);
|
|
3580
|
+
capMesh.renderOrder = 5;
|
|
3581
|
+
this.add(capMesh);
|
|
3582
|
+
this._caps.push(capMesh);
|
|
3583
|
+
const lineMat = new LineMaterial({
|
|
3584
|
+
color: 0xffffff,
|
|
3585
|
+
linewidth: 2,
|
|
3586
|
+
resolution: new Vector2(window.innerWidth, window.innerHeight),
|
|
3587
|
+
depthTest: true,
|
|
3588
|
+
clipping: true,
|
|
3589
|
+
vertexColors: true,
|
|
3590
|
+
});
|
|
3591
|
+
const lineObj = new LineSegments2(new LineSegmentsGeometry(), lineMat);
|
|
3592
|
+
lineObj.renderOrder = 100;
|
|
3593
|
+
this.add(lineObj);
|
|
3594
|
+
this._outlines.push(lineObj);
|
|
3595
|
+
const ptsMat = new PointsMaterial({
|
|
3596
|
+
color: 0x00aaff,
|
|
3597
|
+
size: 6,
|
|
3598
|
+
sizeAttenuation: false,
|
|
3599
|
+
depthTest: false,
|
|
3600
|
+
transparent: true,
|
|
3601
|
+
depthWrite: false,
|
|
3602
|
+
});
|
|
3603
|
+
const pointsObj = new Points(new BufferGeometry(), ptsMat);
|
|
3604
|
+
pointsObj.renderOrder = 200;
|
|
3605
|
+
this.add(pointsObj);
|
|
3606
|
+
this._debugPoints.push(pointsObj);
|
|
3607
|
+
const debugSegMat = new LineMaterial({
|
|
3608
|
+
color: 0x00ff00,
|
|
3609
|
+
linewidth: 4,
|
|
3610
|
+
resolution: new Vector2(window.innerWidth, window.innerHeight),
|
|
3611
|
+
depthTest: false,
|
|
3612
|
+
transparent: true,
|
|
3613
|
+
depthWrite: false,
|
|
3614
|
+
clipping: true,
|
|
3615
|
+
});
|
|
3616
|
+
const debugSegObj = new LineSegments2(new LineSegmentsGeometry(), debugSegMat);
|
|
3617
|
+
debugSegObj.renderOrder = 150;
|
|
3618
|
+
this.add(debugSegObj);
|
|
3619
|
+
this._debugSegments.push(debugSegObj);
|
|
3620
|
+
const gapPtsMat = new PointsMaterial({
|
|
3621
|
+
size: 6,
|
|
3622
|
+
sizeAttenuation: false,
|
|
3623
|
+
depthTest: false,
|
|
3624
|
+
transparent: true,
|
|
3625
|
+
depthWrite: false,
|
|
3626
|
+
vertexColors: true,
|
|
3627
|
+
});
|
|
3628
|
+
const gapsObj = new Points(new BufferGeometry(), gapPtsMat);
|
|
3629
|
+
gapsObj.renderOrder = 250;
|
|
3630
|
+
this.add(gapsObj);
|
|
3631
|
+
this._debugGaps.push(gapsObj);
|
|
3632
|
+
}
|
|
3633
|
+
for (let i = count; i < this._caps.length; i++) {
|
|
3634
|
+
this._caps[i].visible = false;
|
|
3635
|
+
this._outlines[i].visible = false;
|
|
3636
|
+
this._debugPoints[i].visible = false;
|
|
3637
|
+
this._debugSegments[i].visible = false;
|
|
3638
|
+
this._debugGaps[i].visible = false;
|
|
3639
|
+
}
|
|
3640
|
+
}
|
|
3641
|
+
update(objects, extents, planes) {
|
|
3642
|
+
const t0 = performance.now();
|
|
3643
|
+
this._ensureHelpersCount(planes.length);
|
|
3644
|
+
if (planes.length === 0) return;
|
|
3645
|
+
const sphere = extents.getBoundingSphere(new Sphere());
|
|
3646
|
+
const globalRadius = Math.max(sphere.radius, 1e-3);
|
|
3647
|
+
const clippingBias = globalRadius * 1e-4;
|
|
3648
|
+
const biasedPlanes = planes.map((p) => {
|
|
3649
|
+
const bp = p.clone();
|
|
3650
|
+
bp.constant += clippingBias;
|
|
3651
|
+
return bp;
|
|
3652
|
+
});
|
|
3653
|
+
const targetMeshes = [];
|
|
3654
|
+
objects.forEach((obj) => {
|
|
3655
|
+
if (obj.isMesh && obj.material) {
|
|
3656
|
+
const mats = Array.isArray(obj.material) ? obj.material : [obj.material];
|
|
3657
|
+
if (mats.some((m) => m.clippingPlanes)) targetMeshes.push(obj);
|
|
3658
|
+
}
|
|
3659
|
+
});
|
|
3660
|
+
planes.forEach((plane, pIdx) => {
|
|
3661
|
+
const capMesh = this._caps[pIdx];
|
|
3662
|
+
const outlineMesh = this._outlines[pIdx];
|
|
3663
|
+
const debugPtsMesh = this._debugPoints[pIdx];
|
|
3664
|
+
const debugSegsMesh = this._debugSegments[pIdx];
|
|
3665
|
+
const debugGapsMesh = this._debugGaps[pIdx];
|
|
3666
|
+
const hatchColor = new Color(this.flags.hatchColor);
|
|
3667
|
+
hatchColor.convertLinearToSRGB();
|
|
3668
|
+
capMesh.material.uniforms.lineColor.value.set(hatchColor);
|
|
3669
|
+
capMesh.material.uniforms.uHatchScale.value = this.flags.hatchScale;
|
|
3670
|
+
capMesh.material.uniforms.uHatchEnabled.value = this.flags.hatchEnabled ? 1.0 : 0.0;
|
|
3671
|
+
outlineMesh.material.linewidth = this.flags.outlineWidth;
|
|
3672
|
+
const otherBiasedPlanes = biasedPlanes.filter((_, i) => i !== pIdx);
|
|
3673
|
+
capMesh.material.clippingPlanes = otherBiasedPlanes;
|
|
3674
|
+
outlineMesh.material.clippingPlanes = otherBiasedPlanes;
|
|
3675
|
+
debugSegsMesh.material.clippingPlanes = otherBiasedPlanes;
|
|
3676
|
+
const n = plane.normal;
|
|
3677
|
+
const planeOrigin = n.clone().multiplyScalar(-plane.constant);
|
|
3678
|
+
const up = new Vector3(0, 1, 0);
|
|
3679
|
+
if (Math.abs(n.dot(up)) > 0.999) up.set(1, 0, 0);
|
|
3680
|
+
const uAxis = new Vector3().crossVectors(up, n).normalize();
|
|
3681
|
+
const vAxis = new Vector3().crossVectors(n, uAxis).normalize();
|
|
3682
|
+
const positions = [];
|
|
3683
|
+
const indices = [];
|
|
3684
|
+
const hatchDirs = [];
|
|
3685
|
+
const fillColors = [];
|
|
3686
|
+
const combinedOutlinePoints = [];
|
|
3687
|
+
const combinedOutlineColors = [];
|
|
3688
|
+
const rawPts = [];
|
|
3689
|
+
const rawSegs = [];
|
|
3690
|
+
const rawGaps = [];
|
|
3691
|
+
const rawGapColors = [];
|
|
3692
|
+
targetMeshes.forEach((mesh, meshIndex) => {
|
|
3693
|
+
if (!mesh.geometry.boundingBox) mesh.geometry.computeBoundingBox();
|
|
3694
|
+
if (!mesh.geometry.boundingSphere) mesh.geometry.computeBoundingSphere();
|
|
3695
|
+
this._worldBox.copy(mesh.geometry.boundingBox).applyMatrix4(mesh.matrixWorld);
|
|
3696
|
+
if (!plane.intersectsBox(this._worldBox)) return;
|
|
3697
|
+
const localScale = new Vector3().setFromMatrixScale(mesh.matrixWorld);
|
|
3698
|
+
const maxScale = Math.max(localScale.x, localScale.y, localScale.z);
|
|
3699
|
+
const localRadius = Math.max(mesh.geometry.boundingSphere.radius * maxScale, 1e-3);
|
|
3700
|
+
const localHashTolerance = Math.max(localRadius * 1e-4, 1e-6);
|
|
3701
|
+
const localEps = Math.max(localRadius * 1e-5, 1e-7);
|
|
3702
|
+
const baseColor = new Color(0xffffff);
|
|
3703
|
+
const om = mesh.userData.originalMaterial;
|
|
3704
|
+
const mm = om ?? (Array.isArray(mesh.material) ? mesh.material[0] : mesh.material);
|
|
3705
|
+
if (mm.color) baseColor.copy(mm.color);
|
|
3706
|
+
const objFillColor = baseColor.clone().lerp(new Color(0x000000), 0.2);
|
|
3707
|
+
const objOutlineColor = baseColor.clone().lerp(new Color(0x000000), 0.85);
|
|
3708
|
+
const hue = ((meshIndex * 137.5) % 360) / 360;
|
|
3709
|
+
const meshGapColor = new Color().setHSL(hue, 1.0, 0.5);
|
|
3710
|
+
const currentHatchDir = meshIndex % 2 === 0 ? 0.0 : 1.0;
|
|
3711
|
+
const fillColor = this.flags.useObjFillColor ? objFillColor : new Color(this.flags.fillColor);
|
|
3712
|
+
const outlineColor = this.flags.useObjOutlineColor ? objOutlineColor : new Color(this.flags.outlineColor);
|
|
3713
|
+
meshGapColor.convertLinearToSRGB();
|
|
3714
|
+
fillColor.convertLinearToSRGB();
|
|
3715
|
+
outlineColor.convertLinearToSRGB();
|
|
3716
|
+
const localEdgeStats = new Map();
|
|
3717
|
+
const localPointGrid = new PointHashGrid(localHashTolerance);
|
|
3718
|
+
this._calculateMeshSegmentsUndirected(mesh, plane, localEdgeStats, localPointGrid, localEps);
|
|
3719
|
+
if (localEdgeStats.size > 0) {
|
|
3720
|
+
const boundaryEdges = [];
|
|
3721
|
+
for (const [key, stat] of localEdgeStats.entries()) {
|
|
3722
|
+
const isBoundary = stat.count % 2 !== 0;
|
|
3723
|
+
const ids = key.split("-");
|
|
3724
|
+
const id0 = Number(ids[0]);
|
|
3725
|
+
const id1 = Number(ids[1]);
|
|
3726
|
+
const p1 = localPointGrid.points[id0];
|
|
3727
|
+
const p2 = localPointGrid.points[id1];
|
|
3728
|
+
if (this.flags.showDebugSeams || (this.flags.boundaryOnly ? isBoundary : true)) {
|
|
3729
|
+
combinedOutlinePoints.push(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z);
|
|
3730
|
+
combinedOutlineColors.push(outlineColor.r, outlineColor.g, outlineColor.b);
|
|
3731
|
+
combinedOutlineColors.push(outlineColor.r, outlineColor.g, outlineColor.b);
|
|
3732
|
+
}
|
|
3733
|
+
if (isBoundary) boundaryEdges.push([id0, id1]);
|
|
3734
|
+
if (this.flags.showDebugSegments) rawSegs.push(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z);
|
|
3735
|
+
}
|
|
3736
|
+
if (this.flags.showDebugPoints) {
|
|
3737
|
+
for (const p of localPointGrid.points) rawPts.push(p.x, p.y, p.z);
|
|
3738
|
+
}
|
|
3739
|
+
if (this.flags.fillEnabled && boundaryEdges.length >= 3) {
|
|
3740
|
+
const currentAdj = new Map();
|
|
3741
|
+
for (const edge of boundaryEdges) {
|
|
3742
|
+
const a = edge[0];
|
|
3743
|
+
const b = edge[1];
|
|
3744
|
+
if (!currentAdj.has(a)) currentAdj.set(a, []);
|
|
3745
|
+
if (!currentAdj.has(b)) currentAdj.set(b, []);
|
|
3746
|
+
currentAdj.get(a).push(b);
|
|
3747
|
+
currentAdj.get(b).push(a);
|
|
3748
|
+
}
|
|
3749
|
+
const degree1 = [];
|
|
3750
|
+
for (const [node, neighbors] of currentAdj.entries()) {
|
|
3751
|
+
if (neighbors.length === 1) degree1.push(node);
|
|
3752
|
+
}
|
|
3753
|
+
const stitchTol = Math.max(localRadius * 0.05, 1e-4);
|
|
3754
|
+
for (let i = 0; i < degree1.length; i++) {
|
|
3755
|
+
const n1 = degree1[i];
|
|
3756
|
+
if (currentAdj.get(n1).length !== 1) continue;
|
|
3757
|
+
const p1 = localPointGrid.points[n1];
|
|
3758
|
+
let bestEdgeIdx = -1;
|
|
3759
|
+
let bestProj = null;
|
|
3760
|
+
let bestT = 0;
|
|
3761
|
+
let minDist = stitchTol;
|
|
3762
|
+
const edgeCount = boundaryEdges.length;
|
|
3763
|
+
for (let eIdx = 0; eIdx < edgeCount; eIdx++) {
|
|
3764
|
+
const edge = boundaryEdges[eIdx];
|
|
3765
|
+
const eA = edge[0];
|
|
3766
|
+
const eB = edge[1];
|
|
3767
|
+
if (eA === n1 || eB === n1) continue;
|
|
3768
|
+
const pA = localPointGrid.points[eA];
|
|
3769
|
+
const pB = localPointGrid.points[eB];
|
|
3770
|
+
const lineVec = new Vector3().subVectors(pB, pA);
|
|
3771
|
+
const lineLenSq = lineVec.lengthSq();
|
|
3772
|
+
let proj;
|
|
3773
|
+
let t;
|
|
3774
|
+
if (lineLenSq < 1e-12) {
|
|
3775
|
+
proj = pA.clone();
|
|
3776
|
+
t = 0;
|
|
3777
|
+
} else {
|
|
3778
|
+
const ptVec = new Vector3().subVectors(p1, pA);
|
|
3779
|
+
t = ptVec.dot(lineVec) / lineLenSq;
|
|
3780
|
+
t = Math.max(0, Math.min(1, t));
|
|
3781
|
+
proj = new Vector3().copy(pA).addScaledVector(lineVec, t);
|
|
3782
|
+
}
|
|
3783
|
+
const dist = p1.distanceTo(proj);
|
|
3784
|
+
if (dist < minDist) {
|
|
3785
|
+
minDist = dist;
|
|
3786
|
+
bestEdgeIdx = eIdx;
|
|
3787
|
+
bestProj = proj;
|
|
3788
|
+
bestT = t;
|
|
3789
|
+
}
|
|
3790
|
+
}
|
|
3791
|
+
if (bestEdgeIdx !== -1) {
|
|
3792
|
+
const edge = boundaryEdges[bestEdgeIdx];
|
|
3793
|
+
const eA = edge[0];
|
|
3794
|
+
const eB = edge[1];
|
|
3795
|
+
if (bestT < 0.001) {
|
|
3796
|
+
boundaryEdges.push([n1, eA]);
|
|
3797
|
+
currentAdj.get(n1).push(eA);
|
|
3798
|
+
currentAdj.get(eA).push(n1);
|
|
3799
|
+
p1.copy(localPointGrid.points[eA]);
|
|
3800
|
+
} else if (bestT > 0.999) {
|
|
3801
|
+
boundaryEdges.push([n1, eB]);
|
|
3802
|
+
currentAdj.get(n1).push(eB);
|
|
3803
|
+
currentAdj.get(eB).push(n1);
|
|
3804
|
+
p1.copy(localPointGrid.points[eB]);
|
|
3805
|
+
} else {
|
|
3806
|
+
const newNodeId = localPointGrid.add(bestProj);
|
|
3807
|
+
edge[1] = newNodeId;
|
|
3808
|
+
boundaryEdges.push([newNodeId, eB]);
|
|
3809
|
+
boundaryEdges.push([n1, newNodeId]);
|
|
3810
|
+
const neighborsA = currentAdj.get(eA);
|
|
3811
|
+
neighborsA[neighborsA.indexOf(eB)] = newNodeId;
|
|
3812
|
+
const neighborsB = currentAdj.get(eB);
|
|
3813
|
+
neighborsB[neighborsB.indexOf(eA)] = newNodeId;
|
|
3814
|
+
if (!currentAdj.has(newNodeId)) currentAdj.set(newNodeId, []);
|
|
3815
|
+
currentAdj.get(newNodeId).push(eA, eB, n1);
|
|
3816
|
+
currentAdj.get(n1).push(newNodeId);
|
|
3817
|
+
p1.copy(bestProj);
|
|
3818
|
+
}
|
|
3819
|
+
}
|
|
3820
|
+
}
|
|
3821
|
+
if (this.flags.showDebugGaps) {
|
|
3822
|
+
for (const [node, neighbors] of currentAdj.entries()) {
|
|
3823
|
+
if (neighbors.length !== 2) {
|
|
3824
|
+
const p = localPointGrid.points[node];
|
|
3825
|
+
rawGaps.push(p.x, p.y, p.z);
|
|
3826
|
+
rawGapColors.push(meshGapColor.r, meshGapColor.g, meshGapColor.b);
|
|
3827
|
+
}
|
|
3828
|
+
}
|
|
3829
|
+
}
|
|
3830
|
+
const loops = this._assembleLoopsUndirected(boundaryEdges, localPointGrid, uAxis, vAxis);
|
|
3831
|
+
if (loops.length > 0) {
|
|
3832
|
+
this._triangulateTreeOptimized(
|
|
3833
|
+
loops,
|
|
3834
|
+
planeOrigin,
|
|
3835
|
+
uAxis,
|
|
3836
|
+
vAxis,
|
|
3837
|
+
positions,
|
|
3838
|
+
indices,
|
|
3839
|
+
localRadius,
|
|
3840
|
+
fillColor,
|
|
3841
|
+
currentHatchDir,
|
|
3842
|
+
hatchDirs,
|
|
3843
|
+
fillColors
|
|
3844
|
+
);
|
|
3845
|
+
}
|
|
3846
|
+
}
|
|
3847
|
+
}
|
|
3848
|
+
});
|
|
3849
|
+
if (indices.length > 0) {
|
|
3850
|
+
capMesh.geometry.dispose();
|
|
3851
|
+
capMesh.geometry = new BufferGeometry();
|
|
3852
|
+
capMesh.geometry.setAttribute("position", new Float32BufferAttribute(positions, 3));
|
|
3853
|
+
capMesh.geometry.setAttribute("aHatchDir", new Float32BufferAttribute(hatchDirs, 1));
|
|
3854
|
+
capMesh.geometry.setAttribute("aFillColor", new Float32BufferAttribute(fillColors, 3));
|
|
3855
|
+
capMesh.geometry.setIndex(indices);
|
|
3856
|
+
capMesh.geometry.computeVertexNormals();
|
|
3857
|
+
capMesh.visible = this.flags.fillEnabled;
|
|
3858
|
+
} else {
|
|
3859
|
+
capMesh.visible = false;
|
|
3860
|
+
}
|
|
3861
|
+
if (outlineMesh.geometry) outlineMesh.geometry.dispose();
|
|
3862
|
+
outlineMesh.geometry = new LineSegmentsGeometry();
|
|
3863
|
+
if (this.flags.outlineEnabled && combinedOutlinePoints.length >= 6) {
|
|
3864
|
+
outlineMesh.geometry.setPositions(new Float32Array(combinedOutlinePoints));
|
|
3865
|
+
outlineMesh.geometry.setColors(new Float32Array(combinedOutlineColors));
|
|
3866
|
+
outlineMesh.visible = true;
|
|
3867
|
+
} else {
|
|
3868
|
+
outlineMesh.visible = false;
|
|
3869
|
+
}
|
|
3870
|
+
if (this.flags.showDebugPoints && rawPts.length > 0) {
|
|
3871
|
+
debugPtsMesh.geometry.setAttribute("position", new Float32BufferAttribute(rawPts, 3));
|
|
3872
|
+
debugPtsMesh.visible = true;
|
|
3873
|
+
} else {
|
|
3874
|
+
debugPtsMesh.visible = false;
|
|
3875
|
+
}
|
|
3876
|
+
if (debugSegsMesh.geometry) debugSegsMesh.geometry.dispose();
|
|
3877
|
+
debugSegsMesh.geometry = new LineSegmentsGeometry();
|
|
3878
|
+
if (this.flags.showDebugSegments && rawSegs.length >= 6) {
|
|
3879
|
+
debugSegsMesh.geometry.setPositions(new Float32Array(rawSegs));
|
|
3880
|
+
debugSegsMesh.visible = true;
|
|
3881
|
+
} else {
|
|
3882
|
+
debugSegsMesh.visible = false;
|
|
3883
|
+
}
|
|
3884
|
+
if (debugGapsMesh.geometry) debugGapsMesh.geometry.dispose();
|
|
3885
|
+
debugGapsMesh.geometry = new BufferGeometry();
|
|
3886
|
+
if (this.flags.showDebugGaps && rawGaps.length > 0) {
|
|
3887
|
+
debugGapsMesh.geometry.setAttribute("position", new Float32BufferAttribute(rawGaps, 3));
|
|
3888
|
+
debugGapsMesh.geometry.setAttribute("color", new Float32BufferAttribute(rawGapColors, 3));
|
|
3889
|
+
debugGapsMesh.visible = true;
|
|
3890
|
+
} else {
|
|
3891
|
+
debugGapsMesh.visible = false;
|
|
3892
|
+
}
|
|
3893
|
+
});
|
|
3894
|
+
if (this.flags.showDebugInfo) {
|
|
3895
|
+
console.log(`[SectionsHelper] v7.00 Updated in ${(performance.now() - t0).toFixed(2)} ms`);
|
|
3896
|
+
}
|
|
3897
|
+
}
|
|
3898
|
+
_assembleLoopsUndirected(edges, pointGrid, uAxis, vAxis) {
|
|
3899
|
+
const adj = new Map();
|
|
3900
|
+
for (const edge of edges) {
|
|
3901
|
+
const a = edge[0];
|
|
3902
|
+
const b = edge[1];
|
|
3903
|
+
if (!adj.has(a)) adj.set(a, []);
|
|
3904
|
+
if (!adj.has(b)) adj.set(b, []);
|
|
3905
|
+
adj.get(a).push(b);
|
|
3906
|
+
adj.get(b).push(a);
|
|
3907
|
+
}
|
|
3908
|
+
const loops = [];
|
|
3909
|
+
while (adj.size > 0) {
|
|
3910
|
+
let startNode = -1;
|
|
3911
|
+
for (const key of adj.keys()) {
|
|
3912
|
+
if (adj.get(key).length > 0) {
|
|
3913
|
+
startNode = key;
|
|
3914
|
+
break;
|
|
3915
|
+
}
|
|
3916
|
+
}
|
|
3917
|
+
if (startNode === -1) break;
|
|
3918
|
+
let current = startNode;
|
|
3919
|
+
let prev = -1;
|
|
3920
|
+
const path = [];
|
|
3921
|
+
const pathIndices = new Map();
|
|
3922
|
+
while (true) {
|
|
3923
|
+
path.push(current);
|
|
3924
|
+
pathIndices.set(current, path.length - 1);
|
|
3925
|
+
const neighbors = adj.get(current);
|
|
3926
|
+
if (!neighbors || neighbors.length === 0) break;
|
|
3927
|
+
let nextIdx = 0;
|
|
3928
|
+
if (neighbors.length > 1 && prev !== -1) {
|
|
3929
|
+
const pPrev = pointGrid.points[prev];
|
|
3930
|
+
const pCurr = pointGrid.points[current];
|
|
3931
|
+
const vIn = new Vector3().subVectors(pCurr, pPrev);
|
|
3932
|
+
const in2d = new Vector2(vIn.dot(uAxis), vIn.dot(vAxis));
|
|
3933
|
+
if (in2d.lengthSq() > 1e-10) {
|
|
3934
|
+
in2d.normalize();
|
|
3935
|
+
let minAngle = Infinity;
|
|
3936
|
+
for (let i = 0; i < neighbors.length; i++) {
|
|
3937
|
+
const pNext = pointGrid.points[neighbors[i]];
|
|
3938
|
+
const vOut = new Vector3().subVectors(pNext, pCurr);
|
|
3939
|
+
const out2d = new Vector2(vOut.dot(uAxis), vOut.dot(vAxis));
|
|
3940
|
+
if (out2d.lengthSq() > 1e-10) {
|
|
3941
|
+
out2d.normalize();
|
|
3942
|
+
const angle = Math.atan2(in2d.cross(out2d), in2d.dot(out2d));
|
|
3943
|
+
if (angle < minAngle) {
|
|
3944
|
+
minAngle = angle;
|
|
3945
|
+
nextIdx = i;
|
|
3946
|
+
}
|
|
3947
|
+
}
|
|
3948
|
+
}
|
|
3949
|
+
}
|
|
3950
|
+
}
|
|
3951
|
+
const next = neighbors[nextIdx];
|
|
3952
|
+
neighbors.splice(nextIdx, 1);
|
|
3953
|
+
const nextNeighbors = adj.get(next);
|
|
3954
|
+
if (nextNeighbors) {
|
|
3955
|
+
const revIdx = nextNeighbors.indexOf(current);
|
|
3956
|
+
if (revIdx !== -1) nextNeighbors.splice(revIdx, 1);
|
|
3957
|
+
}
|
|
3958
|
+
prev = current;
|
|
3959
|
+
current = next;
|
|
3960
|
+
if (pathIndices.has(current)) {
|
|
3961
|
+
const loopStartIdx = pathIndices.get(current);
|
|
3962
|
+
const loopNodes = path.slice(loopStartIdx);
|
|
3963
|
+
if (loopNodes.length >= 3) loops.push(loopNodes.map((id) => pointGrid.points[id]));
|
|
3964
|
+
for (let i = loopStartIdx; i < path.length; i++) pathIndices.delete(path[i]);
|
|
3965
|
+
path.length = loopStartIdx;
|
|
3966
|
+
prev = path.length > 1 ? path[path.length - 2] : -1;
|
|
3967
|
+
}
|
|
3968
|
+
}
|
|
3969
|
+
for (const key of adj.keys()) {
|
|
3970
|
+
if (adj.get(key).length === 0) adj.delete(key);
|
|
3971
|
+
}
|
|
3972
|
+
}
|
|
3973
|
+
return loops;
|
|
3974
|
+
}
|
|
3975
|
+
_triangulateTreeOptimized(
|
|
3976
|
+
loops,
|
|
3977
|
+
planeOrigin,
|
|
3978
|
+
uAxis,
|
|
3979
|
+
vAxis,
|
|
3980
|
+
positionsBuffer,
|
|
3981
|
+
indicesBuffer,
|
|
3982
|
+
localRadius,
|
|
3983
|
+
fillColor,
|
|
3984
|
+
hatchDir,
|
|
3985
|
+
hatchDirsBuffer,
|
|
3986
|
+
fillColorsBuffer
|
|
3987
|
+
) {
|
|
3988
|
+
const shapesData = [];
|
|
3989
|
+
const minArea = localRadius * 1e-5 * (localRadius * 1e-5);
|
|
3990
|
+
loops.forEach((loop) => {
|
|
3991
|
+
const pts2d = loop.map((p) => {
|
|
3992
|
+
const pv = p.clone().sub(planeOrigin);
|
|
3993
|
+
return new Vector2(pv.dot(uAxis), pv.dot(vAxis));
|
|
3994
|
+
});
|
|
3995
|
+
const cleaned = [];
|
|
3996
|
+
for (let k = 0; k < pts2d.length; k++) {
|
|
3997
|
+
const prev = k === 0 ? pts2d[pts2d.length - 1] : pts2d[k - 1];
|
|
3998
|
+
if (pts2d[k].distanceTo(prev) > 1e-5) cleaned.push(pts2d[k]);
|
|
3999
|
+
}
|
|
4000
|
+
if (cleaned.length < 3) return;
|
|
4001
|
+
const area = ShapeUtils.area(cleaned);
|
|
4002
|
+
if (Math.abs(area) > minArea) {
|
|
4003
|
+
shapesData.push({ pts2d: cleaned, absArea: Math.abs(area), depth: 0, parent: -1, holes: [] });
|
|
4004
|
+
}
|
|
4005
|
+
});
|
|
4006
|
+
shapesData.sort((a, b) => b.absArea - a.absArea);
|
|
4007
|
+
for (let i = 0; i < shapesData.length; i++) {
|
|
4008
|
+
for (let j = i - 1; j >= 0; j--) {
|
|
4009
|
+
if (shapesData[i].absArea > shapesData[j].absArea * 0.98) continue;
|
|
4010
|
+
if (this._isLoopInside(shapesData[i].pts2d, shapesData[j].pts2d, localRadius)) {
|
|
4011
|
+
shapesData[i].parent = j;
|
|
4012
|
+
shapesData[i].depth = shapesData[j].depth + 1;
|
|
4013
|
+
break;
|
|
4014
|
+
}
|
|
4015
|
+
}
|
|
4016
|
+
}
|
|
4017
|
+
for (let i = 0; i < shapesData.length; i++) {
|
|
4018
|
+
const shape = shapesData[i];
|
|
4019
|
+
if (shape.depth % 2 === 1 && shape.parent !== -1) {
|
|
4020
|
+
shapesData[shape.parent].holes.push(shape.pts2d);
|
|
4021
|
+
}
|
|
4022
|
+
}
|
|
4023
|
+
for (let i = 0; i < shapesData.length; i++) {
|
|
4024
|
+
const shapeData = shapesData[i];
|
|
4025
|
+
if (shapeData.depth % 2 !== 0) continue;
|
|
4026
|
+
if (ShapeUtils.area(shapeData.pts2d) < 0) {
|
|
4027
|
+
shapeData.pts2d.reverse();
|
|
4028
|
+
}
|
|
4029
|
+
shapeData.holes.forEach((h) => {
|
|
4030
|
+
if (ShapeUtils.area(h) > 0) h.reverse();
|
|
4031
|
+
});
|
|
4032
|
+
const allPoints = [...shapeData.pts2d];
|
|
4033
|
+
shapeData.holes.forEach((h) => allPoints.push(...h));
|
|
4034
|
+
const faces = ShapeUtils.triangulateShape(shapeData.pts2d, shapeData.holes);
|
|
4035
|
+
const vertexOffset = positionsBuffer.length / 3;
|
|
4036
|
+
for (const pt of allPoints) {
|
|
4037
|
+
const p3d = planeOrigin.clone().addScaledVector(uAxis, pt.x).addScaledVector(vAxis, pt.y);
|
|
4038
|
+
positionsBuffer.push(p3d.x, p3d.y, p3d.z);
|
|
4039
|
+
hatchDirsBuffer.push(hatchDir);
|
|
4040
|
+
fillColorsBuffer.push(fillColor.r, fillColor.g, fillColor.b);
|
|
4041
|
+
}
|
|
4042
|
+
for (let f = 0; f < faces.length; f++) {
|
|
4043
|
+
indicesBuffer.push(vertexOffset + faces[f][0], vertexOffset + faces[f][1], vertexOffset + faces[f][2]);
|
|
4044
|
+
}
|
|
4045
|
+
}
|
|
4046
|
+
}
|
|
4047
|
+
_isPointInPoly(pt, poly) {
|
|
4048
|
+
let inside = false;
|
|
4049
|
+
const py = pt.y + 1.119e-7;
|
|
4050
|
+
const px = pt.x;
|
|
4051
|
+
for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {
|
|
4052
|
+
if (
|
|
4053
|
+
poly[i].y > py !== poly[j].y > py &&
|
|
4054
|
+
px < ((poly[j].x - poly[i].x) * (py - poly[i].y)) / (poly[j].y - poly[i].y) + poly[i].x
|
|
4055
|
+
) {
|
|
4056
|
+
inside = !inside;
|
|
4057
|
+
}
|
|
4058
|
+
}
|
|
4059
|
+
return inside;
|
|
4060
|
+
}
|
|
4061
|
+
_isLoopInside(child, parent, localRadius) {
|
|
4062
|
+
let minX1 = Infinity;
|
|
4063
|
+
let maxX1 = -Infinity;
|
|
4064
|
+
let minY1 = Infinity;
|
|
4065
|
+
let maxY1 = -Infinity;
|
|
4066
|
+
for (const p of child) {
|
|
4067
|
+
if (p.x < minX1) minX1 = p.x;
|
|
4068
|
+
if (p.x > maxX1) maxX1 = p.x;
|
|
4069
|
+
if (p.y < minY1) minY1 = p.y;
|
|
4070
|
+
if (p.y > maxY1) maxY1 = p.y;
|
|
4071
|
+
}
|
|
4072
|
+
let minX2 = Infinity;
|
|
4073
|
+
let maxX2 = -Infinity;
|
|
4074
|
+
let minY2 = Infinity;
|
|
4075
|
+
let maxY2 = -Infinity;
|
|
4076
|
+
for (const p of parent) {
|
|
4077
|
+
if (p.x < minX2) minX2 = p.x;
|
|
4078
|
+
if (p.x > maxX2) maxX2 = p.x;
|
|
4079
|
+
if (p.y < minY2) minY2 = p.y;
|
|
4080
|
+
if (p.y > maxY2) maxY2 = p.y;
|
|
4081
|
+
}
|
|
4082
|
+
const margin = Math.max(localRadius * 1e-4, 1e-5);
|
|
4083
|
+
if (minX1 < minX2 - margin || maxX1 > maxX2 + margin || minY1 < minY2 - margin || maxY1 > maxY2 + margin) {
|
|
4084
|
+
return false;
|
|
4085
|
+
}
|
|
4086
|
+
let insideCount = 0;
|
|
4087
|
+
for (let i = 0; i < child.length; i++) {
|
|
4088
|
+
if (this._isPointInPoly(child[i], parent)) {
|
|
4089
|
+
insideCount++;
|
|
4090
|
+
}
|
|
4091
|
+
}
|
|
4092
|
+
return insideCount >= child.length * 0.85;
|
|
4093
|
+
}
|
|
4094
|
+
_calculateMeshSegmentsUndirected(mesh, plane, edgeStats, grid, eps) {
|
|
4095
|
+
const geom = mesh.geometry;
|
|
4096
|
+
const pos = geom.attributes.position;
|
|
4097
|
+
const index = geom.index;
|
|
4098
|
+
const world = mesh.matrixWorld;
|
|
4099
|
+
const count = index ? index.count : pos.count;
|
|
4100
|
+
for (let i = 0; i < count; i += 3) {
|
|
4101
|
+
const i1 = index ? index.getX(i) : i;
|
|
4102
|
+
const i2 = index ? index.getX(i + 1) : i + 1;
|
|
4103
|
+
const i3 = index ? index.getX(i + 2) : i + 2;
|
|
4104
|
+
const v1 = this._vA.fromBufferAttribute(pos, i1).applyMatrix4(world);
|
|
4105
|
+
const v2 = this._vB.fromBufferAttribute(pos, i2).applyMatrix4(world);
|
|
4106
|
+
const v3 = this._vC.fromBufferAttribute(pos, i3).applyMatrix4(world);
|
|
4107
|
+
let d1 = plane.distanceToPoint(v1);
|
|
4108
|
+
let d2 = plane.distanceToPoint(v2);
|
|
4109
|
+
let d3 = plane.distanceToPoint(v3);
|
|
4110
|
+
if (Math.abs(d1) <= eps) d1 = eps;
|
|
4111
|
+
if (Math.abs(d2) <= eps) d2 = eps;
|
|
4112
|
+
if (Math.abs(d3) <= eps) d3 = eps;
|
|
4113
|
+
const s1 = d1 > 0 ? 1 : -1;
|
|
4114
|
+
const s2 = d2 > 0 ? 1 : -1;
|
|
4115
|
+
const s3 = d3 > 0 ? 1 : -1;
|
|
4116
|
+
if (s1 === s2 && s2 === s3) continue;
|
|
4117
|
+
const intersections = [];
|
|
4118
|
+
if (s1 !== s2) {
|
|
4119
|
+
intersections.push(new Vector3().lerpVectors(v1, v2, Math.abs(d1) / (Math.abs(d1) + Math.abs(d2))));
|
|
4120
|
+
}
|
|
4121
|
+
if (s2 !== s3) {
|
|
4122
|
+
intersections.push(new Vector3().lerpVectors(v2, v3, Math.abs(d2) / (Math.abs(d2) + Math.abs(d3))));
|
|
4123
|
+
}
|
|
4124
|
+
if (s3 !== s1) {
|
|
4125
|
+
intersections.push(new Vector3().lerpVectors(v3, v1, Math.abs(d3) / (Math.abs(d3) + Math.abs(d1))));
|
|
4126
|
+
}
|
|
4127
|
+
if (intersections.length >= 2) {
|
|
4128
|
+
const id1 = grid.add(intersections[0]);
|
|
4129
|
+
const id2 = grid.add(intersections[1]);
|
|
4130
|
+
if (id1 !== id2) {
|
|
4131
|
+
const key = id1 < id2 ? `${id1}-${id2}` : `${id2}-${id1}`;
|
|
4132
|
+
const stat = edgeStats.get(key) || { count: 0 };
|
|
4133
|
+
stat.count++;
|
|
4134
|
+
edgeStats.set(key, stat);
|
|
4135
|
+
}
|
|
4136
|
+
}
|
|
4137
|
+
}
|
|
4138
|
+
}
|
|
4139
|
+
}
|
|
4140
|
+
|
|
4141
|
+
class SectionsComponent {
|
|
4142
|
+
constructor(viewer) {
|
|
4143
|
+
this.updateTimerId = 0;
|
|
4144
|
+
this.updateDelay = 250;
|
|
4145
|
+
this.syncOptions = () => {
|
|
4146
|
+
function rgbToHex(c) {
|
|
4147
|
+
const hex = (v = 0) => v.toString(16).padStart(2, "0");
|
|
4148
|
+
return "#" + hex(c.r) + hex(c.g) + hex(c.b);
|
|
4149
|
+
}
|
|
4150
|
+
const options = this.viewer.options;
|
|
4151
|
+
const flags = this.sectionsHelper.flags;
|
|
4152
|
+
flags.fillEnabled = options.enableSectionFill;
|
|
4153
|
+
flags.fillColor = rgbToHex(options.sectionFillColor);
|
|
4154
|
+
flags.useObjFillColor = options.sectionUseObjectColor;
|
|
4155
|
+
flags.hatchEnabled = options.enableSectionHatch;
|
|
4156
|
+
flags.hatchColor = rgbToHex(options.sectionHatchColor);
|
|
4157
|
+
flags.hatchScale = options.sectionHatchScale;
|
|
4158
|
+
flags.outlineEnabled = options.enableSectionOutline;
|
|
4159
|
+
flags.outlineColor = rgbToHex(options.sectionOutlineColor);
|
|
4160
|
+
flags.outlineWidth = options.sectionOutlineWidth;
|
|
4161
|
+
this.syncSections();
|
|
4162
|
+
};
|
|
4163
|
+
this.syncHelper = () => {
|
|
4164
|
+
this.sectionsHelper.removeFromParent();
|
|
4165
|
+
this.viewer.helpers.add(this.sectionsHelper);
|
|
4166
|
+
};
|
|
4167
|
+
this.syncSections = () => {
|
|
4168
|
+
this.sectionsHelper.visible = false;
|
|
4169
|
+
clearTimeout(this.updateTimerId);
|
|
4170
|
+
this.updateTimerId = window.setTimeout(this.updateSections, this.updateDelay);
|
|
4171
|
+
};
|
|
4172
|
+
this.viewerResize = (event) => {
|
|
4173
|
+
this.sectionsHelper.setSize(event.width, event.height);
|
|
4174
|
+
};
|
|
4175
|
+
this.updateSections = () => {
|
|
4176
|
+
const objects = [];
|
|
4177
|
+
this.viewer.models.forEach((model) => objects.push(model.getVisibleObjects()));
|
|
4178
|
+
const objects2 = objects.flat();
|
|
4179
|
+
this.sectionsHelper.update(objects2, this.viewer.extents, this.viewer.clippingPlanes);
|
|
4180
|
+
this.sectionsHelper.visible = true;
|
|
4181
|
+
this.viewer.update();
|
|
4182
|
+
};
|
|
4183
|
+
this.sectionsHelper = new SectionsHelper();
|
|
4184
|
+
this.viewer = viewer;
|
|
4185
|
+
this.viewer.addEventListener("initialize", this.syncHelper);
|
|
4186
|
+
this.viewer.addEventListener("databasechunk", this.syncHelper);
|
|
4187
|
+
this.viewer.addEventListener("drawviewpoint", this.syncHelper);
|
|
4188
|
+
this.viewer.addEventListener("changecuttingplanes", this.syncSections);
|
|
4189
|
+
this.viewer.addEventListener("explode", this.syncSections);
|
|
4190
|
+
this.viewer.addEventListener("hide", this.syncSections);
|
|
4191
|
+
this.viewer.addEventListener("isolate", this.syncSections);
|
|
4192
|
+
this.viewer.addEventListener("show", this.syncSections);
|
|
4193
|
+
this.viewer.addEventListener("showall", this.syncSections);
|
|
4194
|
+
this.viewer.addEventListener("resize", this.viewerResize);
|
|
4195
|
+
this.viewer.addEventListener("optionschange", this.syncOptions);
|
|
4196
|
+
this.syncOptions();
|
|
4197
|
+
}
|
|
4198
|
+
dispose() {
|
|
4199
|
+
clearTimeout(this.updateTimerId);
|
|
4200
|
+
this.sectionsHelper.removeFromParent();
|
|
4201
|
+
this.sectionsHelper.dispose();
|
|
4202
|
+
this.viewer.removeEventListener("initialize", this.syncHelper);
|
|
4203
|
+
this.viewer.removeEventListener("databasechunk", this.syncHelper);
|
|
4204
|
+
this.viewer.removeEventListener("drawviewpoint", this.syncHelper);
|
|
4205
|
+
this.viewer.removeEventListener("changecuttingplanes", this.syncSections);
|
|
4206
|
+
this.viewer.removeEventListener("explode", this.syncSections);
|
|
4207
|
+
this.viewer.removeEventListener("hide", this.syncSections);
|
|
4208
|
+
this.viewer.removeEventListener("isolate", this.syncSections);
|
|
4209
|
+
this.viewer.removeEventListener("show", this.syncSections);
|
|
4210
|
+
this.viewer.removeEventListener("showall", this.syncSections);
|
|
4211
|
+
this.viewer.removeEventListener("resize", this.viewerResize);
|
|
4212
|
+
this.viewer.removeEventListener("optionschange", this.syncOptions);
|
|
4213
|
+
}
|
|
4214
|
+
}
|
|
4215
|
+
|
|
3383
4216
|
class WCSHelper extends Object3D {
|
|
3384
4217
|
constructor(camera) {
|
|
3385
4218
|
super();
|
|
4219
|
+
this.type = "WCSHelper";
|
|
3386
4220
|
this.camera = camera;
|
|
3387
4221
|
this.size = 160;
|
|
3388
4222
|
this.orthoCamera = new OrthographicCamera(-2, 2, 2, -2, 0, 4);
|
|
@@ -3470,7 +4304,7 @@ class WCSHelper extends Object3D {
|
|
|
3470
4304
|
|
|
3471
4305
|
class WCSHelperComponent {
|
|
3472
4306
|
constructor(viewer) {
|
|
3473
|
-
this.
|
|
4307
|
+
this.syncHelper = () => {
|
|
3474
4308
|
this.wcsHelper.dispose();
|
|
3475
4309
|
this.wcsHelper = new WCSHelper(this.viewer.camera);
|
|
3476
4310
|
};
|
|
@@ -3484,14 +4318,14 @@ class WCSHelperComponent {
|
|
|
3484
4318
|
};
|
|
3485
4319
|
this.wcsHelper = new WCSHelper(viewer.camera);
|
|
3486
4320
|
this.viewer = viewer;
|
|
3487
|
-
this.viewer.addEventListener("databasechunk", this.
|
|
3488
|
-
this.viewer.addEventListener("drawviewpoint", this.
|
|
4321
|
+
this.viewer.addEventListener("databasechunk", this.syncHelper);
|
|
4322
|
+
this.viewer.addEventListener("drawviewpoint", this.syncHelper);
|
|
3489
4323
|
this.viewer.addEventListener("render", this.viewerRender);
|
|
3490
4324
|
this.viewer.addEventListener("changecameramode", this.updateHelperCamera);
|
|
3491
4325
|
}
|
|
3492
4326
|
dispose() {
|
|
3493
|
-
this.viewer.removeEventListener("databasechunk", this.
|
|
3494
|
-
this.viewer.removeEventListener("drawviewpoint", this.
|
|
4327
|
+
this.viewer.removeEventListener("databasechunk", this.syncHelper);
|
|
4328
|
+
this.viewer.removeEventListener("drawviewpoint", this.syncHelper);
|
|
3495
4329
|
this.viewer.removeEventListener("render", this.viewerRender);
|
|
3496
4330
|
this.viewer.removeEventListener("changecameramode", this.updateHelperCamera);
|
|
3497
4331
|
this.wcsHelper.dispose();
|
|
@@ -3537,11 +4371,14 @@ components.registerComponent("CanvasRemoveComponent", (viewer) => new CanvasRemo
|
|
|
3537
4371
|
components.registerComponent("RenderLoopComponent", (viewer) => new RenderLoopComponent(viewer));
|
|
3538
4372
|
components.registerComponent("HighlighterComponent", (viewer) => new HighlighterComponent(viewer));
|
|
3539
4373
|
components.registerComponent("SelectionComponent", (viewer) => new SelectionComponent(viewer));
|
|
4374
|
+
components.registerComponent("ClippingPlaneComponent", (viewer) => new ClippingPlaneComponent(viewer));
|
|
4375
|
+
components.registerComponent("SectionsComponent", (viewer) => new SectionsComponent(viewer));
|
|
3540
4376
|
components.registerComponent("WCSHelperComponent", (viewer) => new WCSHelperComponent(viewer));
|
|
3541
4377
|
components.registerComponent("ResetComponent", (viewer) => new ResetComponent(viewer));
|
|
3542
4378
|
|
|
3543
4379
|
class ModelImpl {
|
|
3544
4380
|
constructor(scene) {
|
|
4381
|
+
this.id = "";
|
|
3545
4382
|
this.scene = scene;
|
|
3546
4383
|
this.handleToObjects = new Map();
|
|
3547
4384
|
this.originalObjects = new Set();
|
|
@@ -3717,7 +4554,25 @@ class ModelImpl {
|
|
|
3717
4554
|
return info;
|
|
3718
4555
|
}
|
|
3719
4556
|
getExtents(target) {
|
|
3720
|
-
|
|
4557
|
+
const _box = new Box3();
|
|
4558
|
+
function expandByObject(object, target) {
|
|
4559
|
+
if (!object.geometry)
|
|
4560
|
+
return;
|
|
4561
|
+
object.updateWorldMatrix(false, false);
|
|
4562
|
+
if (object.boundingBox !== undefined) {
|
|
4563
|
+
if (object.boundingBox === null)
|
|
4564
|
+
object.computeBoundingBox();
|
|
4565
|
+
_box.copy(object.boundingBox);
|
|
4566
|
+
}
|
|
4567
|
+
else {
|
|
4568
|
+
if (object.geometry.boundingBox === null)
|
|
4569
|
+
object.geometry.computeBoundingBox();
|
|
4570
|
+
_box.copy(object.geometry.boundingBox);
|
|
4571
|
+
}
|
|
4572
|
+
_box.applyMatrix4(object.matrixWorld);
|
|
4573
|
+
target.union(_box);
|
|
4574
|
+
}
|
|
4575
|
+
this.scene.traverseVisible((object) => expandByObject(object, target));
|
|
3721
4576
|
return target;
|
|
3722
4577
|
}
|
|
3723
4578
|
getObjects() {
|
|
@@ -3725,8 +4580,8 @@ class ModelImpl {
|
|
|
3725
4580
|
}
|
|
3726
4581
|
getVisibleObjects() {
|
|
3727
4582
|
const objects = [];
|
|
3728
|
-
this.scene.traverseVisible((object) => objects.push(object));
|
|
3729
|
-
return objects
|
|
4583
|
+
this.scene.traverseVisible((object) => object.userData.handle && objects.push(object));
|
|
4584
|
+
return objects;
|
|
3730
4585
|
}
|
|
3731
4586
|
getObjectsByHandles(handles) {
|
|
3732
4587
|
if (!Array.isArray(handles))
|
|
@@ -4080,6 +4935,7 @@ class GltfStructure {
|
|
|
4080
4935
|
this._nextObjectId = 1;
|
|
4081
4936
|
this.loadingAborted = false;
|
|
4082
4937
|
this.criticalError = null;
|
|
4938
|
+
this.embeddedBinaryChunk = null;
|
|
4083
4939
|
}
|
|
4084
4940
|
async initialize(loader) {
|
|
4085
4941
|
const json = await this.loadController.loadJson();
|
|
@@ -4088,28 +4944,72 @@ class GltfStructure {
|
|
|
4088
4944
|
}
|
|
4089
4945
|
this.json = json;
|
|
4090
4946
|
this.loader = loader;
|
|
4091
|
-
|
|
4947
|
+
const bufferUri = this.json.buffers?.[0]?.uri || "";
|
|
4948
|
+
if (bufferUri.startsWith("data:")) {
|
|
4949
|
+
this.embeddedBinaryChunk = await this._decodeDataUri(bufferUri);
|
|
4950
|
+
this.uri = "";
|
|
4951
|
+
} else {
|
|
4952
|
+
this.uri = bufferUri;
|
|
4953
|
+
}
|
|
4954
|
+
}
|
|
4955
|
+
async _decodeDataUri(dataUri) {
|
|
4956
|
+
try {
|
|
4957
|
+
const response = await fetch(dataUri);
|
|
4958
|
+
return await response.arrayBuffer();
|
|
4959
|
+
} catch (e) {
|
|
4960
|
+
throw new Error(`DynamicLoader: Failed to decode embedded data URI: ${e.message}`);
|
|
4961
|
+
}
|
|
4092
4962
|
}
|
|
4093
4963
|
clear() {
|
|
4094
|
-
this.json = null;
|
|
4095
|
-
this.loadController = null;
|
|
4096
|
-
this.pendingRequests = [];
|
|
4097
4964
|
if (this.batchTimeout) {
|
|
4098
4965
|
clearTimeout(this.batchTimeout);
|
|
4099
4966
|
this.batchTimeout = null;
|
|
4100
4967
|
}
|
|
4101
|
-
this.
|
|
4102
|
-
this.
|
|
4103
|
-
|
|
4968
|
+
this._rejectPendingRequests();
|
|
4969
|
+
if (this.disposeMaterials) {
|
|
4970
|
+
try {
|
|
4971
|
+
this.disposeMaterials();
|
|
4972
|
+
} catch (e) {
|
|
4973
|
+
console.warn("DynamicLoader: error during disposeMaterials in clear():", e);
|
|
4974
|
+
}
|
|
4975
|
+
}
|
|
4976
|
+
if (this.textureCache) this.textureCache.clear();
|
|
4977
|
+
if (this.materials) this.materials.clear();
|
|
4978
|
+
this.embeddedBinaryChunk = null;
|
|
4979
|
+
this.json = null;
|
|
4980
|
+
this.loadController = null;
|
|
4981
|
+
this.uri = "";
|
|
4104
4982
|
this.activeChunkLoads = 0;
|
|
4105
4983
|
this.chunkQueue = [];
|
|
4106
4984
|
this.loadingAborted = false;
|
|
4107
4985
|
this.criticalError = null;
|
|
4108
4986
|
}
|
|
4987
|
+
_rejectPendingRequests() {
|
|
4988
|
+
const pending = this.pendingRequests;
|
|
4989
|
+
this.pendingRequests = [];
|
|
4990
|
+
if (!pending || pending.length === 0) return;
|
|
4991
|
+
const cancelError = new Error("DynamicLoader: Structure cleared while requests pending");
|
|
4992
|
+
for (let i = 0; i < pending.length; i++) {
|
|
4993
|
+
const item = pending[i];
|
|
4994
|
+
if (item && typeof item._reject === "function") {
|
|
4995
|
+
try {
|
|
4996
|
+
item._reject(cancelError);
|
|
4997
|
+
} catch {
|
|
4998
|
+
}
|
|
4999
|
+
}
|
|
5000
|
+
}
|
|
5001
|
+
}
|
|
4109
5002
|
getJson() {
|
|
4110
5003
|
return this.json;
|
|
4111
5004
|
}
|
|
4112
5005
|
scheduleRequest(request) {
|
|
5006
|
+
if (this.embeddedBinaryChunk && !this.uri) {
|
|
5007
|
+
return Promise.resolve({
|
|
5008
|
+
buffer: this.embeddedBinaryChunk,
|
|
5009
|
+
relOffset: request.offset,
|
|
5010
|
+
length: request.length,
|
|
5011
|
+
});
|
|
5012
|
+
}
|
|
4113
5013
|
return new Promise((resolve, reject) => {
|
|
4114
5014
|
if (this.loadingAborted) {
|
|
4115
5015
|
reject(
|
|
@@ -4386,8 +5286,13 @@ class GltfStructure {
|
|
|
4386
5286
|
return await this.textureLoader.loadAsync(fullUrl);
|
|
4387
5287
|
} else if (image.bufferView !== undefined) {
|
|
4388
5288
|
const bufferView = this.json.bufferViews[image.bufferView];
|
|
4389
|
-
const { buffer } = await this.getBufferView(
|
|
4390
|
-
|
|
5289
|
+
const { buffer, relOffset } = await this.getBufferView(
|
|
5290
|
+
bufferView.byteOffset || 0,
|
|
5291
|
+
bufferView.byteLength,
|
|
5292
|
+
5121
|
|
5293
|
+
);
|
|
5294
|
+
const imageBytes = new Uint8Array(buffer, relOffset, bufferView.byteLength);
|
|
5295
|
+
const blob = new Blob([imageBytes], { type: image.mimeType });
|
|
4391
5296
|
const url = URL.createObjectURL(blob);
|
|
4392
5297
|
const texture = await this.textureLoader.loadAsync(url);
|
|
4393
5298
|
URL.revokeObjectURL(url);
|
|
@@ -4626,6 +5531,7 @@ class GltfStructure {
|
|
|
4626
5531
|
}
|
|
4627
5532
|
}
|
|
4628
5533
|
|
|
5534
|
+
const DRACO_EXTENSION_NAME = "KHR_draco_mesh_compression";
|
|
4629
5535
|
const STRUCTURE_ID_SEPARATOR = ":";
|
|
4630
5536
|
class DynamicGltfLoader {
|
|
4631
5537
|
constructor(camera, scene, renderer) {
|
|
@@ -4700,6 +5606,189 @@ class DynamicGltfLoader {
|
|
|
4700
5606
|
this.transformData = null;
|
|
4701
5607
|
this.identityTransformData = null;
|
|
4702
5608
|
this.visibilityMaterials = new Set();
|
|
5609
|
+
this._dracoLoader = null;
|
|
5610
|
+
}
|
|
5611
|
+
setDracoLoader(loader = null) {
|
|
5612
|
+
this._dracoLoader = loader || null;
|
|
5613
|
+
}
|
|
5614
|
+
async _decodeDracoPrimitive(structure, primitive, dracoBufferData) {
|
|
5615
|
+
const dracoExt = primitive.extensions[DRACO_EXTENSION_NAME];
|
|
5616
|
+
const loader = this._dracoLoader;
|
|
5617
|
+
const attributeIDs = {};
|
|
5618
|
+
const attributeTypes = {};
|
|
5619
|
+
const gltfNameToThreeName = new Map();
|
|
5620
|
+
const threeNameToAccessor = new Map();
|
|
5621
|
+
for (const [gltfAttrName, dracoUniqueId] of Object.entries(dracoExt.attributes)) {
|
|
5622
|
+
const threeName = this._gltfAttributeNameToThreeName(gltfAttrName);
|
|
5623
|
+
attributeIDs[threeName] = dracoUniqueId;
|
|
5624
|
+
gltfNameToThreeName.set(gltfAttrName, threeName);
|
|
5625
|
+
const accessorIdx = primitive.attributes[gltfAttrName];
|
|
5626
|
+
if (accessorIdx !== undefined) {
|
|
5627
|
+
const accessor = structure.json.accessors[accessorIdx];
|
|
5628
|
+
attributeTypes[threeName] = this._gltfComponentTypeToTypedArrayName(accessor.componentType);
|
|
5629
|
+
threeNameToAccessor.set(threeName, accessor);
|
|
5630
|
+
}
|
|
5631
|
+
}
|
|
5632
|
+
const geometry = await loader.decodeGeometry(dracoBufferData, {
|
|
5633
|
+
attributeIDs,
|
|
5634
|
+
attributeTypes,
|
|
5635
|
+
useUniqueIDs: true,
|
|
5636
|
+
});
|
|
5637
|
+
for (const [threeName, accessor] of threeNameToAccessor) {
|
|
5638
|
+
const attribute = geometry.getAttribute(threeName);
|
|
5639
|
+
if (!attribute) continue;
|
|
5640
|
+
if (accessor.normalized === true) {
|
|
5641
|
+
attribute.normalized = true;
|
|
5642
|
+
}
|
|
5643
|
+
if (accessor.min) attribute.min = accessor.min;
|
|
5644
|
+
if (accessor.max) attribute.max = accessor.max;
|
|
5645
|
+
}
|
|
5646
|
+
for (const [threeName, accessor] of threeNameToAccessor) {
|
|
5647
|
+
const attribute = geometry.getAttribute(threeName);
|
|
5648
|
+
if (!attribute || !attribute.normalized) continue;
|
|
5649
|
+
const denom = this._normalizedDenominator(accessor.componentType);
|
|
5650
|
+
if (denom <= 0) continue;
|
|
5651
|
+
const src = attribute.array;
|
|
5652
|
+
const inv = 1 / denom;
|
|
5653
|
+
const isSigned = accessor.componentType === 5120 || accessor.componentType === 5122;
|
|
5654
|
+
const out = new Float32Array(src.length);
|
|
5655
|
+
for (let i = 0; i < src.length; i++) {
|
|
5656
|
+
let v = src[i] * inv;
|
|
5657
|
+
if (isSigned && v < -1) v = -1;
|
|
5658
|
+
out[i] = v;
|
|
5659
|
+
}
|
|
5660
|
+
const newAttr = new BufferAttribute(out, attribute.itemSize, false);
|
|
5661
|
+
if (accessor.min) newAttr.min = accessor.min;
|
|
5662
|
+
if (accessor.max) newAttr.max = accessor.max;
|
|
5663
|
+
geometry.setAttribute(threeName, newAttr);
|
|
5664
|
+
}
|
|
5665
|
+
return geometry;
|
|
5666
|
+
}
|
|
5667
|
+
_gltfComponentTypeToTypedArrayName(componentType) {
|
|
5668
|
+
switch (componentType) {
|
|
5669
|
+
case 5120:
|
|
5670
|
+
return "Int8Array";
|
|
5671
|
+
case 5121:
|
|
5672
|
+
return "Uint8Array";
|
|
5673
|
+
case 5122:
|
|
5674
|
+
return "Int16Array";
|
|
5675
|
+
case 5123:
|
|
5676
|
+
return "Uint16Array";
|
|
5677
|
+
case 5125:
|
|
5678
|
+
return "Uint32Array";
|
|
5679
|
+
case 5126:
|
|
5680
|
+
return "Float32Array";
|
|
5681
|
+
default:
|
|
5682
|
+
return "Float32Array";
|
|
5683
|
+
}
|
|
5684
|
+
}
|
|
5685
|
+
_normalizedDenominator(componentType) {
|
|
5686
|
+
switch (componentType) {
|
|
5687
|
+
case 5120:
|
|
5688
|
+
return 127;
|
|
5689
|
+
case 5121:
|
|
5690
|
+
return 255;
|
|
5691
|
+
case 5122:
|
|
5692
|
+
return 32767;
|
|
5693
|
+
case 5123:
|
|
5694
|
+
return 65535;
|
|
5695
|
+
default:
|
|
5696
|
+
return 0;
|
|
5697
|
+
}
|
|
5698
|
+
}
|
|
5699
|
+
_gltfAttributeNameToThreeName(name) {
|
|
5700
|
+
switch (name) {
|
|
5701
|
+
case "POSITION":
|
|
5702
|
+
return "position";
|
|
5703
|
+
case "NORMAL":
|
|
5704
|
+
return "normal";
|
|
5705
|
+
case "TANGENT":
|
|
5706
|
+
return "tangent";
|
|
5707
|
+
case "TEXCOORD_0":
|
|
5708
|
+
return "uv";
|
|
5709
|
+
case "TEXCOORD_1":
|
|
5710
|
+
return "uv2";
|
|
5711
|
+
case "COLOR_0":
|
|
5712
|
+
return "color";
|
|
5713
|
+
case "JOINTS_0":
|
|
5714
|
+
return "skinIndex";
|
|
5715
|
+
case "WEIGHTS_0":
|
|
5716
|
+
return "skinWeight";
|
|
5717
|
+
default:
|
|
5718
|
+
return name.toLowerCase();
|
|
5719
|
+
}
|
|
5720
|
+
}
|
|
5721
|
+
_buildAccessorRequest(structure, accessorIndex, type, primIdx) {
|
|
5722
|
+
const accessor = structure.json.accessors[accessorIndex];
|
|
5723
|
+
const bufferView = structure.json.bufferViews[accessor.bufferView];
|
|
5724
|
+
const components = structure.getNumComponents(accessor.type);
|
|
5725
|
+
const componentSize = structure.getComponentSize(accessor.componentType);
|
|
5726
|
+
const itemBytes = components * componentSize;
|
|
5727
|
+
const accessorByteOffset = accessor.byteOffset || 0;
|
|
5728
|
+
const bvByteOffset = bufferView.byteOffset || 0;
|
|
5729
|
+
const byteStride = bufferView.byteStride || 0;
|
|
5730
|
+
const interleaved = byteStride !== 0 && byteStride !== itemBytes;
|
|
5731
|
+
const offset = bvByteOffset + accessorByteOffset;
|
|
5732
|
+
let length;
|
|
5733
|
+
if (interleaved) {
|
|
5734
|
+
length = (accessor.count - 1) * byteStride + itemBytes;
|
|
5735
|
+
} else {
|
|
5736
|
+
length = accessor.count * itemBytes;
|
|
5737
|
+
}
|
|
5738
|
+
return {
|
|
5739
|
+
offset,
|
|
5740
|
+
length,
|
|
5741
|
+
componentType: accessor.componentType,
|
|
5742
|
+
accessorIndex,
|
|
5743
|
+
type,
|
|
5744
|
+
primIdx,
|
|
5745
|
+
_accessor: accessor,
|
|
5746
|
+
_components: components,
|
|
5747
|
+
_componentSize: componentSize,
|
|
5748
|
+
_itemBytes: itemBytes,
|
|
5749
|
+
_byteStride: byteStride,
|
|
5750
|
+
_interleaved: interleaved,
|
|
5751
|
+
};
|
|
5752
|
+
}
|
|
5753
|
+
_createGeometryAttribute(req) {
|
|
5754
|
+
const accessor = req._accessor;
|
|
5755
|
+
const components = req._components;
|
|
5756
|
+
const count = accessor.count;
|
|
5757
|
+
const stride = req._interleaved ? req._byteStride / req._componentSize : components;
|
|
5758
|
+
const normalized = accessor.normalized === true;
|
|
5759
|
+
const componentType = req.componentType;
|
|
5760
|
+
const src = req.data;
|
|
5761
|
+
if (!req._interleaved && !normalized) {
|
|
5762
|
+
return new BufferAttribute(src, components, false);
|
|
5763
|
+
}
|
|
5764
|
+
if (normalized) {
|
|
5765
|
+
const denom = this._normalizedDenominator(componentType);
|
|
5766
|
+
if (denom > 0) {
|
|
5767
|
+
const out = new Float32Array(count * components);
|
|
5768
|
+
const inv = 1 / denom;
|
|
5769
|
+
const isSignedNormalized = componentType === 5120 || componentType === 5122;
|
|
5770
|
+
for (let i = 0; i < count; i++) {
|
|
5771
|
+
const srcBase = i * stride;
|
|
5772
|
+
const dstBase = i * components;
|
|
5773
|
+
for (let c = 0; c < components; c++) {
|
|
5774
|
+
let v = src[srcBase + c] * inv;
|
|
5775
|
+
if (isSignedNormalized && v < -1) v = -1;
|
|
5776
|
+
out[dstBase + c] = v;
|
|
5777
|
+
}
|
|
5778
|
+
}
|
|
5779
|
+
return new BufferAttribute(out, components, false);
|
|
5780
|
+
}
|
|
5781
|
+
}
|
|
5782
|
+
const TypedArrayCtor = src.constructor;
|
|
5783
|
+
const out = new TypedArrayCtor(count * components);
|
|
5784
|
+
for (let i = 0; i < count; i++) {
|
|
5785
|
+
const srcBase = i * stride;
|
|
5786
|
+
const dstBase = i * components;
|
|
5787
|
+
for (let c = 0; c < components; c++) {
|
|
5788
|
+
out[dstBase + c] = src[srcBase + c];
|
|
5789
|
+
}
|
|
5790
|
+
}
|
|
5791
|
+
return new BufferAttribute(out, components, false);
|
|
4703
5792
|
}
|
|
4704
5793
|
createDummyTexture() {
|
|
4705
5794
|
const data = new Float32Array(16);
|
|
@@ -4771,7 +5860,7 @@ class DynamicGltfLoader {
|
|
|
4771
5860
|
if (!this.transformTexture) return;
|
|
4772
5861
|
this.transformTexture.needsUpdate = true;
|
|
4773
5862
|
}
|
|
4774
|
-
setVisibleEdges(visible) {
|
|
5863
|
+
setVisibleEdges(visible = true) {
|
|
4775
5864
|
this.visibleEdges = visible;
|
|
4776
5865
|
}
|
|
4777
5866
|
getAvailableMemory() {
|
|
@@ -5025,78 +6114,51 @@ class DynamicGltfLoader {
|
|
|
5025
6114
|
node.loading = true;
|
|
5026
6115
|
const meshDef = node.structure.getJson().meshes[node.meshIndex];
|
|
5027
6116
|
try {
|
|
6117
|
+
if (
|
|
6118
|
+
!this._dracoLoader &&
|
|
6119
|
+
meshDef.primitives &&
|
|
6120
|
+
meshDef.primitives.some((p) => p.extensions && p.extensions[DRACO_EXTENSION_NAME])
|
|
6121
|
+
) {
|
|
6122
|
+
throw new Error(
|
|
6123
|
+
"primitive uses KHR_draco_mesh_compression but no DRACOLoader is configured. " +
|
|
6124
|
+
"Inject one via dynamicLoader.setDracoLoader(new DRACOLoader()) before opening the file."
|
|
6125
|
+
);
|
|
6126
|
+
}
|
|
5028
6127
|
const bufferRequests = [];
|
|
5029
6128
|
const primitiveReqMap = new Map();
|
|
6129
|
+
const dracoPrimitives = new Map();
|
|
5030
6130
|
for (let primIdx = 0; primIdx < meshDef.primitives.length; primIdx++) {
|
|
5031
6131
|
const primitive = meshDef.primitives[primIdx];
|
|
5032
6132
|
const reqs = [];
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
const
|
|
5036
|
-
const
|
|
5037
|
-
const
|
|
5038
|
-
const
|
|
5039
|
-
const count = accessor.count;
|
|
5040
|
-
const byteLength = count * components * node.structure.getComponentSize(accessor.componentType);
|
|
5041
|
-
reqs.push({
|
|
6133
|
+
const dracoExt = primitive.extensions && primitive.extensions[DRACO_EXTENSION_NAME];
|
|
6134
|
+
if (dracoExt) {
|
|
6135
|
+
const bufferView = node.structure.json.bufferViews[dracoExt.bufferView];
|
|
6136
|
+
const byteOffset = bufferView.byteOffset || 0;
|
|
6137
|
+
const byteLength = bufferView.byteLength;
|
|
6138
|
+
const dracoReq = {
|
|
5042
6139
|
offset: byteOffset,
|
|
5043
6140
|
length: byteLength,
|
|
5044
|
-
componentType:
|
|
5045
|
-
|
|
5046
|
-
type: "position",
|
|
6141
|
+
componentType: 5121,
|
|
6142
|
+
type: "draco",
|
|
5047
6143
|
primIdx,
|
|
5048
|
-
}
|
|
6144
|
+
};
|
|
6145
|
+
reqs.push(dracoReq);
|
|
6146
|
+
dracoPrimitives.set(primIdx, { req: dracoReq, primitive });
|
|
6147
|
+
primitiveReqMap.set(primIdx, reqs);
|
|
6148
|
+
bufferRequests.push(...reqs);
|
|
6149
|
+
continue;
|
|
6150
|
+
}
|
|
6151
|
+
if (primitive.attributes.POSITION !== undefined) {
|
|
6152
|
+
reqs.push(this._buildAccessorRequest(node.structure, primitive.attributes.POSITION, "position", primIdx));
|
|
5049
6153
|
}
|
|
5050
6154
|
if (primitive.attributes.NORMAL !== undefined) {
|
|
5051
|
-
|
|
5052
|
-
const accessor = node.structure.json.accessors[accessorIndex];
|
|
5053
|
-
const bufferView = node.structure.json.bufferViews[accessor.bufferView];
|
|
5054
|
-
const byteOffset = (bufferView.byteOffset || 0) + (accessor.byteOffset || 0);
|
|
5055
|
-
const components = node.structure.getNumComponents(accessor.type);
|
|
5056
|
-
const count = accessor.count;
|
|
5057
|
-
const byteLength = count * components * node.structure.getComponentSize(accessor.componentType);
|
|
5058
|
-
reqs.push({
|
|
5059
|
-
offset: byteOffset,
|
|
5060
|
-
length: byteLength,
|
|
5061
|
-
componentType: accessor.componentType,
|
|
5062
|
-
accessorIndex,
|
|
5063
|
-
type: "normal",
|
|
5064
|
-
primIdx,
|
|
5065
|
-
});
|
|
6155
|
+
reqs.push(this._buildAccessorRequest(node.structure, primitive.attributes.NORMAL, "normal", primIdx));
|
|
5066
6156
|
}
|
|
5067
6157
|
if (primitive.attributes.TEXCOORD_0 !== undefined) {
|
|
5068
|
-
|
|
5069
|
-
const accessor = node.structure.json.accessors[accessorIndex];
|
|
5070
|
-
const bufferView = node.structure.json.bufferViews[accessor.bufferView];
|
|
5071
|
-
const byteOffset = (bufferView.byteOffset || 0) + (accessor.byteOffset || 0);
|
|
5072
|
-
const components = node.structure.getNumComponents(accessor.type);
|
|
5073
|
-
const count = accessor.count;
|
|
5074
|
-
const byteLength = count * components * node.structure.getComponentSize(accessor.componentType);
|
|
5075
|
-
reqs.push({
|
|
5076
|
-
offset: byteOffset,
|
|
5077
|
-
length: byteLength,
|
|
5078
|
-
componentType: accessor.componentType,
|
|
5079
|
-
accessorIndex,
|
|
5080
|
-
type: "uv",
|
|
5081
|
-
primIdx,
|
|
5082
|
-
});
|
|
6158
|
+
reqs.push(this._buildAccessorRequest(node.structure, primitive.attributes.TEXCOORD_0, "uv", primIdx));
|
|
5083
6159
|
}
|
|
5084
6160
|
if (primitive.indices !== undefined) {
|
|
5085
|
-
|
|
5086
|
-
const accessor = node.structure.json.accessors[accessorIndex];
|
|
5087
|
-
const bufferView = node.structure.json.bufferViews[accessor.bufferView];
|
|
5088
|
-
const byteOffset = (bufferView.byteOffset || 0) + (accessor.byteOffset || 0);
|
|
5089
|
-
const components = node.structure.getNumComponents(accessor.type);
|
|
5090
|
-
const count = accessor.count;
|
|
5091
|
-
const byteLength = count * components * node.structure.getComponentSize(accessor.componentType);
|
|
5092
|
-
reqs.push({
|
|
5093
|
-
offset: byteOffset,
|
|
5094
|
-
length: byteLength,
|
|
5095
|
-
componentType: accessor.componentType,
|
|
5096
|
-
accessorIndex,
|
|
5097
|
-
type: "index",
|
|
5098
|
-
primIdx,
|
|
5099
|
-
});
|
|
6161
|
+
reqs.push(this._buildAccessorRequest(node.structure, primitive.indices, "index", primIdx));
|
|
5100
6162
|
}
|
|
5101
6163
|
primitiveReqMap.set(primIdx, reqs);
|
|
5102
6164
|
bufferRequests.push(...reqs);
|
|
@@ -5122,29 +6184,31 @@ class DynamicGltfLoader {
|
|
|
5122
6184
|
}
|
|
5123
6185
|
for (let primIdx = 0; primIdx < meshDef.primitives.length; primIdx++) {
|
|
5124
6186
|
const primitive = meshDef.primitives[primIdx];
|
|
5125
|
-
const geometry = new BufferGeometry();
|
|
5126
6187
|
const reqs = primitiveReqMap.get(primIdx);
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
const
|
|
5130
|
-
const
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
6188
|
+
let geometry;
|
|
6189
|
+
if (dracoPrimitives.has(primIdx)) {
|
|
6190
|
+
const dracoReq = reqs.find((r) => r.type === "draco");
|
|
6191
|
+
const dracoBytes = new Uint8Array(dracoReq.data.buffer, dracoReq.data.byteOffset, dracoReq.data.byteLength);
|
|
6192
|
+
const dracoBuffer = dracoBytes.slice().buffer;
|
|
6193
|
+
geometry = await this._decodeDracoPrimitive(node.structure, primitive, dracoBuffer);
|
|
6194
|
+
} else {
|
|
6195
|
+
geometry = new BufferGeometry();
|
|
6196
|
+
if (primitive.attributes.POSITION !== undefined) {
|
|
6197
|
+
const req = reqs.find((r) => r.type === "position" && r.accessorIndex === primitive.attributes.POSITION);
|
|
6198
|
+
geometry.setAttribute("position", this._createGeometryAttribute(req));
|
|
6199
|
+
}
|
|
6200
|
+
if (primitive.attributes.NORMAL !== undefined) {
|
|
6201
|
+
const req = reqs.find((r) => r.type === "normal" && r.accessorIndex === primitive.attributes.NORMAL);
|
|
6202
|
+
geometry.setAttribute("normal", this._createGeometryAttribute(req));
|
|
6203
|
+
}
|
|
6204
|
+
if (primitive.attributes.TEXCOORD_0 !== undefined) {
|
|
6205
|
+
const req = reqs.find((r) => r.type === "uv" && r.accessorIndex === primitive.attributes.TEXCOORD_0);
|
|
6206
|
+
geometry.setAttribute("uv", this._createGeometryAttribute(req));
|
|
6207
|
+
}
|
|
6208
|
+
if (primitive.indices !== undefined) {
|
|
6209
|
+
const req = reqs.find((r) => r.type === "index" && r.accessorIndex === primitive.indices);
|
|
6210
|
+
geometry.setIndex(this._createGeometryAttribute(req));
|
|
6211
|
+
}
|
|
5148
6212
|
}
|
|
5149
6213
|
let material;
|
|
5150
6214
|
if (primitive.material !== undefined) {
|
|
@@ -5383,20 +6447,43 @@ class DynamicGltfLoader {
|
|
|
5383
6447
|
const nodeMatrix = new Matrix4();
|
|
5384
6448
|
const uniqueNodeId = `${structure.id}_${nodeId}`;
|
|
5385
6449
|
const meshDef = structure.json.meshes[nodeDef.mesh];
|
|
6450
|
+
if (!meshDef || !meshDef.primitives || meshDef.primitives.length === 0) {
|
|
6451
|
+
if (nodeDef.children) {
|
|
6452
|
+
for (const childId of nodeDef.children) {
|
|
6453
|
+
await this.processNodeHierarchy(structure, childId, nodeGroup || parentGroup);
|
|
6454
|
+
}
|
|
6455
|
+
}
|
|
6456
|
+
return nodeGroup;
|
|
6457
|
+
}
|
|
5386
6458
|
const geometryExtents = new Box3();
|
|
5387
6459
|
for (const primitive of meshDef.primitives) {
|
|
6460
|
+
if (!primitive.attributes) continue;
|
|
5388
6461
|
const positionAccessor = structure.json.accessors[primitive.attributes.POSITION];
|
|
5389
6462
|
if (positionAccessor && positionAccessor.min && positionAccessor.max) {
|
|
5390
|
-
const
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
6463
|
+
const minVec = new Vector3().fromArray(positionAccessor.min);
|
|
6464
|
+
const maxVec = new Vector3().fromArray(positionAccessor.max);
|
|
6465
|
+
if (positionAccessor.normalized === true) {
|
|
6466
|
+
const denom = this._normalizedDenominator(positionAccessor.componentType);
|
|
6467
|
+
if (denom > 0) {
|
|
6468
|
+
minVec.divideScalar(denom);
|
|
6469
|
+
maxVec.divideScalar(denom);
|
|
6470
|
+
if (positionAccessor.componentType === 5120 || positionAccessor.componentType === 5122) {
|
|
6471
|
+
minVec.x = Math.max(minVec.x, -1);
|
|
6472
|
+
minVec.y = Math.max(minVec.y, -1);
|
|
6473
|
+
minVec.z = Math.max(minVec.z, -1);
|
|
6474
|
+
maxVec.x = Math.max(maxVec.x, -1);
|
|
6475
|
+
maxVec.y = Math.max(maxVec.y, -1);
|
|
6476
|
+
maxVec.z = Math.max(maxVec.z, -1);
|
|
6477
|
+
}
|
|
6478
|
+
}
|
|
6479
|
+
}
|
|
6480
|
+
geometryExtents.union(new Box3(minVec, maxVec));
|
|
5395
6481
|
}
|
|
5396
6482
|
}
|
|
5397
6483
|
let isEdge = false;
|
|
5398
|
-
|
|
5399
|
-
|
|
6484
|
+
const firstPrimitive = meshDef.primitives[0];
|
|
6485
|
+
if (firstPrimitive && firstPrimitive.material !== undefined) {
|
|
6486
|
+
const material = structure.json.materials[firstPrimitive.material];
|
|
5400
6487
|
if (material?.name === "edges") {
|
|
5401
6488
|
isEdge = true;
|
|
5402
6489
|
}
|
|
@@ -5709,6 +6796,10 @@ class DynamicGltfLoader {
|
|
|
5709
6796
|
vec3 objectNormal = vec3( normal );
|
|
5710
6797
|
mat3 bm = mat3( batchingMatrix );
|
|
5711
6798
|
objectNormal = bm * objectNormal;
|
|
6799
|
+
#ifdef USE_TANGENT
|
|
6800
|
+
vec3 objectTangent = vec3( tangent.xyz );
|
|
6801
|
+
objectTangent = bm * objectTangent;
|
|
6802
|
+
#endif
|
|
5712
6803
|
`
|
|
5713
6804
|
);
|
|
5714
6805
|
}
|
|
@@ -6881,7 +7972,7 @@ class DynamicGltfLoader {
|
|
|
6881
7972
|
}
|
|
6882
7973
|
return extent;
|
|
6883
7974
|
}
|
|
6884
|
-
setMaxConcurrentChunks(maxChunks) {
|
|
7975
|
+
setMaxConcurrentChunks(maxChunks = 6) {
|
|
6885
7976
|
if (maxChunks < 1) {
|
|
6886
7977
|
console.warn("Max concurrent chunks must be at least 1");
|
|
6887
7978
|
return;
|
|
@@ -7077,8 +8168,10 @@ class GLTFFileDynamicLoader extends Loader {
|
|
|
7077
8168
|
this.manager = new GLTFLoadingManager(file, params);
|
|
7078
8169
|
const scene = new Group();
|
|
7079
8170
|
this.gltfLoader = new DynamicGltfLoader(this.viewer.camera, scene, this.viewer.renderer);
|
|
7080
|
-
this.gltfLoader.
|
|
7081
|
-
this.gltfLoader.
|
|
8171
|
+
this.gltfLoader.setMemoryLimit(this.viewer.options.memoryLimit);
|
|
8172
|
+
this.gltfLoader.setVisibleEdges(this.viewer.options.edgeModel);
|
|
8173
|
+
this.gltfLoader.setMaxConcurrentChunks(params.maxConcurrentChunks);
|
|
8174
|
+
this.gltfLoader.setDracoLoader(params.dracoLoader);
|
|
7082
8175
|
const modelImpl = new DynamicModelImpl(scene);
|
|
7083
8176
|
modelImpl.id = params.modelId || this.extractFileName(file);
|
|
7084
8177
|
modelImpl.gltfLoader = this.gltfLoader;
|
|
@@ -7165,8 +8258,10 @@ class GLTFCloudDynamicLoader extends Loader {
|
|
|
7165
8258
|
async load(model, format, params = {}) {
|
|
7166
8259
|
const scene = new Group();
|
|
7167
8260
|
this.gltfLoader = new DynamicGltfLoader(this.viewer.camera, scene, this.viewer.renderer);
|
|
7168
|
-
this.gltfLoader.
|
|
8261
|
+
this.gltfLoader.setMemoryLimit(this.viewer.options.memoryLimit);
|
|
7169
8262
|
this.gltfLoader.setVisibleEdges(this.viewer.options.edgeModel);
|
|
8263
|
+
this.gltfLoader.setMaxConcurrentChunks(params.maxConcurrentChunks);
|
|
8264
|
+
this.gltfLoader.setDracoLoader(params.dracoLoader);
|
|
7170
8265
|
const modelImpl = new DynamicModelImpl(scene);
|
|
7171
8266
|
modelImpl.id = model.file.id;
|
|
7172
8267
|
modelImpl.gltfLoader = this.gltfLoader;
|
|
@@ -7226,207 +8321,6 @@ const loaders = loadersRegistry("threejs");
|
|
|
7226
8321
|
loaders.registerLoader("gltf-file", (viewer) => new GLTFFileDynamicLoader(viewer));
|
|
7227
8322
|
loaders.registerLoader("gltf-cloud", (viewer) => new GLTFCloudDynamicLoader(viewer));
|
|
7228
8323
|
|
|
7229
|
-
class SSAARenderPass extends Pass {
|
|
7230
|
-
constructor(scenes, camera, clearColor = 0x000000, clearAlpha = 0) {
|
|
7231
|
-
super();
|
|
7232
|
-
this.scenes = Array.isArray(scenes) ? scenes : [scenes];
|
|
7233
|
-
this.camera = camera;
|
|
7234
|
-
this.sampleLevel = 2;
|
|
7235
|
-
this.unbiased = true;
|
|
7236
|
-
this.stencilBuffer = false;
|
|
7237
|
-
this.clearColor = clearColor;
|
|
7238
|
-
this.clearAlpha = clearAlpha;
|
|
7239
|
-
this._sampleRenderTarget = null;
|
|
7240
|
-
this._oldClearColor = new Color();
|
|
7241
|
-
this._copyUniforms = UniformsUtils.clone(CopyShader.uniforms);
|
|
7242
|
-
this._copyMaterial = new ShaderMaterial({
|
|
7243
|
-
uniforms: this._copyUniforms,
|
|
7244
|
-
vertexShader: CopyShader.vertexShader,
|
|
7245
|
-
fragmentShader: CopyShader.fragmentShader,
|
|
7246
|
-
transparent: true,
|
|
7247
|
-
depthTest: false,
|
|
7248
|
-
depthWrite: false,
|
|
7249
|
-
premultipliedAlpha: true,
|
|
7250
|
-
blending: AdditiveBlending,
|
|
7251
|
-
});
|
|
7252
|
-
this._fsQuad = new FullScreenQuad(this._copyMaterial);
|
|
7253
|
-
}
|
|
7254
|
-
dispose() {
|
|
7255
|
-
if (this._sampleRenderTarget) {
|
|
7256
|
-
this._sampleRenderTarget.dispose();
|
|
7257
|
-
this._sampleRenderTarget = null;
|
|
7258
|
-
}
|
|
7259
|
-
this._copyMaterial.dispose();
|
|
7260
|
-
this._fsQuad.dispose();
|
|
7261
|
-
}
|
|
7262
|
-
setSize(width, height) {
|
|
7263
|
-
if (this._sampleRenderTarget) this._sampleRenderTarget.setSize(width, height);
|
|
7264
|
-
}
|
|
7265
|
-
render(renderer, writeBuffer, readBuffer, deltaTime, maskActive) {
|
|
7266
|
-
if (!this._sampleRenderTarget) {
|
|
7267
|
-
this._sampleRenderTarget = new WebGLRenderTarget(readBuffer.width, readBuffer.height, {
|
|
7268
|
-
type: HalfFloatType,
|
|
7269
|
-
stencilBuffer: this.stencilBuffer,
|
|
7270
|
-
});
|
|
7271
|
-
this._sampleRenderTarget.texture.name = "SSAAMultiRenderPass.sample";
|
|
7272
|
-
}
|
|
7273
|
-
const jitterOffsets = _JitterVectors[Math.max(0, Math.min(this.sampleLevel, 5))];
|
|
7274
|
-
const autoClear = renderer.autoClear;
|
|
7275
|
-
renderer.autoClear = false;
|
|
7276
|
-
renderer.getClearColor(this._oldClearColor);
|
|
7277
|
-
const oldClearAlpha = renderer.getClearAlpha();
|
|
7278
|
-
const baseSampleWeight = 1.0 / jitterOffsets.length;
|
|
7279
|
-
const roundingRange = 1 / 32;
|
|
7280
|
-
this._copyUniforms["tDiffuse"].value = this._sampleRenderTarget.texture;
|
|
7281
|
-
const viewOffset = {
|
|
7282
|
-
fullWidth: readBuffer.width,
|
|
7283
|
-
fullHeight: readBuffer.height,
|
|
7284
|
-
offsetX: 0,
|
|
7285
|
-
offsetY: 0,
|
|
7286
|
-
width: readBuffer.width,
|
|
7287
|
-
height: readBuffer.height,
|
|
7288
|
-
};
|
|
7289
|
-
const originalViewOffset = Object.assign({}, this.camera.view);
|
|
7290
|
-
if (originalViewOffset.enabled) Object.assign(viewOffset, originalViewOffset);
|
|
7291
|
-
for (let i = 0; i < jitterOffsets.length; i++) {
|
|
7292
|
-
const jitterOffset = jitterOffsets[i];
|
|
7293
|
-
if (this.camera.setViewOffset) {
|
|
7294
|
-
this.camera.setViewOffset(
|
|
7295
|
-
viewOffset.fullWidth,
|
|
7296
|
-
viewOffset.fullHeight,
|
|
7297
|
-
viewOffset.offsetX + jitterOffset[0] * 0.0625,
|
|
7298
|
-
viewOffset.offsetY + jitterOffset[1] * 0.0625,
|
|
7299
|
-
viewOffset.width,
|
|
7300
|
-
viewOffset.height
|
|
7301
|
-
);
|
|
7302
|
-
}
|
|
7303
|
-
let sampleWeight = baseSampleWeight;
|
|
7304
|
-
if (this.unbiased) {
|
|
7305
|
-
const uniformCenteredDistribution = -0.5 + (i + 0.5) / jitterOffsets.length;
|
|
7306
|
-
sampleWeight += roundingRange * uniformCenteredDistribution;
|
|
7307
|
-
}
|
|
7308
|
-
this._copyUniforms["opacity"].value = sampleWeight;
|
|
7309
|
-
renderer.setClearColor(this.clearColor, this.clearAlpha);
|
|
7310
|
-
renderer.setRenderTarget(this._sampleRenderTarget);
|
|
7311
|
-
renderer.clear();
|
|
7312
|
-
this.scenes.forEach((scene) => renderer.render(scene, this.camera));
|
|
7313
|
-
renderer.setRenderTarget(this.renderToScreen ? null : writeBuffer);
|
|
7314
|
-
if (i === 0) {
|
|
7315
|
-
renderer.setClearColor(0x000000, 0.0);
|
|
7316
|
-
renderer.clear();
|
|
7317
|
-
}
|
|
7318
|
-
this._fsQuad.render(renderer);
|
|
7319
|
-
}
|
|
7320
|
-
if (this.camera.setViewOffset && originalViewOffset.enabled) {
|
|
7321
|
-
this.camera.setViewOffset(
|
|
7322
|
-
originalViewOffset.fullWidth,
|
|
7323
|
-
originalViewOffset.fullHeight,
|
|
7324
|
-
originalViewOffset.offsetX,
|
|
7325
|
-
originalViewOffset.offsetY,
|
|
7326
|
-
originalViewOffset.width,
|
|
7327
|
-
originalViewOffset.height
|
|
7328
|
-
);
|
|
7329
|
-
} else if (this.camera.clearViewOffset) {
|
|
7330
|
-
this.camera.clearViewOffset();
|
|
7331
|
-
}
|
|
7332
|
-
renderer.autoClear = autoClear;
|
|
7333
|
-
renderer.setClearColor(this._oldClearColor, oldClearAlpha);
|
|
7334
|
-
}
|
|
7335
|
-
}
|
|
7336
|
-
const _JitterVectors = [
|
|
7337
|
-
[[0, 0]],
|
|
7338
|
-
[
|
|
7339
|
-
[4, 4],
|
|
7340
|
-
[-4, -4],
|
|
7341
|
-
],
|
|
7342
|
-
[
|
|
7343
|
-
[-2, -6],
|
|
7344
|
-
[6, -2],
|
|
7345
|
-
[-6, 2],
|
|
7346
|
-
[2, 6],
|
|
7347
|
-
],
|
|
7348
|
-
[
|
|
7349
|
-
[1, -3],
|
|
7350
|
-
[-1, 3],
|
|
7351
|
-
[5, 1],
|
|
7352
|
-
[-3, -5],
|
|
7353
|
-
[-5, 5],
|
|
7354
|
-
[-7, -1],
|
|
7355
|
-
[3, 7],
|
|
7356
|
-
[7, -7],
|
|
7357
|
-
],
|
|
7358
|
-
[
|
|
7359
|
-
[1, 1],
|
|
7360
|
-
[-1, -3],
|
|
7361
|
-
[-3, 2],
|
|
7362
|
-
[4, -1],
|
|
7363
|
-
[-5, -2],
|
|
7364
|
-
[2, 5],
|
|
7365
|
-
[5, 3],
|
|
7366
|
-
[3, -5],
|
|
7367
|
-
[-2, 6],
|
|
7368
|
-
[0, -7],
|
|
7369
|
-
[-4, -6],
|
|
7370
|
-
[-6, 4],
|
|
7371
|
-
[-8, 0],
|
|
7372
|
-
[7, -4],
|
|
7373
|
-
[6, 7],
|
|
7374
|
-
[-7, -8],
|
|
7375
|
-
],
|
|
7376
|
-
[
|
|
7377
|
-
[-4, -7],
|
|
7378
|
-
[-7, -5],
|
|
7379
|
-
[-3, -5],
|
|
7380
|
-
[-5, -4],
|
|
7381
|
-
[-1, -4],
|
|
7382
|
-
[-2, -2],
|
|
7383
|
-
[-6, -1],
|
|
7384
|
-
[-4, 0],
|
|
7385
|
-
[-7, 1],
|
|
7386
|
-
[-1, 2],
|
|
7387
|
-
[-6, 3],
|
|
7388
|
-
[-3, 3],
|
|
7389
|
-
[-7, 6],
|
|
7390
|
-
[-3, 6],
|
|
7391
|
-
[-5, 7],
|
|
7392
|
-
[-1, 7],
|
|
7393
|
-
[5, -7],
|
|
7394
|
-
[1, -6],
|
|
7395
|
-
[6, -5],
|
|
7396
|
-
[4, -4],
|
|
7397
|
-
[2, -3],
|
|
7398
|
-
[7, -2],
|
|
7399
|
-
[1, -1],
|
|
7400
|
-
[4, -1],
|
|
7401
|
-
[2, 1],
|
|
7402
|
-
[6, 2],
|
|
7403
|
-
[0, 4],
|
|
7404
|
-
[4, 4],
|
|
7405
|
-
[2, 5],
|
|
7406
|
-
[7, 5],
|
|
7407
|
-
[5, 6],
|
|
7408
|
-
[3, 7],
|
|
7409
|
-
],
|
|
7410
|
-
];
|
|
7411
|
-
|
|
7412
|
-
class Helpers extends Scene {
|
|
7413
|
-
constructor() {
|
|
7414
|
-
super(...arguments);
|
|
7415
|
-
this.oldAutoClear = false;
|
|
7416
|
-
this.oldClippingPlanes = [];
|
|
7417
|
-
}
|
|
7418
|
-
onBeforeRender(renderer) {
|
|
7419
|
-
this.oldAutoClear = renderer.autoClear;
|
|
7420
|
-
this.oldClippingPlanes = renderer.clippingPlanes;
|
|
7421
|
-
renderer.autoClear = false;
|
|
7422
|
-
renderer.clippingPlanes = [];
|
|
7423
|
-
}
|
|
7424
|
-
onAfterRender(renderer) {
|
|
7425
|
-
renderer.clippingPlanes = this.oldClippingPlanes;
|
|
7426
|
-
renderer.autoClear = this.oldAutoClear;
|
|
7427
|
-
}
|
|
7428
|
-
}
|
|
7429
|
-
|
|
7430
8324
|
class Viewer extends EventEmitter2 {
|
|
7431
8325
|
constructor(client) {
|
|
7432
8326
|
super();
|
|
@@ -7440,9 +8334,9 @@ class Viewer extends EventEmitter2 {
|
|
|
7440
8334
|
this.selected = [];
|
|
7441
8335
|
this.extents = new Box3();
|
|
7442
8336
|
this.target = new Vector3(0, 0, 0);
|
|
8337
|
+
this.clippingPlanes = [];
|
|
7443
8338
|
this._activeDragger = null;
|
|
7444
8339
|
this._components = [];
|
|
7445
|
-
this._updateDelay = 1000;
|
|
7446
8340
|
this._renderNeeded = false;
|
|
7447
8341
|
this._renderTime = 0;
|
|
7448
8342
|
this.render = this.render.bind(this);
|
|
@@ -7461,7 +8355,9 @@ class Viewer extends EventEmitter2 {
|
|
|
7461
8355
|
initialize(canvas, onProgress) {
|
|
7462
8356
|
this.addEventListener("optionschange", (event) => this.syncOptions(event.data));
|
|
7463
8357
|
this.scene = new Scene();
|
|
7464
|
-
this.helpers = new
|
|
8358
|
+
this.helpers = new Group();
|
|
8359
|
+
this.helpers.name = "Helpers";
|
|
8360
|
+
this.scene.add(this.helpers);
|
|
7465
8361
|
const pixelRatio = window.devicePixelRatio;
|
|
7466
8362
|
const rect = canvas.parentElement.getBoundingClientRect();
|
|
7467
8363
|
const width = rect.width || 1;
|
|
@@ -7483,17 +8379,17 @@ class Viewer extends EventEmitter2 {
|
|
|
7483
8379
|
this.renderer.setPixelRatio(pixelRatio);
|
|
7484
8380
|
this.renderer.setSize(width, height);
|
|
7485
8381
|
this.renderer.outputColorSpace = LinearSRGBColorSpace;
|
|
8382
|
+
this.renderer.localClippingEnabled = true;
|
|
7486
8383
|
this.renderPass = new RenderPass(this.scene, this.camera);
|
|
7487
|
-
this.helpersPass = new RenderPass(this.helpers, this.camera);
|
|
7488
|
-
this.helpersPass.clear = false;
|
|
7489
8384
|
this.fxaaPass = new FXAAPass();
|
|
7490
8385
|
this.smaaPass = new SMAAPass();
|
|
7491
|
-
this.ssaaRenderPass = new SSAARenderPass(
|
|
8386
|
+
this.ssaaRenderPass = new SSAARenderPass(this.scene, this.camera);
|
|
7492
8387
|
this.ssaaRenderPass.unbiased = true;
|
|
7493
8388
|
this.outputPass = new OutputPass();
|
|
7494
|
-
|
|
8389
|
+
const renderTarget = new WebGLRenderTarget(1, 1, { samples: 4 });
|
|
8390
|
+
renderTarget.texture.name = "EffectComposer.rt1";
|
|
8391
|
+
this.composer = new EffectComposer(this.renderer, renderTarget);
|
|
7495
8392
|
this.composer.addPass(this.renderPass);
|
|
7496
|
-
this.composer.addPass(this.helpersPass);
|
|
7497
8393
|
this.composer.addPass(this.smaaPass);
|
|
7498
8394
|
this.composer.addPass(this.fxaaPass);
|
|
7499
8395
|
this.composer.addPass(this.ssaaRenderPass);
|
|
@@ -7524,8 +8420,11 @@ class Viewer extends EventEmitter2 {
|
|
|
7524
8420
|
this.removeAllListeners();
|
|
7525
8421
|
this.setActiveDragger();
|
|
7526
8422
|
this._components.forEach((component) => component.dispose());
|
|
7527
|
-
this._components =
|
|
7528
|
-
this._markup
|
|
8423
|
+
this._components.length = 0;
|
|
8424
|
+
if (this._markup) {
|
|
8425
|
+
this._markup.dispose();
|
|
8426
|
+
this._markup = undefined;
|
|
8427
|
+
}
|
|
7529
8428
|
if (this.canvas) {
|
|
7530
8429
|
this.canvasEvents.forEach((x) => this.canvas.removeEventListener(x, this.canvaseventlistener));
|
|
7531
8430
|
this.canvas = undefined;
|
|
@@ -7534,8 +8433,6 @@ class Viewer extends EventEmitter2 {
|
|
|
7534
8433
|
this.composer.dispose();
|
|
7535
8434
|
if (this.renderPass)
|
|
7536
8435
|
this.renderPass.dispose();
|
|
7537
|
-
if (this.helpersPass)
|
|
7538
|
-
this.helpersPass.dispose();
|
|
7539
8436
|
if (this.fxaaPass)
|
|
7540
8437
|
this.fxaaPass.dispose();
|
|
7541
8438
|
if (this.smaaPass)
|
|
@@ -7551,7 +8448,6 @@ class Viewer extends EventEmitter2 {
|
|
|
7551
8448
|
this.camera = undefined;
|
|
7552
8449
|
this.renderer = undefined;
|
|
7553
8450
|
this.renderPass = undefined;
|
|
7554
|
-
this.helpersPass = undefined;
|
|
7555
8451
|
this.fxaaPass = undefined;
|
|
7556
8452
|
this.smaaPass = undefined;
|
|
7557
8453
|
this.ssaaRenderPass = undefined;
|
|
@@ -7583,11 +8479,12 @@ class Viewer extends EventEmitter2 {
|
|
|
7583
8479
|
}
|
|
7584
8480
|
update(force = false) {
|
|
7585
8481
|
const time = performance.now();
|
|
7586
|
-
|
|
8482
|
+
if (typeof force === "number" && time - this._renderTime >= force)
|
|
8483
|
+
force = true;
|
|
7587
8484
|
this._renderNeeded = true;
|
|
7588
8485
|
if (force)
|
|
7589
8486
|
this.render(time);
|
|
7590
|
-
this.emitEvent({ type: "update", force });
|
|
8487
|
+
this.emitEvent({ type: "update", force: !!force });
|
|
7591
8488
|
}
|
|
7592
8489
|
render(time, force = false) {
|
|
7593
8490
|
if (!this.renderer)
|
|
@@ -7601,13 +8498,7 @@ class Viewer extends EventEmitter2 {
|
|
|
7601
8498
|
this._renderNeeded = false;
|
|
7602
8499
|
this.renderer.info.autoReset = false;
|
|
7603
8500
|
this.renderer.info.reset();
|
|
7604
|
-
|
|
7605
|
-
this.renderer.render(this.scene, this.camera);
|
|
7606
|
-
this.renderer.render(this.helpers, this.camera);
|
|
7607
|
-
}
|
|
7608
|
-
else {
|
|
7609
|
-
this.composer.render(deltaTime);
|
|
7610
|
-
}
|
|
8501
|
+
this.composer.render(deltaTime);
|
|
7611
8502
|
this.emitEvent({ type: "render", time, deltaTime });
|
|
7612
8503
|
}
|
|
7613
8504
|
loadReferences(model) {
|
|
@@ -7667,11 +8558,12 @@ class Viewer extends EventEmitter2 {
|
|
|
7667
8558
|
this.clearOverlay();
|
|
7668
8559
|
this.clearSelected();
|
|
7669
8560
|
this.loaders.forEach((loader) => loader.dispose());
|
|
7670
|
-
this.loaders =
|
|
8561
|
+
this.loaders.length = 0;
|
|
7671
8562
|
this.models.forEach((model) => model.dispose());
|
|
7672
|
-
this.models =
|
|
7673
|
-
this.scene.clear();
|
|
8563
|
+
this.models.length = 0;
|
|
7674
8564
|
this.helpers.clear();
|
|
8565
|
+
this.scene.clear();
|
|
8566
|
+
this.scene.add(this.helpers);
|
|
7675
8567
|
this.extents.makeEmpty();
|
|
7676
8568
|
this.syncOptions();
|
|
7677
8569
|
this.syncOverlay();
|
|
@@ -7688,8 +8580,15 @@ class Viewer extends EventEmitter2 {
|
|
|
7688
8580
|
this.fxaaPass.enabled = options.antialiasing === "fxaa";
|
|
7689
8581
|
this.smaaPass.enabled = options.antialiasing === "smaa";
|
|
7690
8582
|
this.ssaaRenderPass.enabled = options.antialiasing === "ssaa";
|
|
7691
|
-
this.renderPass.enabled =
|
|
7692
|
-
|
|
8583
|
+
this.renderPass.enabled = options.antialiasing !== "ssaa";
|
|
8584
|
+
const samples = options.antialiasing === true || options.antialiasing === "msaa" ? 4 : 0;
|
|
8585
|
+
if (this.composer.renderTarget1.samples !== samples) {
|
|
8586
|
+
const size = this.renderer.getSize(new Vector2());
|
|
8587
|
+
const newRenderTarget = new WebGLRenderTarget(1, 1, { samples });
|
|
8588
|
+
newRenderTarget.texture.name = "EffectComposer.rt1";
|
|
8589
|
+
this.composer.reset(newRenderTarget);
|
|
8590
|
+
this.composer.setSize(size.x, size.y);
|
|
8591
|
+
}
|
|
7693
8592
|
this.update();
|
|
7694
8593
|
}
|
|
7695
8594
|
syncOverlay() {
|
|
@@ -7708,7 +8607,8 @@ class Viewer extends EventEmitter2 {
|
|
|
7708
8607
|
clearSlices() {
|
|
7709
8608
|
if (!this.renderer)
|
|
7710
8609
|
return;
|
|
7711
|
-
this.
|
|
8610
|
+
this.clippingPlanes.length = 0;
|
|
8611
|
+
this.emitEvent({ type: "changecuttingplanes" });
|
|
7712
8612
|
this.emitEvent({ type: "clearslices" });
|
|
7713
8613
|
this.update();
|
|
7714
8614
|
}
|
|
@@ -7804,7 +8704,6 @@ class Viewer extends EventEmitter2 {
|
|
|
7804
8704
|
camera.updateMatrixWorld();
|
|
7805
8705
|
this.camera = camera;
|
|
7806
8706
|
this.renderPass.camera = camera;
|
|
7807
|
-
this.helpersPass.camera = camera;
|
|
7808
8707
|
this.ssaaRenderPass.camera = camera;
|
|
7809
8708
|
this.options.cameraMode = "orthographic";
|
|
7810
8709
|
this.emitEvent({ type: "changecameramode", mode: "orthographic" });
|
|
@@ -7827,7 +8726,6 @@ class Viewer extends EventEmitter2 {
|
|
|
7827
8726
|
camera.updateMatrixWorld();
|
|
7828
8727
|
this.camera = camera;
|
|
7829
8728
|
this.renderPass.camera = camera;
|
|
7830
|
-
this.helpersPass.camera = camera;
|
|
7831
8729
|
this.ssaaRenderPass.camera = camera;
|
|
7832
8730
|
this.options.cameraMode = "perspective";
|
|
7833
8731
|
this.emitEvent({ type: "changecameramode", mode: "perspective" });
|
|
@@ -7838,8 +8736,9 @@ class Viewer extends EventEmitter2 {
|
|
|
7838
8736
|
clipping_planes.forEach((clipping_plane) => {
|
|
7839
8737
|
const plane = new Plane();
|
|
7840
8738
|
plane.setFromNormalAndCoplanarPoint(getVector3FromPoint3d(clipping_plane.direction), getVector3FromPoint3d(clipping_plane.location));
|
|
7841
|
-
this.
|
|
8739
|
+
this.clippingPlanes.push(plane);
|
|
7842
8740
|
});
|
|
8741
|
+
this.emitEvent({ type: "changecuttingplanes" });
|
|
7843
8742
|
}
|
|
7844
8743
|
};
|
|
7845
8744
|
const setSelection = (selection) => {
|
|
@@ -7894,7 +8793,7 @@ class Viewer extends EventEmitter2 {
|
|
|
7894
8793
|
};
|
|
7895
8794
|
const getClippingPlanes = () => {
|
|
7896
8795
|
const clipping_planes = [];
|
|
7897
|
-
this.
|
|
8796
|
+
this.clippingPlanes.forEach((plane) => {
|
|
7898
8797
|
const clipping_plane = {
|
|
7899
8798
|
location: getPoint3dFromVector3(plane.coplanarPoint(new Vector3())),
|
|
7900
8799
|
direction: getPoint3dFromVector3(plane.normal),
|