@inweb/viewer-three 27.2.3 → 27.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/viewer-three.js +319 -652
- package/dist/viewer-three.js.map +1 -1
- package/dist/viewer-three.min.js +3 -3
- package/dist/viewer-three.module.js +321 -654
- package/dist/viewer-three.module.js.map +1 -1
- package/lib/Viewer/controls/WalkControls.d.ts +0 -8
- package/lib/Viewer/draggers/CuttingPlaneDragger.d.ts +5 -23
- package/lib/Viewer/helpers/PlaneHelper2.d.ts +4 -8
- package/lib/Viewer/measurement/Snapper.d.ts +1 -1
- package/package.json +5 -5
- package/src/Viewer/components/SelectionComponent.ts +1 -1
- package/src/Viewer/controls/WalkControls.ts +4 -50
- package/src/Viewer/draggers/CuttingPlaneDragger.ts +31 -191
- package/src/Viewer/draggers/CuttingPlaneXAxis.ts +3 -2
- package/src/Viewer/draggers/CuttingPlaneYAxis.ts +3 -2
- package/src/Viewer/draggers/CuttingPlaneZAxis.ts +3 -2
- package/src/Viewer/draggers/index.ts +0 -2
- package/src/Viewer/helpers/PlaneHelper2.ts +17 -30
- package/src/Viewer/loaders/DynamicGltfLoader/DynamicGltfLoader.js +189 -413
- package/src/Viewer/measurement/Snapper.ts +5 -13
|
@@ -23,7 +23,7 @@
|
|
|
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 {
|
|
26
|
+
import { Line, BufferGeometry, Float32BufferAttribute, LineBasicMaterial, Mesh, MeshBasicMaterial, DoubleSide, EventDispatcher, Vector3, MOUSE, TOUCH, Spherical, Quaternion, Vector2, Plane, Object3D, Line3, Raycaster, MathUtils, EdgesGeometry, Matrix4, Vector4, Controls, Clock, Box3, Color, PerspectiveCamera, OrthographicCamera, AmbientLight, DirectionalLight, HemisphereLight, REVISION, MeshPhongMaterial, WebGLRenderTarget, UnsignedByteType, RGBAFormat, CylinderGeometry, Sprite, CanvasTexture, SRGBColorSpace, SpriteMaterial, TextureLoader, BufferAttribute, PointsMaterial, Points, TriangleStripDrawMode, TriangleFanDrawMode, LineSegments, LineLoop, Group, NormalBlending, LoadingManager, LoaderUtils, FileLoader, UniformsUtils, ShaderMaterial, AdditiveBlending, HalfFloatType, Scene, WebGLRenderer, LinearSRGBColorSpace } from 'three';
|
|
27
27
|
import { TransformControls } from 'three/examples/jsm/controls/TransformControls.js';
|
|
28
28
|
import { LineSegmentsGeometry } from 'three/examples/jsm/lines/LineSegmentsGeometry.js';
|
|
29
29
|
import { Wireframe } from 'three/examples/jsm/lines/Wireframe.js';
|
|
@@ -41,6 +41,41 @@ import { EventEmitter2 } from '@inweb/eventemitter2';
|
|
|
41
41
|
import { Markup } from '@inweb/markup';
|
|
42
42
|
export * from '@inweb/markup';
|
|
43
43
|
|
|
44
|
+
class PlaneHelper2 extends Line {
|
|
45
|
+
constructor(size = 1, color = 0xc0c0c0) {
|
|
46
|
+
const positions = [1, 1, 0, -1, 1, 0, -1, -1, 0, 1, -1, 0, 1, 1, 0];
|
|
47
|
+
const geometry = new BufferGeometry();
|
|
48
|
+
geometry.setAttribute("position", new Float32BufferAttribute(positions, 3));
|
|
49
|
+
geometry.computeBoundingSphere();
|
|
50
|
+
super(geometry, new LineBasicMaterial({ color, toneMapped: false }));
|
|
51
|
+
this.type = "PlaneHelper2";
|
|
52
|
+
this.size = size;
|
|
53
|
+
const positions2 = [1, 1, 0, -1, 1, 0, -1, -1, 0, 1, 1, 0, -1, -1, 0, 1, -1, 0];
|
|
54
|
+
const geometry2 = new BufferGeometry();
|
|
55
|
+
geometry2.setAttribute("position", new Float32BufferAttribute(positions2, 3));
|
|
56
|
+
geometry2.computeBoundingSphere();
|
|
57
|
+
this.helper = new Mesh(geometry2, new MeshBasicMaterial({
|
|
58
|
+
color,
|
|
59
|
+
opacity: 0.2,
|
|
60
|
+
transparent: true,
|
|
61
|
+
depthWrite: false,
|
|
62
|
+
toneMapped: false,
|
|
63
|
+
side: DoubleSide,
|
|
64
|
+
}));
|
|
65
|
+
this.add(this.helper);
|
|
66
|
+
}
|
|
67
|
+
dispose() {
|
|
68
|
+
this.geometry.dispose();
|
|
69
|
+
this.material.dispose();
|
|
70
|
+
this.helper.geometry.dispose();
|
|
71
|
+
this.helper.material.dispose();
|
|
72
|
+
}
|
|
73
|
+
updateMatrixWorld(force) {
|
|
74
|
+
this.scale.set(0.5 * this.size, 0.5 * this.size, 1);
|
|
75
|
+
super.updateMatrixWorld(force);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
44
79
|
const _changeEvent = { type: "change" };
|
|
45
80
|
const _startEvent = { type: "start" };
|
|
46
81
|
const _endEvent = { type: "end" };
|
|
@@ -699,166 +734,6 @@ class OrbitControls extends EventDispatcher {
|
|
|
699
734
|
}
|
|
700
735
|
}
|
|
701
736
|
|
|
702
|
-
class PlaneHelper2 extends Object3D {
|
|
703
|
-
constructor(size = 1, color = 0xf0f0f0, opacity = 0.15) {
|
|
704
|
-
super();
|
|
705
|
-
this.type = "PlaneHelper2";
|
|
706
|
-
this.size = size;
|
|
707
|
-
const positions = [1, 1, 0, -1, 1, 0, -1, -1, 0, 1, -1, 0, 1, 1, 0];
|
|
708
|
-
const geometry = new BufferGeometry();
|
|
709
|
-
geometry.setAttribute("position", new Float32BufferAttribute(positions, 3));
|
|
710
|
-
geometry.computeBoundingSphere();
|
|
711
|
-
this.outline = new Line(geometry, new LineBasicMaterial({ color, toneMapped: false }));
|
|
712
|
-
const positions2 = [1, 1, 0, -1, 1, 0, -1, -1, 0, 1, 1, 0, -1, -1, 0, 1, -1, 0];
|
|
713
|
-
const geometry2 = new BufferGeometry();
|
|
714
|
-
geometry2.setAttribute("position", new Float32BufferAttribute(positions2, 3));
|
|
715
|
-
geometry2.computeBoundingSphere();
|
|
716
|
-
this.mesh = new Mesh(geometry2, new MeshBasicMaterial({
|
|
717
|
-
color,
|
|
718
|
-
opacity,
|
|
719
|
-
transparent: true,
|
|
720
|
-
depthWrite: false,
|
|
721
|
-
toneMapped: false,
|
|
722
|
-
side: DoubleSide,
|
|
723
|
-
}));
|
|
724
|
-
this.add(this.outline);
|
|
725
|
-
this.add(this.mesh);
|
|
726
|
-
}
|
|
727
|
-
dispose() {
|
|
728
|
-
this.outline.geometry.dispose();
|
|
729
|
-
this.outline.material.dispose();
|
|
730
|
-
this.mesh.geometry.dispose();
|
|
731
|
-
this.mesh.material.dispose();
|
|
732
|
-
}
|
|
733
|
-
updateMatrixWorld(force) {
|
|
734
|
-
this.scale.set(0.5 * this.size, 0.5 * this.size, 1);
|
|
735
|
-
super.updateMatrixWorld(force);
|
|
736
|
-
}
|
|
737
|
-
getLineMaterial() {
|
|
738
|
-
return this.outline.material;
|
|
739
|
-
}
|
|
740
|
-
getMeshMaterial() {
|
|
741
|
-
return this.mesh.material;
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
const DESKTOP_SNAP_DISTANCE = 10;
|
|
746
|
-
const MOBILE_SNAP_DISTANCE = 50;
|
|
747
|
-
const _vertex = new Vector3();
|
|
748
|
-
const _start = new Vector3();
|
|
749
|
-
const _end = new Vector3();
|
|
750
|
-
const _line = new Line3();
|
|
751
|
-
const _center = new Vector3();
|
|
752
|
-
const _projection = new Vector3();
|
|
753
|
-
class Snapper {
|
|
754
|
-
constructor(camera, renderer, canvas) {
|
|
755
|
-
this.camera = camera;
|
|
756
|
-
this.renderer = renderer;
|
|
757
|
-
this.canvas = canvas;
|
|
758
|
-
this.threshold = 0.0001;
|
|
759
|
-
this.raycaster = new Raycaster();
|
|
760
|
-
this.detectRadiusInPixels = this.isMobile() ? MOBILE_SNAP_DISTANCE : DESKTOP_SNAP_DISTANCE;
|
|
761
|
-
this.edgesCache = new WeakMap();
|
|
762
|
-
}
|
|
763
|
-
isMobile() {
|
|
764
|
-
if (typeof navigator === "undefined")
|
|
765
|
-
return false;
|
|
766
|
-
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent);
|
|
767
|
-
}
|
|
768
|
-
getMousePosition(event, target) {
|
|
769
|
-
return target.set(event.clientX, event.clientY);
|
|
770
|
-
}
|
|
771
|
-
getPointerIntersects(mouse, objects, recursive = false, clip = true) {
|
|
772
|
-
const rect = this.canvas.getBoundingClientRect();
|
|
773
|
-
const x = ((mouse.x - rect.left) / rect.width) * 2 - 1;
|
|
774
|
-
const y = (-(mouse.y - rect.top) / rect.height) * 2 + 1;
|
|
775
|
-
const coords = new Vector2(x, y);
|
|
776
|
-
this.raycaster.setFromCamera(coords, this.camera);
|
|
777
|
-
this.raycaster.params = {
|
|
778
|
-
Mesh: {},
|
|
779
|
-
Line: { threshold: this.threshold },
|
|
780
|
-
Line2: { threshold: this.threshold },
|
|
781
|
-
LOD: {},
|
|
782
|
-
Points: { threshold: this.threshold },
|
|
783
|
-
Sprite: {},
|
|
784
|
-
};
|
|
785
|
-
let intersects = this.raycaster.intersectObjects(objects, recursive);
|
|
786
|
-
if (clip) {
|
|
787
|
-
const clippingPlanes = this.renderer.clippingPlanes || [];
|
|
788
|
-
clippingPlanes.forEach((plane) => {
|
|
789
|
-
intersects = intersects.filter((intersect) => plane.distanceToPoint(intersect.point) >= 0);
|
|
790
|
-
});
|
|
791
|
-
}
|
|
792
|
-
return intersects;
|
|
793
|
-
}
|
|
794
|
-
getDetectRadius(point) {
|
|
795
|
-
const camera = this.camera;
|
|
796
|
-
if (camera.isOrthographicCamera) {
|
|
797
|
-
const fieldHeight = (camera.top - camera.bottom) / camera.zoom;
|
|
798
|
-
const canvasHeight = this.canvas.height;
|
|
799
|
-
const worldUnitsPerPixel = fieldHeight / canvasHeight;
|
|
800
|
-
return this.detectRadiusInPixels * worldUnitsPerPixel;
|
|
801
|
-
}
|
|
802
|
-
if (camera.isPerspectiveCamera) {
|
|
803
|
-
const distance = camera.position.distanceTo(point);
|
|
804
|
-
const fieldHeight = 2 * Math.tan(MathUtils.degToRad(camera.fov * 0.5)) * distance;
|
|
805
|
-
const canvasHeight = this.canvas.height;
|
|
806
|
-
const worldUnitsPerPixel = fieldHeight / canvasHeight;
|
|
807
|
-
return this.detectRadiusInPixels * worldUnitsPerPixel;
|
|
808
|
-
}
|
|
809
|
-
return 0.1;
|
|
810
|
-
}
|
|
811
|
-
getSnapPoint(mouse, objects) {
|
|
812
|
-
const intersections = this.getPointerIntersects(mouse, objects);
|
|
813
|
-
if (intersections.length === 0)
|
|
814
|
-
return undefined;
|
|
815
|
-
const object = intersections[0].object;
|
|
816
|
-
const intersectionPoint = intersections[0].point;
|
|
817
|
-
const localPoint = object.worldToLocal(intersectionPoint.clone());
|
|
818
|
-
let snapPoint;
|
|
819
|
-
let snapDistance = this.getDetectRadius(intersectionPoint);
|
|
820
|
-
const geometry = object.geometry;
|
|
821
|
-
const positions = geometry.attributes.position.array;
|
|
822
|
-
for (let i = 0; i < positions.length; i += 3) {
|
|
823
|
-
_vertex.set(positions[i], positions[i + 1], positions[i + 2]);
|
|
824
|
-
const distance = _vertex.distanceTo(localPoint);
|
|
825
|
-
if (distance < snapDistance) {
|
|
826
|
-
snapDistance = distance;
|
|
827
|
-
snapPoint = _vertex.clone();
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
if (snapPoint)
|
|
831
|
-
return object.localToWorld(snapPoint);
|
|
832
|
-
let edges = this.edgesCache.get(geometry);
|
|
833
|
-
if (!edges) {
|
|
834
|
-
edges = new EdgesGeometry(geometry);
|
|
835
|
-
this.edgesCache.set(geometry, edges);
|
|
836
|
-
}
|
|
837
|
-
const edgePositions = edges.attributes.position.array;
|
|
838
|
-
for (let i = 0; i < edgePositions.length; i += 6) {
|
|
839
|
-
_start.set(edgePositions[i], edgePositions[i + 1], edgePositions[i + 2]);
|
|
840
|
-
_end.set(edgePositions[i + 3], edgePositions[i + 4], edgePositions[i + 5]);
|
|
841
|
-
_line.set(_start, _end);
|
|
842
|
-
_line.getCenter(_center);
|
|
843
|
-
const centerDistance = _center.distanceTo(localPoint);
|
|
844
|
-
if (centerDistance < snapDistance) {
|
|
845
|
-
snapDistance = centerDistance;
|
|
846
|
-
snapPoint = _center.clone();
|
|
847
|
-
continue;
|
|
848
|
-
}
|
|
849
|
-
_line.closestPointToPoint(localPoint, true, _projection);
|
|
850
|
-
const lineDistance = _projection.distanceTo(localPoint);
|
|
851
|
-
if (lineDistance < snapDistance) {
|
|
852
|
-
snapDistance = lineDistance;
|
|
853
|
-
snapPoint = _projection.clone();
|
|
854
|
-
}
|
|
855
|
-
}
|
|
856
|
-
if (snapPoint)
|
|
857
|
-
return object.localToWorld(snapPoint);
|
|
858
|
-
return intersectionPoint.clone();
|
|
859
|
-
}
|
|
860
|
-
}
|
|
861
|
-
|
|
862
737
|
class OrbitDragger {
|
|
863
738
|
constructor(viewer) {
|
|
864
739
|
this.updateControls = () => {
|
|
@@ -951,18 +826,12 @@ class OrbitDragger {
|
|
|
951
826
|
}
|
|
952
827
|
|
|
953
828
|
class CuttingPlaneDragger extends OrbitDragger {
|
|
954
|
-
constructor(viewer) {
|
|
829
|
+
constructor(viewer, normal) {
|
|
955
830
|
super(viewer);
|
|
956
|
-
this.helpers = [];
|
|
957
|
-
this.activeHelper = null;
|
|
958
831
|
this.transformChange = () => {
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
const plane = this.activeHelper.plane;
|
|
962
|
-
plane.normal.copy(new Vector3(0, 0, -1)).applyQuaternion(this.activeHelper.quaternion);
|
|
963
|
-
plane.constant = -this.activeHelper.position.dot(plane.normal);
|
|
832
|
+
this.plane.normal.copy(new Vector3(0, 0, -1)).applyQuaternion(this.planeCenter.quaternion);
|
|
833
|
+
this.plane.constant = -this.planeCenter.position.dot(this.plane.normal);
|
|
964
834
|
this.viewer.update();
|
|
965
|
-
this.changed = true;
|
|
966
835
|
};
|
|
967
836
|
this.translateDrag = (event) => {
|
|
968
837
|
this.orbit.enabled = !event.value;
|
|
@@ -973,83 +842,45 @@ class CuttingPlaneDragger extends OrbitDragger {
|
|
|
973
842
|
this.translate.enabled = !event.value;
|
|
974
843
|
};
|
|
975
844
|
this.updatePlaneSize = () => {
|
|
976
|
-
|
|
977
|
-
this.helpers.forEach((planeHelper) => (planeHelper.size = extentsSize));
|
|
845
|
+
this.planeHelper.size = this.viewer.extents.getSize(new Vector3()).length() || 1;
|
|
978
846
|
this.viewer.update();
|
|
979
847
|
};
|
|
980
848
|
this.updateTransformCamera = () => {
|
|
981
849
|
this.translate.camera = this.viewer.camera;
|
|
982
850
|
this.rotate.camera = this.viewer.camera;
|
|
983
|
-
this.snapper.camera = this.viewer.camera;
|
|
984
|
-
};
|
|
985
|
-
this.clearHelpers = () => {
|
|
986
|
-
this.setActiveHelper();
|
|
987
|
-
this.helpers.forEach((helper) => {
|
|
988
|
-
helper.removeFromParent();
|
|
989
|
-
helper.dispose();
|
|
990
|
-
});
|
|
991
|
-
this.helpers = [];
|
|
992
|
-
this.viewer.update();
|
|
993
851
|
};
|
|
994
852
|
this.onKeyDown = (event) => {
|
|
995
853
|
if (event.key === "Shift")
|
|
996
854
|
this.rotate.setRotationSnap(Math.PI / 4);
|
|
997
|
-
if (event.key === "Delete" || event.key === "Backspace")
|
|
998
|
-
this.deleteActivePlane();
|
|
999
|
-
if (event.key === "Escape" && (this.translate.dragging || this.rotate.dragging))
|
|
1000
|
-
this.reset();
|
|
1001
855
|
};
|
|
1002
856
|
this.onKeyUp = (event) => {
|
|
1003
857
|
if (event.key === "Shift")
|
|
1004
858
|
this.rotate.setRotationSnap(null);
|
|
1005
859
|
};
|
|
1006
|
-
this.onPointerDown = (event) => {
|
|
1007
|
-
if (event.button !== 0 || !event.isPrimary)
|
|
1008
|
-
return;
|
|
1009
|
-
this.snapper.getMousePosition(event, this.downPosition);
|
|
1010
|
-
this.saveState();
|
|
1011
|
-
};
|
|
1012
|
-
this.onPointerUp = (event) => {
|
|
1013
|
-
if (event.button !== 0)
|
|
1014
|
-
return;
|
|
1015
|
-
const upPosition = this.snapper.getMousePosition(event, new Vector2());
|
|
1016
|
-
if (upPosition.distanceTo(this.downPosition) !== 0)
|
|
1017
|
-
return;
|
|
1018
|
-
const intersects = this.snapper.getPointerIntersects(upPosition, this.helpers, true, false);
|
|
1019
|
-
if (intersects.length === 0)
|
|
1020
|
-
return;
|
|
1021
|
-
this.setActiveHelper(intersects[0].object.parent);
|
|
1022
|
-
};
|
|
1023
|
-
this.onPointerCancel = (event) => {
|
|
1024
|
-
this.viewer.canvas.dispatchEvent(new PointerEvent("pointerup", event));
|
|
1025
|
-
};
|
|
1026
860
|
this.onDoubleClick = (event) => {
|
|
1027
|
-
if (!this.activeHelper)
|
|
1028
|
-
return;
|
|
1029
|
-
const mousePosition = this.snapper.getMousePosition(event, new Vector2());
|
|
1030
|
-
const intersects = this.snapper.getPointerIntersects(mousePosition, [this.activeHelper], true, false);
|
|
1031
|
-
if (intersects.length === 0)
|
|
1032
|
-
return;
|
|
1033
|
-
this.activeHelper.rotateOnAxis(new Vector3(0, 1, 0), Math.PI);
|
|
1034
|
-
this.transformChange();
|
|
1035
861
|
event.stopPropagation();
|
|
862
|
+
this.planeCenter.rotateOnAxis(new Vector3(0, 1, 0), Math.PI);
|
|
863
|
+
this.transformChange();
|
|
1036
864
|
};
|
|
865
|
+
const extentsSize = viewer.extents.getSize(new Vector3()).length() || 1;
|
|
866
|
+
const extentsCenter = viewer.extents.getCenter(new Vector3());
|
|
867
|
+
const constant = -extentsCenter.dot(normal);
|
|
868
|
+
this.plane = new Plane(normal, constant);
|
|
1037
869
|
if (!viewer.renderer.clippingPlanes)
|
|
1038
870
|
viewer.renderer.clippingPlanes = [];
|
|
1039
|
-
|
|
1040
|
-
this.
|
|
1041
|
-
|
|
1042
|
-
this.
|
|
1043
|
-
this.
|
|
1044
|
-
this.
|
|
1045
|
-
this.
|
|
1046
|
-
this.quaternion0 = new Quaternion();
|
|
871
|
+
viewer.renderer.clippingPlanes.push(this.plane);
|
|
872
|
+
this.planeCenter = new Object3D();
|
|
873
|
+
this.planeCenter.position.copy(extentsCenter);
|
|
874
|
+
this.planeCenter.quaternion.setFromUnitVectors(new Vector3(0, 0, -1), normal);
|
|
875
|
+
this.viewer.helpers.add(this.planeCenter);
|
|
876
|
+
this.planeHelper = new PlaneHelper2(extentsSize);
|
|
877
|
+
this.planeCenter.add(this.planeHelper);
|
|
1047
878
|
this.translate = new TransformControls(viewer.camera, viewer.canvas);
|
|
1048
|
-
this.translate.setMode("translate");
|
|
1049
879
|
this.translate.setSpace("local");
|
|
1050
880
|
this.translate.showX = false;
|
|
1051
881
|
this.translate.showY = false;
|
|
1052
882
|
this.translate.showZ = true;
|
|
883
|
+
this.translate.attach(this.planeCenter);
|
|
1053
884
|
this.translate.addEventListener("change", this.transformChange);
|
|
1054
885
|
this.translate.addEventListener("dragging-changed", this.translateDrag);
|
|
1055
886
|
this.viewer.helpers.add(this.translate.getHelper());
|
|
@@ -1059,18 +890,14 @@ class CuttingPlaneDragger extends OrbitDragger {
|
|
|
1059
890
|
this.rotate.showX = true;
|
|
1060
891
|
this.rotate.showY = true;
|
|
1061
892
|
this.rotate.showZ = false;
|
|
893
|
+
this.rotate.attach(this.planeCenter);
|
|
1062
894
|
this.rotate.addEventListener("change", this.transformChange);
|
|
1063
895
|
this.rotate.addEventListener("dragging-changed", this.rotateDrag);
|
|
1064
896
|
this.viewer.helpers.add(this.rotate.getHelper());
|
|
1065
|
-
this.setActiveHelper(this.helpers[this.helpers.length - 1]);
|
|
1066
897
|
this.viewer.addEventListener("explode", this.updatePlaneSize);
|
|
1067
898
|
this.viewer.addEventListener("show", this.updatePlaneSize);
|
|
1068
899
|
this.viewer.addEventListener("showall", this.updatePlaneSize);
|
|
1069
900
|
this.viewer.addEventListener("changecameramode", this.updateTransformCamera);
|
|
1070
|
-
this.viewer.addEventListener("clearslices", this.clearHelpers);
|
|
1071
|
-
this.viewer.canvas.addEventListener("pointerdown", this.onPointerDown, true);
|
|
1072
|
-
this.viewer.canvas.addEventListener("pointerup", this.onPointerUp, true);
|
|
1073
|
-
this.viewer.canvas.addEventListener("pointercancel", this.onPointerCancel, true);
|
|
1074
901
|
this.viewer.canvas.addEventListener("dblclick", this.onDoubleClick, true);
|
|
1075
902
|
window.addEventListener("keydown", this.onKeyDown);
|
|
1076
903
|
window.addEventListener("keyup", this.onKeyUp);
|
|
@@ -1081,10 +908,6 @@ class CuttingPlaneDragger extends OrbitDragger {
|
|
|
1081
908
|
this.viewer.removeEventListener("show", this.updatePlaneSize);
|
|
1082
909
|
this.viewer.removeEventListener("showall", this.updatePlaneSize);
|
|
1083
910
|
this.viewer.removeEventListener("changecameramode", this.updateTransformCamera);
|
|
1084
|
-
this.viewer.removeEventListener("clearslices", this.clearHelpers);
|
|
1085
|
-
this.viewer.canvas.removeEventListener("pointerdown", this.onPointerDown, true);
|
|
1086
|
-
this.viewer.canvas.removeEventListener("pointerup", this.onPointerUp, true);
|
|
1087
|
-
this.viewer.canvas.removeEventListener("pointercancel", this.onPointerCancel, true);
|
|
1088
911
|
this.viewer.canvas.removeEventListener("dblclick", this.onDoubleClick, true);
|
|
1089
912
|
window.removeEventListener("keydown", this.onKeyDown);
|
|
1090
913
|
window.removeEventListener("keyup", this.onKeyUp);
|
|
@@ -1098,108 +921,28 @@ class CuttingPlaneDragger extends OrbitDragger {
|
|
|
1098
921
|
this.rotate.getHelper().removeFromParent();
|
|
1099
922
|
this.rotate.detach();
|
|
1100
923
|
this.rotate.dispose();
|
|
1101
|
-
this.
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
});
|
|
1105
|
-
this.helpers = [];
|
|
1106
|
-
this.activeHelper = null;
|
|
924
|
+
this.planeHelper.removeFromParent();
|
|
925
|
+
this.planeHelper.dispose();
|
|
926
|
+
this.planeCenter.removeFromParent();
|
|
1107
927
|
super.dispose();
|
|
1108
928
|
}
|
|
1109
|
-
addHelper(plane) {
|
|
1110
|
-
const extentsSize = this.viewer.extents.getSize(new Vector3()).length() || 1;
|
|
1111
|
-
const extentsCenter = this.viewer.extents.getCenter(new Vector3());
|
|
1112
|
-
const helper = new PlaneHelper2(extentsSize);
|
|
1113
|
-
helper.plane = plane;
|
|
1114
|
-
helper.position.copy(plane.projectPoint(extentsCenter, new Vector3()));
|
|
1115
|
-
helper.quaternion.setFromUnitVectors(new Vector3(0, 0, -1), plane.normal);
|
|
1116
|
-
this.helpers.push(helper);
|
|
1117
|
-
this.viewer.helpers.add(helper);
|
|
1118
|
-
return helper;
|
|
1119
|
-
}
|
|
1120
|
-
setActiveHelper(helper) {
|
|
1121
|
-
if (helper === this.activeHelper)
|
|
1122
|
-
return;
|
|
1123
|
-
if (this.activeHelper) {
|
|
1124
|
-
this.activeHelper.getLineMaterial().color.setHex(0xf0f0f0);
|
|
1125
|
-
this.activeHelper.getMeshMaterial().opacity = 0.15;
|
|
1126
|
-
this.translate.detach();
|
|
1127
|
-
this.rotate.detach();
|
|
1128
|
-
}
|
|
1129
|
-
this.activeHelper = helper;
|
|
1130
|
-
if (this.activeHelper) {
|
|
1131
|
-
this.activeHelper.getLineMaterial().color.setHex(0xd0d0d0);
|
|
1132
|
-
this.activeHelper.getMeshMaterial().opacity = 0.3;
|
|
1133
|
-
this.translate.attach(this.activeHelper);
|
|
1134
|
-
this.rotate.attach(this.activeHelper);
|
|
1135
|
-
}
|
|
1136
|
-
this.viewer.update();
|
|
1137
|
-
}
|
|
1138
|
-
saveState() {
|
|
1139
|
-
if (!this.activeHelper)
|
|
1140
|
-
return;
|
|
1141
|
-
this.position0.copy(this.activeHelper.position);
|
|
1142
|
-
this.quaternion0.copy(this.activeHelper.quaternion);
|
|
1143
|
-
}
|
|
1144
|
-
reset() {
|
|
1145
|
-
if (!this.activeHelper)
|
|
1146
|
-
return;
|
|
1147
|
-
this.translate.dragging = false;
|
|
1148
|
-
this.rotate.dragging = false;
|
|
1149
|
-
this.orbit.state = STATE.NONE;
|
|
1150
|
-
this.activeHelper.position.copy(this.position0);
|
|
1151
|
-
this.activeHelper.quaternion.copy(this.quaternion0);
|
|
1152
|
-
this.transformChange();
|
|
1153
|
-
}
|
|
1154
|
-
addPlane(normal) {
|
|
1155
|
-
const extentsCenter = this.viewer.extents.getCenter(new Vector3());
|
|
1156
|
-
const constant = -extentsCenter.dot(normal);
|
|
1157
|
-
const plane = new Plane(normal, constant);
|
|
1158
|
-
this.clippingPlanes.push(plane);
|
|
1159
|
-
const helper = this.addHelper(plane);
|
|
1160
|
-
this.setActiveHelper(helper);
|
|
1161
|
-
}
|
|
1162
|
-
addPlaneX() {
|
|
1163
|
-
this.addPlane(new Vector3(-1, 0, 0));
|
|
1164
|
-
}
|
|
1165
|
-
addPlaneY() {
|
|
1166
|
-
this.addPlane(new Vector3(0, -1, 0));
|
|
1167
|
-
}
|
|
1168
|
-
addPlaneZ() {
|
|
1169
|
-
this.addPlane(new Vector3(0, 0, -1));
|
|
1170
|
-
}
|
|
1171
|
-
deleteActivePlane() {
|
|
1172
|
-
if (!this.activeHelper)
|
|
1173
|
-
return;
|
|
1174
|
-
const helper = this.activeHelper;
|
|
1175
|
-
const index = this.clippingPlanes.indexOf(helper.plane);
|
|
1176
|
-
if (index !== -1)
|
|
1177
|
-
this.clippingPlanes.splice(index, 1);
|
|
1178
|
-
this.helpers = this.helpers.filter((x) => x !== helper);
|
|
1179
|
-
helper.removeFromParent();
|
|
1180
|
-
helper.dispose();
|
|
1181
|
-
this.setActiveHelper(this.helpers[this.helpers.length - 1]);
|
|
1182
|
-
}
|
|
1183
929
|
}
|
|
1184
930
|
|
|
1185
931
|
class CuttingPlaneXAxisDragger extends CuttingPlaneDragger {
|
|
1186
932
|
constructor(viewer) {
|
|
1187
|
-
super(viewer);
|
|
1188
|
-
this.addPlaneX();
|
|
933
|
+
super(viewer, new Vector3(-1, 0, 0));
|
|
1189
934
|
}
|
|
1190
935
|
}
|
|
1191
936
|
|
|
1192
937
|
class CuttingPlaneYAxisDragger extends CuttingPlaneDragger {
|
|
1193
938
|
constructor(viewer) {
|
|
1194
|
-
super(viewer);
|
|
1195
|
-
this.addPlaneY();
|
|
939
|
+
super(viewer, new Vector3(0, -1, 0));
|
|
1196
940
|
}
|
|
1197
941
|
}
|
|
1198
942
|
|
|
1199
943
|
class CuttingPlaneZAxisDragger extends CuttingPlaneDragger {
|
|
1200
944
|
constructor(viewer) {
|
|
1201
|
-
super(viewer);
|
|
1202
|
-
this.addPlaneZ();
|
|
945
|
+
super(viewer, new Vector3(0, 0, -1));
|
|
1203
946
|
}
|
|
1204
947
|
}
|
|
1205
948
|
|
|
@@ -1276,6 +1019,120 @@ function formatDistance(distance, units, precision = 2) {
|
|
|
1276
1019
|
}
|
|
1277
1020
|
}
|
|
1278
1021
|
|
|
1022
|
+
const DESKTOP_SNAP_DISTANCE = 10;
|
|
1023
|
+
const MOBILE_SNAP_DISTANCE = 50;
|
|
1024
|
+
const _vertex = new Vector3();
|
|
1025
|
+
const _start = new Vector3();
|
|
1026
|
+
const _end = new Vector3();
|
|
1027
|
+
const _line = new Line3();
|
|
1028
|
+
const _center = new Vector3();
|
|
1029
|
+
const _projection = new Vector3();
|
|
1030
|
+
class Snapper {
|
|
1031
|
+
constructor(camera, renderer, canvas) {
|
|
1032
|
+
this.camera = camera;
|
|
1033
|
+
this.renderer = renderer;
|
|
1034
|
+
this.canvas = canvas;
|
|
1035
|
+
this.threshold = 0.0001;
|
|
1036
|
+
this.raycaster = new Raycaster();
|
|
1037
|
+
this.detectRadiusInPixels = this.isMobile() ? MOBILE_SNAP_DISTANCE : DESKTOP_SNAP_DISTANCE;
|
|
1038
|
+
this.edgesCache = new WeakMap();
|
|
1039
|
+
}
|
|
1040
|
+
isMobile() {
|
|
1041
|
+
if (typeof navigator === "undefined")
|
|
1042
|
+
return false;
|
|
1043
|
+
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent);
|
|
1044
|
+
}
|
|
1045
|
+
getMousePosition(event, target) {
|
|
1046
|
+
return target.set(event.clientX, event.clientY);
|
|
1047
|
+
}
|
|
1048
|
+
getPointerIntersects(mouse, objects) {
|
|
1049
|
+
const rect = this.canvas.getBoundingClientRect();
|
|
1050
|
+
const x = ((mouse.x - rect.left) / rect.width) * 2 - 1;
|
|
1051
|
+
const y = (-(mouse.y - rect.top) / rect.height) * 2 + 1;
|
|
1052
|
+
const coords = new Vector2(x, y);
|
|
1053
|
+
this.raycaster.setFromCamera(coords, this.camera);
|
|
1054
|
+
this.raycaster.params = {
|
|
1055
|
+
Mesh: {},
|
|
1056
|
+
Line: { threshold: this.threshold },
|
|
1057
|
+
Line2: { threshold: this.threshold },
|
|
1058
|
+
LOD: {},
|
|
1059
|
+
Points: { threshold: this.threshold },
|
|
1060
|
+
Sprite: {},
|
|
1061
|
+
};
|
|
1062
|
+
let intersects = this.raycaster.intersectObjects(objects, false);
|
|
1063
|
+
(this.renderer.clippingPlanes || []).forEach((plane) => {
|
|
1064
|
+
intersects = intersects.filter((intersect) => plane.distanceToPoint(intersect.point) >= 0);
|
|
1065
|
+
});
|
|
1066
|
+
return intersects;
|
|
1067
|
+
}
|
|
1068
|
+
getDetectRadius(point) {
|
|
1069
|
+
const camera = this.camera;
|
|
1070
|
+
if (camera.isOrthographicCamera) {
|
|
1071
|
+
const fieldHeight = (camera.top - camera.bottom) / camera.zoom;
|
|
1072
|
+
const canvasHeight = this.canvas.height;
|
|
1073
|
+
const worldUnitsPerPixel = fieldHeight / canvasHeight;
|
|
1074
|
+
return this.detectRadiusInPixels * worldUnitsPerPixel;
|
|
1075
|
+
}
|
|
1076
|
+
if (camera.isPerspectiveCamera) {
|
|
1077
|
+
const distance = camera.position.distanceTo(point);
|
|
1078
|
+
const fieldHeight = 2 * Math.tan(MathUtils.degToRad(camera.fov * 0.5)) * distance;
|
|
1079
|
+
const canvasHeight = this.canvas.height;
|
|
1080
|
+
const worldUnitsPerPixel = fieldHeight / canvasHeight;
|
|
1081
|
+
return this.detectRadiusInPixels * worldUnitsPerPixel;
|
|
1082
|
+
}
|
|
1083
|
+
return 0.1;
|
|
1084
|
+
}
|
|
1085
|
+
getSnapPoint(mouse, objects) {
|
|
1086
|
+
const intersections = this.getPointerIntersects(mouse, objects);
|
|
1087
|
+
if (intersections.length === 0)
|
|
1088
|
+
return undefined;
|
|
1089
|
+
const object = intersections[0].object;
|
|
1090
|
+
const intersectionPoint = intersections[0].point;
|
|
1091
|
+
const localPoint = object.worldToLocal(intersectionPoint.clone());
|
|
1092
|
+
let snapPoint;
|
|
1093
|
+
let snapDistance = this.getDetectRadius(intersectionPoint);
|
|
1094
|
+
const geometry = object.geometry;
|
|
1095
|
+
const positions = geometry.attributes.position.array;
|
|
1096
|
+
for (let i = 0; i < positions.length; i += 3) {
|
|
1097
|
+
_vertex.set(positions[i], positions[i + 1], positions[i + 2]);
|
|
1098
|
+
const distance = _vertex.distanceTo(localPoint);
|
|
1099
|
+
if (distance < snapDistance) {
|
|
1100
|
+
snapDistance = distance;
|
|
1101
|
+
snapPoint = _vertex.clone();
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
if (snapPoint)
|
|
1105
|
+
return object.localToWorld(snapPoint);
|
|
1106
|
+
let edges = this.edgesCache.get(geometry);
|
|
1107
|
+
if (!edges) {
|
|
1108
|
+
edges = new EdgesGeometry(geometry);
|
|
1109
|
+
this.edgesCache.set(geometry, edges);
|
|
1110
|
+
}
|
|
1111
|
+
const edgePositions = edges.attributes.position.array;
|
|
1112
|
+
for (let i = 0; i < edgePositions.length; i += 6) {
|
|
1113
|
+
_start.set(edgePositions[i], edgePositions[i + 1], edgePositions[i + 2]);
|
|
1114
|
+
_end.set(edgePositions[i + 3], edgePositions[i + 4], edgePositions[i + 5]);
|
|
1115
|
+
_line.set(_start, _end);
|
|
1116
|
+
_line.getCenter(_center);
|
|
1117
|
+
const centerDistance = _center.distanceTo(localPoint);
|
|
1118
|
+
if (centerDistance < snapDistance) {
|
|
1119
|
+
snapDistance = centerDistance;
|
|
1120
|
+
snapPoint = _center.clone();
|
|
1121
|
+
continue;
|
|
1122
|
+
}
|
|
1123
|
+
_line.closestPointToPoint(localPoint, true, _projection);
|
|
1124
|
+
const lineDistance = _projection.distanceTo(localPoint);
|
|
1125
|
+
if (lineDistance < snapDistance) {
|
|
1126
|
+
snapDistance = lineDistance;
|
|
1127
|
+
snapPoint = _projection.clone();
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
if (snapPoint)
|
|
1131
|
+
return object.localToWorld(snapPoint);
|
|
1132
|
+
return intersectionPoint.clone();
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1279
1136
|
const _downPoint = new Vector2();
|
|
1280
1137
|
class MeasureLineDragger extends OrbitDragger {
|
|
1281
1138
|
constructor(viewer) {
|
|
@@ -1687,12 +1544,6 @@ class WalkControls extends Controls {
|
|
|
1687
1544
|
this.movementSpeed = 0.1;
|
|
1688
1545
|
this.multiplier = 3;
|
|
1689
1546
|
this.groundFollowingSkippedFrames = 0;
|
|
1690
|
-
this.GROUND_BOX_HALF_SIZE = 20;
|
|
1691
|
-
this.GROUND_BOX_REFRESH_THRESHOLD = 0.3;
|
|
1692
|
-
this._groundObjectBoxes = new Map();
|
|
1693
|
-
this._activeGroundObjects = [];
|
|
1694
|
-
this._groundBox = new Box3();
|
|
1695
|
-
this._groundBoxCenter = new Vector3();
|
|
1696
1547
|
this.moveWheel = 0;
|
|
1697
1548
|
this.mouseDragOn = false;
|
|
1698
1549
|
this._up = new Vector3();
|
|
@@ -1759,20 +1610,11 @@ class WalkControls extends Controls {
|
|
|
1759
1610
|
}
|
|
1760
1611
|
};
|
|
1761
1612
|
this.onKeyUp = (event) => {
|
|
1762
|
-
if (this.moveKeys.delete(event.code))
|
|
1763
|
-
if (this.moveKeys.size === 0) {
|
|
1764
|
-
this._rebuildGroundBox(this.object.position);
|
|
1765
|
-
}
|
|
1613
|
+
if (this.moveKeys.delete(event.code))
|
|
1766
1614
|
this.update();
|
|
1767
|
-
}
|
|
1768
1615
|
};
|
|
1769
1616
|
this.camera = camera;
|
|
1770
1617
|
this.groundObjects = groundObjects;
|
|
1771
|
-
for (const obj of groundObjects) {
|
|
1772
|
-
this._groundObjectBoxes.set(obj, new Box3().setFromObject(obj));
|
|
1773
|
-
}
|
|
1774
|
-
const pos = this.object.position;
|
|
1775
|
-
this._rebuildGroundBox(pos);
|
|
1776
1618
|
this.raycaster = new Raycaster();
|
|
1777
1619
|
this.raycaster.near = 0;
|
|
1778
1620
|
this.raycaster.far = this.EYE_HEIGHT + this.FAILING_DISTANCE;
|
|
@@ -1807,29 +1649,10 @@ class WalkControls extends Controls {
|
|
|
1807
1649
|
window.removeEventListener("keyup", this.onKeyUp);
|
|
1808
1650
|
super.dispose();
|
|
1809
1651
|
}
|
|
1810
|
-
_rebuildGroundBox(center) {
|
|
1811
|
-
const h = this.GROUND_BOX_HALF_SIZE;
|
|
1812
|
-
this._groundBoxCenter.copy(center);
|
|
1813
|
-
this._groundBox.set(new Vector3(center.x - h, center.y - h * 4, center.z - h), new Vector3(center.x + h, center.y + h * 4, center.z + h));
|
|
1814
|
-
this._activeGroundObjects = this.groundObjects.filter((obj) => {
|
|
1815
|
-
const objectBox = this._groundObjectBoxes.get(obj);
|
|
1816
|
-
return objectBox !== undefined && this._groundBox.intersectsBox(objectBox);
|
|
1817
|
-
});
|
|
1818
|
-
}
|
|
1819
|
-
_needsGroundBoxRebuild(pos) {
|
|
1820
|
-
if (this._activeGroundObjects.length === 0 && this.groundObjects.length > 0)
|
|
1821
|
-
return true;
|
|
1822
|
-
const threshold = this.GROUND_BOX_HALF_SIZE * this.GROUND_BOX_REFRESH_THRESHOLD;
|
|
1823
|
-
return (Math.abs(pos.x - this._groundBoxCenter.x) > threshold || Math.abs(pos.z - this._groundBoxCenter.z) > threshold);
|
|
1824
|
-
}
|
|
1825
1652
|
updateGroundFollowing() {
|
|
1826
|
-
const pos = this.object.position;
|
|
1827
|
-
if (this._needsGroundBoxRebuild(pos)) {
|
|
1828
|
-
this._rebuildGroundBox(pos);
|
|
1829
|
-
}
|
|
1830
1653
|
this._up.copy(this.camera.up).negate();
|
|
1831
|
-
this.raycaster.set(
|
|
1832
|
-
const intersects = this.raycaster.intersectObjects(this.
|
|
1654
|
+
this.raycaster.set(this.object.position, this._up);
|
|
1655
|
+
const intersects = this.raycaster.intersectObjects(this.groundObjects, false);
|
|
1833
1656
|
if (intersects.length > 0) {
|
|
1834
1657
|
const groundY = intersects[0].point.y;
|
|
1835
1658
|
const targetY = groundY + this.EYE_HEIGHT;
|
|
@@ -2381,7 +2204,6 @@ draggers.registerDragger("Pan", (viewer) => new PanDragger(viewer));
|
|
|
2381
2204
|
draggers.registerDragger("Orbit", (viewer) => new OrbitDragger(viewer));
|
|
2382
2205
|
draggers.registerDragger("Zoom", (viewer) => new ZoomDragger(viewer));
|
|
2383
2206
|
draggers.registerDragger("MeasureLine", (viewer) => new MeasureLineDragger(viewer));
|
|
2384
|
-
draggers.registerDragger("CuttingPlane", (viewer) => new CuttingPlaneDragger(viewer));
|
|
2385
2207
|
draggers.registerDragger("CuttingPlaneXAxis", (viewer) => new CuttingPlaneXAxisDragger(viewer));
|
|
2386
2208
|
draggers.registerDragger("CuttingPlaneYAxis", (viewer) => new CuttingPlaneYAxisDragger(viewer));
|
|
2387
2209
|
draggers.registerDragger("CuttingPlaneZAxis", (viewer) => new CuttingPlaneZAxisDragger(viewer));
|
|
@@ -3277,7 +3099,7 @@ class SelectionComponent {
|
|
|
3277
3099
|
this.getMousePosition(event, this.downPosition);
|
|
3278
3100
|
};
|
|
3279
3101
|
this.onPointerUp = (event) => {
|
|
3280
|
-
if (!event.isPrimary
|
|
3102
|
+
if (!event.isPrimary)
|
|
3281
3103
|
return;
|
|
3282
3104
|
const upPosition = this.getMousePosition(event, new Vector2());
|
|
3283
3105
|
if (upPosition.distanceTo(this.downPosition) !== 0)
|
|
@@ -4591,81 +4413,6 @@ class DynamicGltfLoader {
|
|
|
4591
4413
|
this.mergedObjectMap = new Map();
|
|
4592
4414
|
this.mergedGeometryVisibility = new Map();
|
|
4593
4415
|
this._webglInfoCache = null;
|
|
4594
|
-
this.transformTextureSize = 1024;
|
|
4595
|
-
this.transformTexture = this.createDummyTexture();
|
|
4596
|
-
this.transformData = null;
|
|
4597
|
-
this.identityTransformData = null;
|
|
4598
|
-
this.visibilityMaterials = new Set();
|
|
4599
|
-
}
|
|
4600
|
-
createDummyTexture() {
|
|
4601
|
-
const data = new Float32Array(16);
|
|
4602
|
-
const identity = new Matrix4();
|
|
4603
|
-
identity.toArray(data);
|
|
4604
|
-
const dummyData = new Float32Array(16);
|
|
4605
|
-
identity.toArray(dummyData);
|
|
4606
|
-
const dummyTexture = new DataTexture(dummyData, 4, 1, RGBAFormat, FloatType);
|
|
4607
|
-
dummyTexture.minFilter = NearestFilter;
|
|
4608
|
-
dummyTexture.magFilter = NearestFilter;
|
|
4609
|
-
dummyTexture.needsUpdate = true;
|
|
4610
|
-
return dummyTexture;
|
|
4611
|
-
}
|
|
4612
|
-
initTransformTexture() {
|
|
4613
|
-
if (this.transformTexture) {
|
|
4614
|
-
this.transformTexture.dispose();
|
|
4615
|
-
}
|
|
4616
|
-
const maxInstanceCount = this.maxObjectId + 1;
|
|
4617
|
-
let size = Math.sqrt(maxInstanceCount * 4);
|
|
4618
|
-
size = Math.ceil(size / 4) * 4;
|
|
4619
|
-
size = Math.max(size, 4);
|
|
4620
|
-
this.transformTextureSize = size;
|
|
4621
|
-
const arraySize = size * size * 4;
|
|
4622
|
-
this.transformData = new Float32Array(arraySize);
|
|
4623
|
-
this.identityTransformData = new Float32Array(arraySize);
|
|
4624
|
-
for (let i = 0; i <= this.maxObjectId; i++) {
|
|
4625
|
-
const base = i * 16;
|
|
4626
|
-
if (base + 15 < arraySize) {
|
|
4627
|
-
this.identityTransformData[base + 0] = 1;
|
|
4628
|
-
this.identityTransformData[base + 5] = 1;
|
|
4629
|
-
this.identityTransformData[base + 10] = 1;
|
|
4630
|
-
this.identityTransformData[base + 15] = 1;
|
|
4631
|
-
}
|
|
4632
|
-
}
|
|
4633
|
-
this._resetTransformData(false);
|
|
4634
|
-
this.transformTexture = new DataTexture(this.transformData, size, size, RGBAFormat, FloatType);
|
|
4635
|
-
this.transformTexture.needsUpdate = true;
|
|
4636
|
-
this.transformTexture.generateMipmaps = false;
|
|
4637
|
-
console.log(`Initialized transform texture: ${size}x${size} for ${maxInstanceCount} objects`);
|
|
4638
|
-
this.updateMaterialUniforms();
|
|
4639
|
-
this.visibilityMaterials.forEach((material) => {
|
|
4640
|
-
material.needsUpdate = true;
|
|
4641
|
-
});
|
|
4642
|
-
}
|
|
4643
|
-
_resetTransformData(updateTexture = true) {
|
|
4644
|
-
if (!this.transformData || !this.identityTransformData) return;
|
|
4645
|
-
this.transformData.set(this.identityTransformData);
|
|
4646
|
-
if (updateTexture) {
|
|
4647
|
-
this.updateTransformTexture();
|
|
4648
|
-
}
|
|
4649
|
-
}
|
|
4650
|
-
updateMaterialUniforms() {
|
|
4651
|
-
if (
|
|
4652
|
-
this._lastTransformTexture === this.transformTexture &&
|
|
4653
|
-
this._lastTransformTextureSize === this.transformTextureSize
|
|
4654
|
-
) {
|
|
4655
|
-
return;
|
|
4656
|
-
}
|
|
4657
|
-
this._lastTransformTexture = this.transformTexture;
|
|
4658
|
-
this._lastTransformTextureSize = this.transformTextureSize;
|
|
4659
|
-
this.visibilityMaterials.forEach((material) => {
|
|
4660
|
-
if (material.userData && material.userData.visibilityUniforms) {
|
|
4661
|
-
material.userData.visibilityUniforms.transformTexture.value = this.transformTexture;
|
|
4662
|
-
material.userData.visibilityUniforms.transformTextureSize.value = this.transformTextureSize;
|
|
4663
|
-
}
|
|
4664
|
-
});
|
|
4665
|
-
}
|
|
4666
|
-
updateTransformTexture() {
|
|
4667
|
-
if (!this.transformTexture) return;
|
|
4668
|
-
this.transformTexture.needsUpdate = true;
|
|
4669
4416
|
}
|
|
4670
4417
|
setVisibleEdges(visible) {
|
|
4671
4418
|
this.visibleEdges = visible;
|
|
@@ -5555,82 +5302,36 @@ class DynamicGltfLoader {
|
|
|
5555
5302
|
}
|
|
5556
5303
|
}
|
|
5557
5304
|
createVisibilityMaterial(material) {
|
|
5558
|
-
this.visibilityMaterials.add(material);
|
|
5559
|
-
const uniforms = {
|
|
5560
|
-
transformTexture: { value: this.transformTexture },
|
|
5561
|
-
transformTextureSize: { value: this.transformTextureSize },
|
|
5562
|
-
};
|
|
5563
|
-
material.userData.visibilityUniforms = uniforms;
|
|
5564
5305
|
material.onBeforeCompile = (shader) => {
|
|
5565
|
-
shader.uniforms.transformTexture = uniforms.transformTexture;
|
|
5566
|
-
shader.uniforms.transformTextureSize = uniforms.transformTextureSize;
|
|
5567
5306
|
shader.vertexShader = shader.vertexShader.replace(
|
|
5568
5307
|
"#include <common>",
|
|
5569
5308
|
`
|
|
5570
5309
|
#include <common>
|
|
5571
|
-
|
|
5572
5310
|
attribute float visibility;
|
|
5573
|
-
attribute float objectId;
|
|
5574
5311
|
varying float vVisibility;
|
|
5575
|
-
uniform highp sampler2D transformTexture;
|
|
5576
|
-
uniform float transformTextureSize;
|
|
5577
|
-
|
|
5578
|
-
mat4 getTransformMatrix(float instanceId) {
|
|
5579
|
-
int size = int(transformTextureSize);
|
|
5580
|
-
int index = int(instanceId) * 4;
|
|
5581
|
-
|
|
5582
|
-
int x0 = index % size;
|
|
5583
|
-
int y0 = index / size;
|
|
5584
|
-
|
|
5585
|
-
vec4 row0 = texelFetch(transformTexture, ivec2(x0, y0), 0);
|
|
5586
|
-
vec4 row1 = texelFetch(transformTexture, ivec2(x0 + 1, y0), 0);
|
|
5587
|
-
vec4 row2 = texelFetch(transformTexture, ivec2(x0 + 2, y0), 0);
|
|
5588
|
-
vec4 row3 = texelFetch(transformTexture, ivec2(x0 + 3, y0), 0);
|
|
5589
|
-
|
|
5590
|
-
return mat4(row0, row1, row2, row3);
|
|
5591
|
-
}
|
|
5592
5312
|
`
|
|
5593
5313
|
);
|
|
5594
|
-
shader.
|
|
5595
|
-
"
|
|
5314
|
+
shader.fragmentShader = shader.fragmentShader.replace(
|
|
5315
|
+
"#include <common>",
|
|
5596
5316
|
`
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
vVisibility = visibility;
|
|
5317
|
+
#include <common>
|
|
5318
|
+
varying float vVisibility;
|
|
5600
5319
|
`
|
|
5601
5320
|
);
|
|
5602
|
-
if (shader.vertexShader.includes("#include <beginnormal_vertex>")) {
|
|
5603
|
-
shader.vertexShader = shader.vertexShader.replace(
|
|
5604
|
-
"#include <beginnormal_vertex>",
|
|
5605
|
-
`
|
|
5606
|
-
vec3 objectNormal = vec3( normal );
|
|
5607
|
-
mat3 bm = mat3( batchingMatrix );
|
|
5608
|
-
objectNormal = bm * objectNormal;
|
|
5609
|
-
`
|
|
5610
|
-
);
|
|
5611
|
-
}
|
|
5612
5321
|
shader.vertexShader = shader.vertexShader.replace(
|
|
5613
|
-
"
|
|
5322
|
+
"void main() {",
|
|
5614
5323
|
`
|
|
5615
|
-
|
|
5616
|
-
|
|
5324
|
+
void main() {
|
|
5325
|
+
vVisibility = visibility;
|
|
5617
5326
|
`
|
|
5618
5327
|
);
|
|
5619
|
-
shader.fragmentShader = shader.fragmentShader
|
|
5620
|
-
|
|
5621
|
-
"#include <common>",
|
|
5622
|
-
`
|
|
5623
|
-
#include <common>
|
|
5624
|
-
varying float vVisibility;
|
|
5328
|
+
shader.fragmentShader = shader.fragmentShader.replace(
|
|
5329
|
+
"void main() {",
|
|
5625
5330
|
`
|
|
5626
|
-
)
|
|
5627
|
-
.replace(
|
|
5628
|
-
"void main() {",
|
|
5629
|
-
`
|
|
5630
5331
|
void main() {
|
|
5631
5332
|
if (vVisibility < 0.5) discard;
|
|
5632
5333
|
`
|
|
5633
|
-
|
|
5334
|
+
);
|
|
5634
5335
|
};
|
|
5635
5336
|
material.needsUpdate = true;
|
|
5636
5337
|
return material;
|
|
@@ -5745,8 +5446,6 @@ class DynamicGltfLoader {
|
|
|
5745
5446
|
this.objectIdToIndex.clear();
|
|
5746
5447
|
this.maxObjectId = 0;
|
|
5747
5448
|
this.objectVisibility = new Float32Array();
|
|
5748
|
-
this.meshToNodeMap = null;
|
|
5749
|
-
this.visibilityMaterials.clear();
|
|
5750
5449
|
}
|
|
5751
5450
|
setStructureTransform(structureId, matrix) {
|
|
5752
5451
|
const rootGroup = this.structureRoots.get(structureId);
|
|
@@ -5862,15 +5561,12 @@ class DynamicGltfLoader {
|
|
|
5862
5561
|
});
|
|
5863
5562
|
this.originalObjects.clear();
|
|
5864
5563
|
this.originalObjectsToSelection.clear();
|
|
5865
|
-
this.objectIdToIndex.clear();
|
|
5866
|
-
this.maxObjectId = 0;
|
|
5867
5564
|
const structureGroups = new Map();
|
|
5868
5565
|
this.dispatchEvent("optimizationprogress", {
|
|
5869
5566
|
phase: "collecting",
|
|
5870
5567
|
progress: 5,
|
|
5871
5568
|
message: "Collecting scene objects...",
|
|
5872
5569
|
});
|
|
5873
|
-
let totalObjectsToMerge = 0;
|
|
5874
5570
|
this.scene.traverse((object) => {
|
|
5875
5571
|
if (object.userData.structureId) {
|
|
5876
5572
|
const structureId = object.userData.structureId;
|
|
@@ -5888,32 +5584,17 @@ class DynamicGltfLoader {
|
|
|
5888
5584
|
});
|
|
5889
5585
|
}
|
|
5890
5586
|
const group = structureGroups.get(structureId);
|
|
5891
|
-
let added = false;
|
|
5892
5587
|
if (object instanceof Mesh) {
|
|
5893
5588
|
this.addToMaterialGroup(object, group.mapMeshes, group.meshes);
|
|
5894
|
-
added = true;
|
|
5895
5589
|
} else if (object instanceof LineSegments) {
|
|
5896
5590
|
this.addToMaterialGroup(object, group.mapLineSegments, group.lineSegments);
|
|
5897
|
-
added = true;
|
|
5898
5591
|
} else if (object instanceof Line) {
|
|
5899
5592
|
this.addToMaterialGroup(object, group.mapLines, group.lines);
|
|
5900
|
-
added = true;
|
|
5901
5593
|
} else if (object instanceof Points) {
|
|
5902
5594
|
this.addToMaterialGroup(object, group.mapPoints, group.points);
|
|
5903
|
-
added = true;
|
|
5904
|
-
}
|
|
5905
|
-
if (added) {
|
|
5906
|
-
totalObjectsToMerge++;
|
|
5907
5595
|
}
|
|
5908
5596
|
}
|
|
5909
5597
|
});
|
|
5910
|
-
if (totalObjectsToMerge > 0) {
|
|
5911
|
-
console.log(`Pre-allocating transform texture for ${totalObjectsToMerge} objects`);
|
|
5912
|
-
this.maxObjectId = totalObjectsToMerge;
|
|
5913
|
-
this.initTransformTexture();
|
|
5914
|
-
this.initializeObjectVisibility();
|
|
5915
|
-
this.maxObjectId = 0;
|
|
5916
|
-
}
|
|
5917
5598
|
let processedGroups = 0;
|
|
5918
5599
|
const totalGroups = structureGroups.size;
|
|
5919
5600
|
this.dispatchEvent("optimizationprogress", {
|
|
@@ -5958,6 +5639,7 @@ class DynamicGltfLoader {
|
|
|
5958
5639
|
this.originalObjectsToSelection.add(obj);
|
|
5959
5640
|
}
|
|
5960
5641
|
});
|
|
5642
|
+
this.initializeObjectVisibility();
|
|
5961
5643
|
console.log(`Optimization complete. Total objects: ${this.maxObjectId}`);
|
|
5962
5644
|
this.dispatchEvent("optimizationprogress", {
|
|
5963
5645
|
phase: "complete",
|
|
@@ -6026,7 +5708,6 @@ class DynamicGltfLoader {
|
|
|
6026
5708
|
}
|
|
6027
5709
|
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
6028
5710
|
const mergedMesh = new Mesh(mergedGeometry, visibilityMaterial);
|
|
6029
|
-
mergedMesh.frustumCulled = false;
|
|
6030
5711
|
mergedMesh.userData.isOptimized = true;
|
|
6031
5712
|
rootGroup.add(mergedMesh);
|
|
6032
5713
|
this.mergedMesh.add(mergedMesh);
|
|
@@ -6143,7 +5824,6 @@ class DynamicGltfLoader {
|
|
|
6143
5824
|
geometry.setAttribute("visibility", new BufferAttribute(visibilityArray, 1));
|
|
6144
5825
|
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
6145
5826
|
const mergedLine = new LineSegments(geometry, visibilityMaterial);
|
|
6146
|
-
mergedLine.frustumCulled = false;
|
|
6147
5827
|
mergedLine.userData.isEdge = isEdge;
|
|
6148
5828
|
mergedLine.userData.isOptimized = true;
|
|
6149
5829
|
const mergedObjects = [mergedLine];
|
|
@@ -6232,7 +5912,6 @@ class DynamicGltfLoader {
|
|
|
6232
5912
|
mergedGeometry.setAttribute("visibility", new BufferAttribute(visibilityArray, 1));
|
|
6233
5913
|
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
6234
5914
|
const mergedLine = new LineSegments(mergedGeometry, visibilityMaterial);
|
|
6235
|
-
mergedLine.frustumCulled = false;
|
|
6236
5915
|
mergedLine.userData.isEdge = isEdge;
|
|
6237
5916
|
mergedLine.userData.isOptimized = true;
|
|
6238
5917
|
if (this.useVAO) {
|
|
@@ -6302,27 +5981,7 @@ class DynamicGltfLoader {
|
|
|
6302
5981
|
const mergedObjects = [];
|
|
6303
5982
|
if (geometries.length > 0) {
|
|
6304
5983
|
const mergedGeometry = mergeGeometries(geometries, false);
|
|
6305
|
-
const
|
|
6306
|
-
const objectIds = new Float32Array(totalVertices);
|
|
6307
|
-
let vertexOffset = 0;
|
|
6308
|
-
group.objects.forEach((points) => {
|
|
6309
|
-
const handle = points.userData.handle;
|
|
6310
|
-
if (!this.objectIdToIndex.has(handle)) {
|
|
6311
|
-
this.objectIdToIndex.set(handle, this.maxObjectId++);
|
|
6312
|
-
}
|
|
6313
|
-
const objectId = this.objectIdToIndex.get(handle);
|
|
6314
|
-
const count = points.geometry.attributes.position.count;
|
|
6315
|
-
for (let i = 0; i < count; i++) {
|
|
6316
|
-
objectIds[vertexOffset++] = objectId;
|
|
6317
|
-
}
|
|
6318
|
-
});
|
|
6319
|
-
mergedGeometry.setAttribute("objectId", new BufferAttribute(objectIds, 1));
|
|
6320
|
-
const visibilityArray = new Float32Array(totalVertices);
|
|
6321
|
-
visibilityArray.fill(1.0);
|
|
6322
|
-
mergedGeometry.setAttribute("visibility", new BufferAttribute(visibilityArray, 1));
|
|
6323
|
-
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
6324
|
-
const mergedPoints = new Points(mergedGeometry, visibilityMaterial);
|
|
6325
|
-
mergedPoints.frustumCulled = false;
|
|
5984
|
+
const mergedPoints = new Points(mergedGeometry, group.material);
|
|
6326
5985
|
mergedPoints.userData.isOptimized = true;
|
|
6327
5986
|
if (this.useVAO) {
|
|
6328
5987
|
this.createVAO(mergedPoints);
|
|
@@ -6391,33 +6050,13 @@ class DynamicGltfLoader {
|
|
|
6391
6050
|
geometriesWithIndex.push(clonedGeometry);
|
|
6392
6051
|
});
|
|
6393
6052
|
const finalGeometry = mergeGeometries(geometriesWithIndex, false);
|
|
6394
|
-
const totalVertices = finalGeometry.attributes.position.count;
|
|
6395
|
-
const objectIds = new Float32Array(totalVertices);
|
|
6396
|
-
let vertexOffset = 0;
|
|
6397
|
-
lineSegmentsArray.forEach((segment) => {
|
|
6398
|
-
const handle = segment.userData.handle;
|
|
6399
|
-
if (!this.objectIdToIndex.has(handle)) {
|
|
6400
|
-
this.objectIdToIndex.set(handle, this.maxObjectId++);
|
|
6401
|
-
}
|
|
6402
|
-
const objectId = this.objectIdToIndex.get(handle);
|
|
6403
|
-
const count = segment.geometry.attributes.position.count;
|
|
6404
|
-
for (let i = 0; i < count; i++) {
|
|
6405
|
-
objectIds[vertexOffset++] = objectId;
|
|
6406
|
-
}
|
|
6407
|
-
});
|
|
6408
|
-
finalGeometry.setAttribute("objectId", new BufferAttribute(objectIds, 1));
|
|
6409
|
-
const visibilityArray = new Float32Array(totalVertices);
|
|
6410
|
-
visibilityArray.fill(1.0);
|
|
6411
|
-
finalGeometry.setAttribute("visibility", new BufferAttribute(visibilityArray, 1));
|
|
6412
6053
|
const material = new LineBasicMaterial({
|
|
6413
6054
|
vertexColors: true,
|
|
6414
6055
|
});
|
|
6415
|
-
const visibilityMaterial = this.createVisibilityMaterial(material);
|
|
6416
6056
|
if (this.useVAO) {
|
|
6417
6057
|
this.createVAO(finalGeometry);
|
|
6418
6058
|
}
|
|
6419
|
-
const mergedLine = new LineSegments(finalGeometry,
|
|
6420
|
-
mergedLine.frustumCulled = false;
|
|
6059
|
+
const mergedLine = new LineSegments(finalGeometry, material);
|
|
6421
6060
|
mergedLine.userData.structureId = structureId;
|
|
6422
6061
|
mergedLine.userData.isOptimized = true;
|
|
6423
6062
|
rootGroup.add(mergedLine);
|
|
@@ -6536,50 +6175,18 @@ class DynamicGltfLoader {
|
|
|
6536
6175
|
console.warn("No merged objects to transform");
|
|
6537
6176
|
return;
|
|
6538
6177
|
}
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
|
|
6178
|
+
this.objectTransforms = new Map(objectTransformMap);
|
|
6179
|
+
for (const mesh of this.mergedMesh) {
|
|
6180
|
+
this._applyTransformToMergedObject(mesh);
|
|
6542
6181
|
}
|
|
6543
|
-
this.
|
|
6544
|
-
|
|
6545
|
-
|
|
6546
|
-
const
|
|
6547
|
-
|
|
6548
|
-
|
|
6549
|
-
|
|
6550
|
-
|
|
6551
|
-
if (!userData) continue;
|
|
6552
|
-
const handle = userData.handle;
|
|
6553
|
-
if (handle === undefined) continue;
|
|
6554
|
-
const objectId = objectIdToIndex.get(handle);
|
|
6555
|
-
if (objectId !== undefined) {
|
|
6556
|
-
transformData.set(matrix.elements, objectId * 16);
|
|
6557
|
-
textureNeedsUpdate = true;
|
|
6558
|
-
}
|
|
6559
|
-
}
|
|
6560
|
-
} else {
|
|
6561
|
-
const len = objectTransformMap.length;
|
|
6562
|
-
for (let i = 0; i < len; i++) {
|
|
6563
|
-
const pair = objectTransformMap[i];
|
|
6564
|
-
const userData = pair[0].userData;
|
|
6565
|
-
if (!userData) continue;
|
|
6566
|
-
const handle = userData.handle;
|
|
6567
|
-
if (handle === undefined) continue;
|
|
6568
|
-
const objectId = objectIdToIndex.get(handle);
|
|
6569
|
-
if (objectId !== undefined) {
|
|
6570
|
-
transformData.set(pair[1].elements, objectId * 16);
|
|
6571
|
-
textureNeedsUpdate = true;
|
|
6572
|
-
}
|
|
6573
|
-
}
|
|
6574
|
-
}
|
|
6575
|
-
if (textureNeedsUpdate) {
|
|
6576
|
-
this.updateTransformTexture();
|
|
6577
|
-
if (
|
|
6578
|
-
this._lastTransformTexture !== this.transformTexture ||
|
|
6579
|
-
this._lastTransformTextureSize !== this.transformTextureSize
|
|
6580
|
-
) {
|
|
6581
|
-
this.updateMaterialUniforms();
|
|
6582
|
-
}
|
|
6182
|
+
for (const line of this.mergedLines) {
|
|
6183
|
+
this._applyTransformToMergedObject(line);
|
|
6184
|
+
}
|
|
6185
|
+
for (const lineSegment of this.mergedLineSegments) {
|
|
6186
|
+
this._applyTransformToMergedObject(lineSegment);
|
|
6187
|
+
}
|
|
6188
|
+
for (const point of this.mergedPoints) {
|
|
6189
|
+
this._applyTransformToMergedObject(point);
|
|
6583
6190
|
}
|
|
6584
6191
|
}
|
|
6585
6192
|
createExplodeTransforms(objects = null, explodeCenter = null, explodeFactor = 1.5) {
|
|
@@ -6596,66 +6203,21 @@ class DynamicGltfLoader {
|
|
|
6596
6203
|
? objects
|
|
6597
6204
|
: Array.from(objects)
|
|
6598
6205
|
: Array.from(this.originalObjects);
|
|
6599
|
-
const structureInverseMatrices = new Map();
|
|
6600
|
-
if (!this.meshToNodeMap) {
|
|
6601
|
-
this.meshToNodeMap = new Map();
|
|
6602
|
-
for (const node of this.nodes.values()) {
|
|
6603
|
-
if (node.object) {
|
|
6604
|
-
this.meshToNodeMap.set(node.object, node);
|
|
6605
|
-
}
|
|
6606
|
-
}
|
|
6607
|
-
}
|
|
6608
6206
|
for (const obj of objectsArray) {
|
|
6609
6207
|
if (!obj.geometry || !obj.geometry.attributes.position) continue;
|
|
6610
|
-
|
|
6611
|
-
|
|
6612
|
-
|
|
6613
|
-
|
|
6614
|
-
|
|
6615
|
-
|
|
6616
|
-
|
|
6617
|
-
|
|
6618
|
-
|
|
6619
|
-
if (!center) {
|
|
6620
|
-
if (!obj.geometry.boundingBox) obj.geometry.computeBoundingBox();
|
|
6621
|
-
const box = obj.geometry.boundingBox.clone();
|
|
6622
|
-
box.applyMatrix4(obj.matrixWorld);
|
|
6623
|
-
center = new Vector3();
|
|
6624
|
-
box.getCenter(center);
|
|
6625
|
-
}
|
|
6626
|
-
const explodeVector = center.sub(explodeCenter);
|
|
6627
|
-
obj.userData.explodeVector = explodeVector;
|
|
6628
|
-
}
|
|
6629
|
-
const explodeVector = obj.userData.explodeVector;
|
|
6630
|
-
const distance = explodeVector.length();
|
|
6208
|
+
const boundingBox = new Box3().setFromBufferAttribute(obj.geometry.attributes.position);
|
|
6209
|
+
if (obj.matrixWorld) {
|
|
6210
|
+
boundingBox.applyMatrix4(obj.matrixWorld);
|
|
6211
|
+
}
|
|
6212
|
+
if (boundingBox.isEmpty()) continue;
|
|
6213
|
+
const objectCenter = new Vector3();
|
|
6214
|
+
boundingBox.getCenter(objectCenter);
|
|
6215
|
+
const direction = objectCenter.clone().sub(explodeCenter);
|
|
6216
|
+
const distance = direction.length();
|
|
6631
6217
|
if (distance > 0) {
|
|
6632
|
-
|
|
6633
|
-
const
|
|
6634
|
-
|
|
6635
|
-
const structureId = obj.userData.structureId;
|
|
6636
|
-
let inverseMatrix = structureInverseMatrices.get(structureId);
|
|
6637
|
-
if (!inverseMatrix) {
|
|
6638
|
-
const rootGroup = this.structureRoots.get(structureId);
|
|
6639
|
-
if (rootGroup) {
|
|
6640
|
-
if (!rootGroup.userData.inverseWorldMatrix) {
|
|
6641
|
-
rootGroup.userData.inverseWorldMatrix = new Matrix4().copy(rootGroup.matrixWorld).invert();
|
|
6642
|
-
}
|
|
6643
|
-
inverseMatrix = rootGroup.userData.inverseWorldMatrix;
|
|
6644
|
-
structureInverseMatrices.set(structureId, inverseMatrix);
|
|
6645
|
-
}
|
|
6646
|
-
}
|
|
6647
|
-
if (inverseMatrix) {
|
|
6648
|
-
const zero = new Vector3(0, 0, 0).applyMatrix4(inverseMatrix);
|
|
6649
|
-
const vec = offset.clone().applyMatrix4(inverseMatrix).sub(zero);
|
|
6650
|
-
localOffset.copy(vec);
|
|
6651
|
-
}
|
|
6652
|
-
}
|
|
6653
|
-
let matrix = obj.userData.explodeMatrix;
|
|
6654
|
-
if (!matrix) {
|
|
6655
|
-
matrix = new Matrix4();
|
|
6656
|
-
obj.userData.explodeMatrix = matrix;
|
|
6657
|
-
}
|
|
6658
|
-
matrix.makeTranslation(localOffset.x, localOffset.y, localOffset.z);
|
|
6218
|
+
direction.normalize();
|
|
6219
|
+
const offset = direction.multiplyScalar(distance * (explodeFactor - 1.0));
|
|
6220
|
+
const matrix = new Matrix4().makeTranslation(offset.x, offset.y, offset.z);
|
|
6659
6221
|
transformMap.set(obj, matrix);
|
|
6660
6222
|
}
|
|
6661
6223
|
}
|
|
@@ -6663,11 +6225,116 @@ class DynamicGltfLoader {
|
|
|
6663
6225
|
}
|
|
6664
6226
|
clearTransforms() {
|
|
6665
6227
|
this.objectTransforms.clear();
|
|
6666
|
-
this.
|
|
6228
|
+
for (const mesh of this.mergedMesh) {
|
|
6229
|
+
this._restoreOriginalGeometry(mesh);
|
|
6230
|
+
}
|
|
6231
|
+
for (const line of this.mergedLines) {
|
|
6232
|
+
this._restoreOriginalGeometry(line);
|
|
6233
|
+
}
|
|
6234
|
+
for (const lineSegment of this.mergedLineSegments) {
|
|
6235
|
+
this._restoreOriginalGeometry(lineSegment);
|
|
6236
|
+
}
|
|
6237
|
+
for (const point of this.mergedPoints) {
|
|
6238
|
+
this._restoreOriginalGeometry(point);
|
|
6239
|
+
}
|
|
6667
6240
|
}
|
|
6668
6241
|
clearHandleTransforms() {
|
|
6669
6242
|
this.clearTransforms();
|
|
6670
6243
|
}
|
|
6244
|
+
_applyTransformToMergedObject(mergedObject) {
|
|
6245
|
+
const objectData = this.mergedObjectMap.get(mergedObject.uuid);
|
|
6246
|
+
if (!objectData || !objectData.objectMapping) return;
|
|
6247
|
+
const geometry = mergedObject.geometry;
|
|
6248
|
+
if (!geometry || !geometry.attributes.position) return;
|
|
6249
|
+
const positionAttr = geometry.attributes.position;
|
|
6250
|
+
const positions = positionAttr.array;
|
|
6251
|
+
if (!this.transformedGeometries.has(mergedObject.uuid)) {
|
|
6252
|
+
this.transformedGeometries.set(mergedObject.uuid, new Float32Array(positions));
|
|
6253
|
+
}
|
|
6254
|
+
const originalPositions = this.transformedGeometries.get(mergedObject.uuid);
|
|
6255
|
+
const tempVector = new Vector3();
|
|
6256
|
+
for (const [originalMesh, mappingData] of objectData.objectMapping) {
|
|
6257
|
+
const transform = this.objectTransforms.get(originalMesh);
|
|
6258
|
+
if (!transform) {
|
|
6259
|
+
const startIdx = mappingData.startVertexIndex * 3;
|
|
6260
|
+
const endIdx = (mappingData.startVertexIndex + mappingData.vertexCount) * 3;
|
|
6261
|
+
for (let i = startIdx; i < endIdx; i++) {
|
|
6262
|
+
positions[i] = originalPositions[i];
|
|
6263
|
+
}
|
|
6264
|
+
continue;
|
|
6265
|
+
}
|
|
6266
|
+
const startVertex = mappingData.startVertexIndex;
|
|
6267
|
+
const vertexCount = mappingData.vertexCount;
|
|
6268
|
+
for (let i = 0; i < vertexCount; i++) {
|
|
6269
|
+
const idx = (startVertex + i) * 3;
|
|
6270
|
+
tempVector.set(originalPositions[idx], originalPositions[idx + 1], originalPositions[idx + 2]);
|
|
6271
|
+
tempVector.applyMatrix4(transform);
|
|
6272
|
+
positions[idx] = tempVector.x;
|
|
6273
|
+
positions[idx + 1] = tempVector.y;
|
|
6274
|
+
positions[idx + 2] = tempVector.z;
|
|
6275
|
+
}
|
|
6276
|
+
}
|
|
6277
|
+
if (geometry.attributes.normal) {
|
|
6278
|
+
this._updateNormalsForTransform(geometry, objectData, originalPositions);
|
|
6279
|
+
}
|
|
6280
|
+
positionAttr.needsUpdate = true;
|
|
6281
|
+
geometry.computeBoundingSphere();
|
|
6282
|
+
geometry.computeBoundingBox();
|
|
6283
|
+
}
|
|
6284
|
+
_updateNormalsForTransform(geometry, objectData, originalPositions) {
|
|
6285
|
+
const normalAttr = geometry.attributes.normal;
|
|
6286
|
+
if (!normalAttr) return;
|
|
6287
|
+
const normals = normalAttr.array;
|
|
6288
|
+
const tempVector = new Vector3();
|
|
6289
|
+
const normalMatrix = new Matrix4();
|
|
6290
|
+
const normalsKey = `${geometry.uuid}_normals`;
|
|
6291
|
+
if (!this.transformedGeometries.has(normalsKey)) {
|
|
6292
|
+
this.transformedGeometries.set(normalsKey, new Float32Array(normals));
|
|
6293
|
+
}
|
|
6294
|
+
const originalNormals = this.transformedGeometries.get(normalsKey);
|
|
6295
|
+
for (const [originalMesh, mappingData] of objectData.objectMapping) {
|
|
6296
|
+
const transform = this.objectTransforms.get(originalMesh);
|
|
6297
|
+
if (!transform) {
|
|
6298
|
+
const startIdx = mappingData.startVertexIndex * 3;
|
|
6299
|
+
const endIdx = (mappingData.startVertexIndex + mappingData.vertexCount) * 3;
|
|
6300
|
+
for (let i = startIdx; i < endIdx; i++) {
|
|
6301
|
+
normals[i] = originalNormals[i];
|
|
6302
|
+
}
|
|
6303
|
+
continue;
|
|
6304
|
+
}
|
|
6305
|
+
normalMatrix.copy(transform).invert().transpose();
|
|
6306
|
+
const startVertex = mappingData.startVertexIndex;
|
|
6307
|
+
const vertexCount = mappingData.vertexCount;
|
|
6308
|
+
for (let i = 0; i < vertexCount; i++) {
|
|
6309
|
+
const idx = (startVertex + i) * 3;
|
|
6310
|
+
tempVector.set(originalNormals[idx], originalNormals[idx + 1], originalNormals[idx + 2]);
|
|
6311
|
+
tempVector.applyMatrix4(normalMatrix).normalize();
|
|
6312
|
+
normals[idx] = tempVector.x;
|
|
6313
|
+
normals[idx + 1] = tempVector.y;
|
|
6314
|
+
normals[idx + 2] = tempVector.z;
|
|
6315
|
+
}
|
|
6316
|
+
}
|
|
6317
|
+
normalAttr.needsUpdate = true;
|
|
6318
|
+
}
|
|
6319
|
+
_restoreOriginalGeometry(mergedObject) {
|
|
6320
|
+
const geometry = mergedObject.geometry;
|
|
6321
|
+
if (!geometry || !geometry.attributes.position) return;
|
|
6322
|
+
const originalPositions = this.transformedGeometries.get(mergedObject.uuid);
|
|
6323
|
+
if (originalPositions) {
|
|
6324
|
+
const positions = geometry.attributes.position.array;
|
|
6325
|
+
positions.set(originalPositions);
|
|
6326
|
+
geometry.attributes.position.needsUpdate = true;
|
|
6327
|
+
}
|
|
6328
|
+
const normalsKey = `${geometry.uuid}_normals`;
|
|
6329
|
+
const originalNormals = this.transformedGeometries.get(normalsKey);
|
|
6330
|
+
if (originalNormals && geometry.attributes.normal) {
|
|
6331
|
+
const normals = geometry.attributes.normal.array;
|
|
6332
|
+
normals.set(originalNormals);
|
|
6333
|
+
geometry.attributes.normal.needsUpdate = true;
|
|
6334
|
+
}
|
|
6335
|
+
geometry.computeBoundingSphere();
|
|
6336
|
+
geometry.computeBoundingBox();
|
|
6337
|
+
}
|
|
6671
6338
|
syncHiddenObjects() {
|
|
6672
6339
|
if (this.mergedObjectMap.size === 0) {
|
|
6673
6340
|
console.log("No merged objects to sync");
|