@inweb/viewer-three 27.2.4 → 27.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +2 -2
- package/README.md +1 -1
- package/dist/extensions/components/AxesHelperComponent.js +2 -2
- package/dist/extensions/components/AxesHelperComponent.js.map +1 -1
- package/dist/extensions/components/AxesHelperComponent.min.js +2 -2
- package/dist/extensions/components/AxesHelperComponent.module.js +2 -2
- package/dist/extensions/components/AxesHelperComponent.module.js.map +1 -1
- package/dist/extensions/components/ExtentsHelperComponent.js +2 -2
- package/dist/extensions/components/ExtentsHelperComponent.js.map +1 -1
- package/dist/extensions/components/ExtentsHelperComponent.min.js +2 -2
- package/dist/extensions/components/ExtentsHelperComponent.module.js +2 -2
- package/dist/extensions/components/ExtentsHelperComponent.module.js.map +1 -1
- package/dist/extensions/components/GridHelperComponent.js +2 -2
- package/dist/extensions/components/GridHelperComponent.js.map +1 -1
- package/dist/extensions/components/GridHelperComponent.min.js +2 -2
- package/dist/extensions/components/GridHelperComponent.module.js +2 -2
- package/dist/extensions/components/GridHelperComponent.module.js.map +1 -1
- package/dist/extensions/components/InfoPanelComponent.js +2 -2
- package/dist/extensions/components/InfoPanelComponent.js.map +1 -1
- package/dist/extensions/components/InfoPanelComponent.min.js +2 -2
- package/dist/extensions/components/InfoPanelComponent.module.js +2 -2
- package/dist/extensions/components/InfoPanelComponent.module.js.map +1 -1
- package/dist/extensions/components/LightHelperComponent.js +2 -2
- package/dist/extensions/components/LightHelperComponent.js.map +1 -1
- package/dist/extensions/components/LightHelperComponent.min.js +2 -2
- package/dist/extensions/components/LightHelperComponent.module.js +2 -2
- package/dist/extensions/components/LightHelperComponent.module.js.map +1 -1
- package/dist/extensions/components/RoomEnvironmentComponent.js +2 -2
- package/dist/extensions/components/RoomEnvironmentComponent.js.map +1 -1
- package/dist/extensions/components/RoomEnvironmentComponent.min.js +2 -2
- package/dist/extensions/components/RoomEnvironmentComponent.module.js +2 -2
- package/dist/extensions/components/RoomEnvironmentComponent.module.js.map +1 -1
- package/dist/extensions/components/StatsPanelComponent.js +2 -2
- package/dist/extensions/components/StatsPanelComponent.js.map +1 -1
- package/dist/extensions/components/StatsPanelComponent.min.js +2 -2
- package/dist/extensions/components/StatsPanelComponent.module.js +2 -2
- package/dist/extensions/components/StatsPanelComponent.module.js.map +1 -1
- package/dist/extensions/loaders/GLTFCloudLoader.js +2 -2
- package/dist/extensions/loaders/GLTFCloudLoader.js.map +1 -1
- package/dist/extensions/loaders/GLTFCloudLoader.min.js +2 -2
- package/dist/extensions/loaders/GLTFCloudLoader.module.js +2 -2
- package/dist/extensions/loaders/GLTFCloudLoader.module.js.map +1 -1
- package/dist/extensions/loaders/GLTFFileLoader.js +2 -2
- package/dist/extensions/loaders/GLTFFileLoader.js.map +1 -1
- package/dist/extensions/loaders/GLTFFileLoader.min.js +2 -2
- package/dist/extensions/loaders/GLTFFileLoader.module.js +2 -2
- package/dist/extensions/loaders/GLTFFileLoader.module.js.map +1 -1
- package/dist/extensions/loaders/IFCXLoader.js +2 -2
- package/dist/extensions/loaders/IFCXLoader.js.map +1 -1
- package/dist/extensions/loaders/IFCXLoader.min.js +2 -2
- package/dist/extensions/loaders/IFCXLoader.module.js +2 -2
- package/dist/extensions/loaders/IFCXLoader.module.js.map +1 -1
- package/dist/extensions/loaders/PotreeLoader.js +2 -2
- package/dist/extensions/loaders/PotreeLoader.js.map +1 -1
- package/dist/extensions/loaders/PotreeLoader.min.js +2 -2
- package/dist/extensions/loaders/PotreeLoader.module.js +2 -2
- package/dist/extensions/loaders/PotreeLoader.module.js.map +1 -1
- package/dist/viewer-three.js +755 -362
- package/dist/viewer-three.js.map +1 -1
- package/dist/viewer-three.min.js +5 -5
- package/dist/viewer-three.module.js +756 -363
- package/dist/viewer-three.module.js.map +1 -1
- package/extensions/components/AxesHelperComponent.ts +2 -2
- package/extensions/components/ExtentsHelperComponent.ts +2 -2
- package/extensions/components/GridHelperComponent.ts +2 -2
- package/extensions/components/InfoPanelComponent.ts +2 -2
- package/extensions/components/LightHelperComponent.ts +2 -2
- package/extensions/components/RoomEnvironmentComponent.ts +2 -2
- package/extensions/components/StatsPanelComponent.ts +2 -2
- package/extensions/loaders/GLTFCloudLoader.ts +2 -2
- package/extensions/loaders/GLTFFileLoader.ts +2 -2
- package/extensions/loaders/IFCX/IFCXCloudLoader.ts +2 -2
- package/extensions/loaders/IFCX/IFCXFileLoader.ts +2 -2
- package/extensions/loaders/IFCX/IFCXLoader.ts +2 -2
- package/extensions/loaders/IFCX/index.ts +2 -2
- package/extensions/loaders/IFCX/render.js +2 -2
- package/extensions/loaders/Potree/PotreeFileLoader.ts +2 -2
- package/extensions/loaders/Potree/PotreeModelImpl.ts +2 -2
- package/extensions/loaders/Potree/index.ts +2 -2
- package/lib/Viewer/controls/WalkControls.d.ts +8 -0
- package/lib/Viewer/draggers/CuttingPlaneDragger.d.ts +23 -5
- package/lib/Viewer/helpers/PlaneHelper2.d.ts +8 -4
- package/lib/Viewer/measurement/Snapper.d.ts +1 -1
- package/package.json +5 -5
- package/src/Viewer/Viewer.ts +2 -2
- package/src/Viewer/commands/ApplyModelTransform.ts +2 -2
- package/src/Viewer/commands/ClearMarkup.ts +2 -2
- package/src/Viewer/commands/ClearSelected.ts +2 -2
- package/src/Viewer/commands/ClearSlices.ts +2 -2
- package/src/Viewer/commands/Explode.ts +2 -2
- package/src/Viewer/commands/GetDefaultViewPositions.ts +2 -2
- package/src/Viewer/commands/GetModels.ts +2 -2
- package/src/Viewer/commands/GetSelected.ts +2 -2
- package/src/Viewer/commands/GetSelected2.ts +2 -2
- package/src/Viewer/commands/GetSnapshot.ts +2 -2
- package/src/Viewer/commands/HideSelected.ts +2 -2
- package/src/Viewer/commands/IsolateSelected.ts +2 -2
- package/src/Viewer/commands/RegenerateAll.ts +2 -2
- package/src/Viewer/commands/ResetView.ts +2 -2
- package/src/Viewer/commands/SelectModel.ts +2 -2
- package/src/Viewer/commands/SetActiveDragger.ts +2 -2
- package/src/Viewer/commands/SetDefaultViewPosition.ts +2 -2
- package/src/Viewer/commands/SetMarkupColor.ts +2 -2
- package/src/Viewer/commands/SetSelected.ts +2 -2
- package/src/Viewer/commands/SetSelected2.ts +2 -2
- package/src/Viewer/commands/ShowAll.ts +2 -2
- package/src/Viewer/commands/ZoomTo.ts +2 -2
- package/src/Viewer/commands/ZoomToExtents.ts +2 -2
- package/src/Viewer/commands/ZoomToObjects.ts +2 -2
- package/src/Viewer/commands/ZoomToSelected.ts +2 -2
- package/src/Viewer/commands/index.ts +2 -2
- package/src/Viewer/components/BackgroundComponent.ts +2 -2
- package/src/Viewer/components/CameraComponent.ts +2 -2
- package/src/Viewer/components/CanvasRemoveComponent.ts +2 -2
- package/src/Viewer/components/CanvasResizeComponent.ts +2 -2
- package/src/Viewer/components/ExtentsComponent.ts +2 -2
- package/src/Viewer/components/HighlighterComponent.ts +2 -2
- package/src/Viewer/components/HighlighterUtils.ts +2 -2
- package/src/Viewer/components/InfoComponent.ts +2 -2
- package/src/Viewer/components/LightComponent.ts +2 -2
- package/src/Viewer/components/RenderLoopComponent.ts +2 -2
- package/src/Viewer/components/ResetComponent.ts +2 -2
- package/src/Viewer/components/SelectionComponent.ts +3 -3
- package/src/Viewer/components/ViewPositionComponent.ts +2 -2
- package/src/Viewer/components/WCSHelperComponent.ts +2 -2
- package/src/Viewer/components/index.ts +2 -2
- package/src/Viewer/controls/FlyControls.ts +2 -2
- package/src/Viewer/controls/JoyStickControls.ts +2 -2
- package/src/Viewer/controls/WalkControls.ts +52 -6
- package/src/Viewer/draggers/CuttingPlaneDragger.ts +193 -33
- package/src/Viewer/draggers/CuttingPlaneXAxis.ts +4 -5
- package/src/Viewer/draggers/CuttingPlaneYAxis.ts +4 -5
- package/src/Viewer/draggers/CuttingPlaneZAxis.ts +4 -5
- package/src/Viewer/draggers/FlyDragger.ts +2 -2
- package/src/Viewer/draggers/MeasureLineDragger.ts +2 -2
- package/src/Viewer/draggers/OrbitDragger.ts +2 -2
- package/src/Viewer/draggers/PanDragger.ts +2 -2
- package/src/Viewer/draggers/WalkDragger.ts +2 -2
- package/src/Viewer/draggers/ZoomDragger.ts +2 -2
- package/src/Viewer/draggers/index.ts +4 -2
- package/src/Viewer/helpers/PlaneHelper2.ts +32 -19
- package/src/Viewer/loaders/DynamicGltfLoader/DynamicGltfLoader.js +495 -182
- package/src/Viewer/loaders/DynamicGltfLoader/DynamicModelImpl.ts +46 -35
- package/src/Viewer/loaders/GLTFBinaryParser.ts +2 -2
- package/src/Viewer/loaders/GLTFCloudDynamicLoader.ts +2 -2
- package/src/Viewer/loaders/GLTFFileDynamicLoader.ts +2 -2
- package/src/Viewer/loaders/GLTFLoadingManager.ts +2 -2
- package/src/Viewer/loaders/JSONStreamParser.ts +2 -2
- package/src/Viewer/loaders/RangesLoader.ts +2 -2
- package/src/Viewer/loaders/index.ts +2 -2
- package/src/Viewer/measurement/Snapper.ts +15 -7
- package/src/Viewer/measurement/UnitConverter.ts +2 -2
- package/src/Viewer/measurement/UnitFormatter.ts +2 -2
- package/src/Viewer/models/IModelImpl.ts +2 -2
- package/src/Viewer/models/ModelImpl.ts +15 -12
- package/src/Viewer/postprocessing/SSAARenderPass.js +2 -2
- package/src/Viewer/scenes/Helpers.ts +2 -2
- package/src/index-umd.ts +2 -2
- package/src/index.ts +2 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
-
// Copyright (C) 2002-
|
|
2
|
+
// Copyright (C) 2002-2026, Open Design Alliance (the "Alliance").
|
|
3
3
|
// All rights reserved.
|
|
4
4
|
//
|
|
5
5
|
// This software and its documentation and related materials are owned by
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
//
|
|
15
15
|
// This application incorporates Open Design Alliance software pursuant to a
|
|
16
16
|
// license agreement with Open Design Alliance.
|
|
17
|
-
// Open Design Alliance Copyright (C) 2002-
|
|
17
|
+
// Open Design Alliance Copyright (C) 2002-2026 by Open Design Alliance.
|
|
18
18
|
// All rights reserved.
|
|
19
19
|
//
|
|
20
20
|
// By use of this software, its documentation or related materials, you
|
|
@@ -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 { 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, PointsMaterial, DataTexture, FloatType, NearestFilter, 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,41 +41,6 @@ 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
|
-
|
|
79
44
|
const _changeEvent = { type: "change" };
|
|
80
45
|
const _startEvent = { type: "start" };
|
|
81
46
|
const _endEvent = { type: "end" };
|
|
@@ -734,6 +699,166 @@ class OrbitControls extends EventDispatcher {
|
|
|
734
699
|
}
|
|
735
700
|
}
|
|
736
701
|
|
|
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
|
+
|
|
737
862
|
class OrbitDragger {
|
|
738
863
|
constructor(viewer) {
|
|
739
864
|
this.updateControls = () => {
|
|
@@ -826,12 +951,18 @@ class OrbitDragger {
|
|
|
826
951
|
}
|
|
827
952
|
|
|
828
953
|
class CuttingPlaneDragger extends OrbitDragger {
|
|
829
|
-
constructor(viewer
|
|
954
|
+
constructor(viewer) {
|
|
830
955
|
super(viewer);
|
|
956
|
+
this.helpers = [];
|
|
957
|
+
this.activeHelper = null;
|
|
831
958
|
this.transformChange = () => {
|
|
832
|
-
|
|
833
|
-
|
|
959
|
+
if (!this.activeHelper)
|
|
960
|
+
return;
|
|
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);
|
|
834
964
|
this.viewer.update();
|
|
965
|
+
this.changed = true;
|
|
835
966
|
};
|
|
836
967
|
this.translateDrag = (event) => {
|
|
837
968
|
this.orbit.enabled = !event.value;
|
|
@@ -842,45 +973,83 @@ class CuttingPlaneDragger extends OrbitDragger {
|
|
|
842
973
|
this.translate.enabled = !event.value;
|
|
843
974
|
};
|
|
844
975
|
this.updatePlaneSize = () => {
|
|
845
|
-
|
|
976
|
+
const extentsSize = this.viewer.extents.getSize(new Vector3()).length() || 1;
|
|
977
|
+
this.helpers.forEach((planeHelper) => (planeHelper.size = extentsSize));
|
|
846
978
|
this.viewer.update();
|
|
847
979
|
};
|
|
848
980
|
this.updateTransformCamera = () => {
|
|
849
981
|
this.translate.camera = this.viewer.camera;
|
|
850
982
|
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();
|
|
851
993
|
};
|
|
852
994
|
this.onKeyDown = (event) => {
|
|
853
995
|
if (event.key === "Shift")
|
|
854
996
|
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();
|
|
855
1001
|
};
|
|
856
1002
|
this.onKeyUp = (event) => {
|
|
857
1003
|
if (event.key === "Shift")
|
|
858
1004
|
this.rotate.setRotationSnap(null);
|
|
859
1005
|
};
|
|
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
|
+
};
|
|
860
1026
|
this.onDoubleClick = (event) => {
|
|
861
|
-
|
|
862
|
-
|
|
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);
|
|
863
1034
|
this.transformChange();
|
|
1035
|
+
event.stopPropagation();
|
|
864
1036
|
};
|
|
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);
|
|
869
1037
|
if (!viewer.renderer.clippingPlanes)
|
|
870
1038
|
viewer.renderer.clippingPlanes = [];
|
|
871
|
-
viewer.renderer.clippingPlanes
|
|
872
|
-
this.
|
|
873
|
-
|
|
874
|
-
this.
|
|
875
|
-
this.
|
|
876
|
-
this.
|
|
877
|
-
this.
|
|
1039
|
+
this.clippingPlanes = viewer.renderer.clippingPlanes;
|
|
1040
|
+
this.clippingPlanes.forEach((plane) => this.addHelper(plane));
|
|
1041
|
+
const extentsSize = viewer.extents.getSize(new Vector3()).length() || 1;
|
|
1042
|
+
this.snapper = new Snapper(viewer.camera, viewer.renderer, viewer.canvas);
|
|
1043
|
+
this.snapper.threshold = extentsSize / 10000;
|
|
1044
|
+
this.downPosition = new Vector2();
|
|
1045
|
+
this.position0 = new Vector3();
|
|
1046
|
+
this.quaternion0 = new Quaternion();
|
|
878
1047
|
this.translate = new TransformControls(viewer.camera, viewer.canvas);
|
|
1048
|
+
this.translate.setMode("translate");
|
|
879
1049
|
this.translate.setSpace("local");
|
|
880
1050
|
this.translate.showX = false;
|
|
881
1051
|
this.translate.showY = false;
|
|
882
1052
|
this.translate.showZ = true;
|
|
883
|
-
this.translate.attach(this.planeCenter);
|
|
884
1053
|
this.translate.addEventListener("change", this.transformChange);
|
|
885
1054
|
this.translate.addEventListener("dragging-changed", this.translateDrag);
|
|
886
1055
|
this.viewer.helpers.add(this.translate.getHelper());
|
|
@@ -890,14 +1059,18 @@ class CuttingPlaneDragger extends OrbitDragger {
|
|
|
890
1059
|
this.rotate.showX = true;
|
|
891
1060
|
this.rotate.showY = true;
|
|
892
1061
|
this.rotate.showZ = false;
|
|
893
|
-
this.rotate.attach(this.planeCenter);
|
|
894
1062
|
this.rotate.addEventListener("change", this.transformChange);
|
|
895
1063
|
this.rotate.addEventListener("dragging-changed", this.rotateDrag);
|
|
896
1064
|
this.viewer.helpers.add(this.rotate.getHelper());
|
|
1065
|
+
this.setActiveHelper(this.helpers[this.helpers.length - 1]);
|
|
897
1066
|
this.viewer.addEventListener("explode", this.updatePlaneSize);
|
|
898
1067
|
this.viewer.addEventListener("show", this.updatePlaneSize);
|
|
899
1068
|
this.viewer.addEventListener("showall", this.updatePlaneSize);
|
|
900
1069
|
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);
|
|
901
1074
|
this.viewer.canvas.addEventListener("dblclick", this.onDoubleClick, true);
|
|
902
1075
|
window.addEventListener("keydown", this.onKeyDown);
|
|
903
1076
|
window.addEventListener("keyup", this.onKeyUp);
|
|
@@ -908,6 +1081,10 @@ class CuttingPlaneDragger extends OrbitDragger {
|
|
|
908
1081
|
this.viewer.removeEventListener("show", this.updatePlaneSize);
|
|
909
1082
|
this.viewer.removeEventListener("showall", this.updatePlaneSize);
|
|
910
1083
|
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);
|
|
911
1088
|
this.viewer.canvas.removeEventListener("dblclick", this.onDoubleClick, true);
|
|
912
1089
|
window.removeEventListener("keydown", this.onKeyDown);
|
|
913
1090
|
window.removeEventListener("keyup", this.onKeyUp);
|
|
@@ -921,28 +1098,108 @@ class CuttingPlaneDragger extends OrbitDragger {
|
|
|
921
1098
|
this.rotate.getHelper().removeFromParent();
|
|
922
1099
|
this.rotate.detach();
|
|
923
1100
|
this.rotate.dispose();
|
|
924
|
-
this.
|
|
925
|
-
|
|
926
|
-
|
|
1101
|
+
this.helpers.forEach((helper) => {
|
|
1102
|
+
helper.removeFromParent();
|
|
1103
|
+
helper.dispose();
|
|
1104
|
+
});
|
|
1105
|
+
this.helpers = [];
|
|
1106
|
+
this.activeHelper = null;
|
|
927
1107
|
super.dispose();
|
|
928
1108
|
}
|
|
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
|
+
}
|
|
929
1183
|
}
|
|
930
1184
|
|
|
931
1185
|
class CuttingPlaneXAxisDragger extends CuttingPlaneDragger {
|
|
932
1186
|
constructor(viewer) {
|
|
933
|
-
super(viewer
|
|
1187
|
+
super(viewer);
|
|
1188
|
+
this.addPlaneX();
|
|
934
1189
|
}
|
|
935
1190
|
}
|
|
936
1191
|
|
|
937
1192
|
class CuttingPlaneYAxisDragger extends CuttingPlaneDragger {
|
|
938
1193
|
constructor(viewer) {
|
|
939
|
-
super(viewer
|
|
1194
|
+
super(viewer);
|
|
1195
|
+
this.addPlaneY();
|
|
940
1196
|
}
|
|
941
1197
|
}
|
|
942
1198
|
|
|
943
1199
|
class CuttingPlaneZAxisDragger extends CuttingPlaneDragger {
|
|
944
1200
|
constructor(viewer) {
|
|
945
|
-
super(viewer
|
|
1201
|
+
super(viewer);
|
|
1202
|
+
this.addPlaneZ();
|
|
946
1203
|
}
|
|
947
1204
|
}
|
|
948
1205
|
|
|
@@ -1019,120 +1276,6 @@ function formatDistance(distance, units, precision = 2) {
|
|
|
1019
1276
|
}
|
|
1020
1277
|
}
|
|
1021
1278
|
|
|
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
|
-
|
|
1136
1279
|
const _downPoint = new Vector2();
|
|
1137
1280
|
class MeasureLineDragger extends OrbitDragger {
|
|
1138
1281
|
constructor(viewer) {
|
|
@@ -1544,6 +1687,12 @@ class WalkControls extends Controls {
|
|
|
1544
1687
|
this.movementSpeed = 0.1;
|
|
1545
1688
|
this.multiplier = 3;
|
|
1546
1689
|
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();
|
|
1547
1696
|
this.moveWheel = 0;
|
|
1548
1697
|
this.mouseDragOn = false;
|
|
1549
1698
|
this._up = new Vector3();
|
|
@@ -1610,11 +1759,20 @@ class WalkControls extends Controls {
|
|
|
1610
1759
|
}
|
|
1611
1760
|
};
|
|
1612
1761
|
this.onKeyUp = (event) => {
|
|
1613
|
-
if (this.moveKeys.delete(event.code))
|
|
1762
|
+
if (this.moveKeys.delete(event.code)) {
|
|
1763
|
+
if (this.moveKeys.size === 0) {
|
|
1764
|
+
this._rebuildGroundBox(this.object.position);
|
|
1765
|
+
}
|
|
1614
1766
|
this.update();
|
|
1767
|
+
}
|
|
1615
1768
|
};
|
|
1616
1769
|
this.camera = camera;
|
|
1617
1770
|
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);
|
|
1618
1776
|
this.raycaster = new Raycaster();
|
|
1619
1777
|
this.raycaster.near = 0;
|
|
1620
1778
|
this.raycaster.far = this.EYE_HEIGHT + this.FAILING_DISTANCE;
|
|
@@ -1649,10 +1807,29 @@ class WalkControls extends Controls {
|
|
|
1649
1807
|
window.removeEventListener("keyup", this.onKeyUp);
|
|
1650
1808
|
super.dispose();
|
|
1651
1809
|
}
|
|
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
|
+
}
|
|
1652
1825
|
updateGroundFollowing() {
|
|
1826
|
+
const pos = this.object.position;
|
|
1827
|
+
if (this._needsGroundBoxRebuild(pos)) {
|
|
1828
|
+
this._rebuildGroundBox(pos);
|
|
1829
|
+
}
|
|
1653
1830
|
this._up.copy(this.camera.up).negate();
|
|
1654
|
-
this.raycaster.set(
|
|
1655
|
-
const intersects = this.raycaster.intersectObjects(this.
|
|
1831
|
+
this.raycaster.set(pos, this._up);
|
|
1832
|
+
const intersects = this.raycaster.intersectObjects(this._activeGroundObjects, false);
|
|
1656
1833
|
if (intersects.length > 0) {
|
|
1657
1834
|
const groundY = intersects[0].point.y;
|
|
1658
1835
|
const targetY = groundY + this.EYE_HEIGHT;
|
|
@@ -2204,6 +2381,7 @@ draggers.registerDragger("Pan", (viewer) => new PanDragger(viewer));
|
|
|
2204
2381
|
draggers.registerDragger("Orbit", (viewer) => new OrbitDragger(viewer));
|
|
2205
2382
|
draggers.registerDragger("Zoom", (viewer) => new ZoomDragger(viewer));
|
|
2206
2383
|
draggers.registerDragger("MeasureLine", (viewer) => new MeasureLineDragger(viewer));
|
|
2384
|
+
draggers.registerDragger("CuttingPlane", (viewer) => new CuttingPlaneDragger(viewer));
|
|
2207
2385
|
draggers.registerDragger("CuttingPlaneXAxis", (viewer) => new CuttingPlaneXAxisDragger(viewer));
|
|
2208
2386
|
draggers.registerDragger("CuttingPlaneYAxis", (viewer) => new CuttingPlaneYAxisDragger(viewer));
|
|
2209
2387
|
draggers.registerDragger("CuttingPlaneZAxis", (viewer) => new CuttingPlaneZAxisDragger(viewer));
|
|
@@ -3099,7 +3277,7 @@ class SelectionComponent {
|
|
|
3099
3277
|
this.getMousePosition(event, this.downPosition);
|
|
3100
3278
|
};
|
|
3101
3279
|
this.onPointerUp = (event) => {
|
|
3102
|
-
if (!event.isPrimary)
|
|
3280
|
+
if (!event.isPrimary || event.button !== 0)
|
|
3103
3281
|
return;
|
|
3104
3282
|
const upPosition = this.getMousePosition(event, new Vector2());
|
|
3105
3283
|
if (upPosition.distanceTo(this.downPosition) !== 0)
|
|
@@ -3628,19 +3806,19 @@ class ModelImpl {
|
|
|
3628
3806
|
return this;
|
|
3629
3807
|
}
|
|
3630
3808
|
explode(scale = 0, coeff = 4) {
|
|
3631
|
-
const
|
|
3632
|
-
const
|
|
3809
|
+
const centersCache = new Map();
|
|
3810
|
+
const calcObjectCenter = (object, target) => {
|
|
3633
3811
|
const extents = new Box3().setFromObject(object);
|
|
3634
3812
|
const handle = object.userData.handle;
|
|
3635
3813
|
if (!handle)
|
|
3636
3814
|
return extents.getCenter(target);
|
|
3637
|
-
const center =
|
|
3815
|
+
const center = centersCache.get(handle);
|
|
3638
3816
|
if (center)
|
|
3639
3817
|
return target.copy(center);
|
|
3640
3818
|
const objects = this.getObjectsByHandles(handle);
|
|
3641
3819
|
objects.forEach((x) => extents.expandByObject(x));
|
|
3642
3820
|
extents.getCenter(target);
|
|
3643
|
-
|
|
3821
|
+
centersCache.set(handle, target.clone());
|
|
3644
3822
|
return target;
|
|
3645
3823
|
};
|
|
3646
3824
|
function calcExplodeDepth(object, depth) {
|
|
@@ -3651,13 +3829,14 @@ class ModelImpl {
|
|
|
3651
3829
|
result = objectDepth;
|
|
3652
3830
|
});
|
|
3653
3831
|
object.userData.originalPosition = object.position.clone();
|
|
3654
|
-
object.userData.originalCenter =
|
|
3832
|
+
object.userData.originalCenter = calcObjectCenter(object, new Vector3());
|
|
3655
3833
|
return result;
|
|
3656
3834
|
}
|
|
3657
3835
|
const explodeScale = scale / 100;
|
|
3658
3836
|
const explodeRoot = this.scene;
|
|
3659
|
-
if (!explodeRoot.userData.explodeDepth)
|
|
3837
|
+
if (!explodeRoot.userData.explodeDepth) {
|
|
3660
3838
|
explodeRoot.userData.explodeDepth = calcExplodeDepth(explodeRoot, 1);
|
|
3839
|
+
}
|
|
3661
3840
|
const maxDepth = explodeRoot.userData.explodeDepth;
|
|
3662
3841
|
const scaledExplodeDepth = explodeScale * maxDepth + 1;
|
|
3663
3842
|
const explodeDepth = 0 | scaledExplodeDepth;
|
|
@@ -3674,8 +3853,8 @@ class ModelImpl {
|
|
|
3674
3853
|
objectScale *= currentSegmentFraction;
|
|
3675
3854
|
const parentCenter = object.parent.userData.originalCenter;
|
|
3676
3855
|
const objectCenter = object.userData.originalCenter;
|
|
3677
|
-
const
|
|
3678
|
-
object.position.add(
|
|
3856
|
+
const localOffset = objectCenter.clone().sub(parentCenter).multiplyScalar(objectScale);
|
|
3857
|
+
object.position.add(localOffset);
|
|
3679
3858
|
}
|
|
3680
3859
|
object.children.forEach((x) => explodeObject(x, depth + 1));
|
|
3681
3860
|
}
|
|
@@ -3767,67 +3946,73 @@ class DynamicModelImpl extends ModelImpl {
|
|
|
3767
3946
|
return this;
|
|
3768
3947
|
}
|
|
3769
3948
|
explode(scale = 0, coeff = 4) {
|
|
3770
|
-
const
|
|
3949
|
+
const centersCache = new Map();
|
|
3771
3950
|
const calcObjectCenter = (object, target) => {
|
|
3772
3951
|
const extents = new Box3().setFromObject(object);
|
|
3773
3952
|
const handle = object.userData.handle;
|
|
3774
3953
|
if (!handle)
|
|
3775
3954
|
return extents.getCenter(target);
|
|
3776
|
-
const center =
|
|
3955
|
+
const center = centersCache.get(handle);
|
|
3777
3956
|
if (center)
|
|
3778
3957
|
return target.copy(center);
|
|
3779
3958
|
const objects = this.getObjectsByHandles(handle);
|
|
3780
3959
|
objects.forEach((x) => extents.expandByObject(x));
|
|
3781
3960
|
extents.getCenter(target);
|
|
3782
|
-
|
|
3961
|
+
centersCache.set(handle, target.clone());
|
|
3783
3962
|
return target;
|
|
3784
3963
|
};
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
if (result < objectDepth)
|
|
3792
|
-
result = objectDepth;
|
|
3793
|
-
});
|
|
3964
|
+
const calcObjectDepth = (object) => {
|
|
3965
|
+
if (object.userData.depth !== undefined)
|
|
3966
|
+
return object.userData.depth;
|
|
3967
|
+
const parent = object.parent;
|
|
3968
|
+
const depth = parent && object !== explodeRoot ? calcObjectDepth(parent) + 1 : 0;
|
|
3969
|
+
object.userData.depth = depth;
|
|
3794
3970
|
object.userData.originalPosition = object.position.clone();
|
|
3795
3971
|
object.userData.originalCenter = calcObjectCenter(object, new Vector3());
|
|
3796
|
-
return
|
|
3797
|
-
}
|
|
3972
|
+
return depth;
|
|
3973
|
+
};
|
|
3798
3974
|
const explodeScale = scale / 100;
|
|
3799
3975
|
const explodeRoot = this.scene.children[0];
|
|
3800
|
-
if (!explodeRoot.userData.explodeDepth)
|
|
3801
|
-
|
|
3976
|
+
if (!explodeRoot.userData.explodeDepth) {
|
|
3977
|
+
let maxDepth = 0;
|
|
3978
|
+
this.gltfLoader.originalObjects.forEach((object) => {
|
|
3979
|
+
const depth = calcObjectDepth(object);
|
|
3980
|
+
if (depth > maxDepth)
|
|
3981
|
+
maxDepth = depth;
|
|
3982
|
+
});
|
|
3983
|
+
explodeRoot.userData.explodeDepth = maxDepth;
|
|
3984
|
+
}
|
|
3802
3985
|
const maxDepth = explodeRoot.userData.explodeDepth;
|
|
3803
3986
|
const scaledExplodeDepth = explodeScale * maxDepth + 1;
|
|
3804
3987
|
const explodeDepth = 0 | scaledExplodeDepth;
|
|
3805
3988
|
const currentSegmentFraction = scaledExplodeDepth - explodeDepth;
|
|
3806
|
-
const
|
|
3807
|
-
|
|
3808
|
-
if (object
|
|
3809
|
-
return;
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3989
|
+
const offsetCache = new Map();
|
|
3990
|
+
const calcObjectOffset = (object, target) => {
|
|
3991
|
+
if (offsetCache.has(object))
|
|
3992
|
+
return target.copy(offsetCache.get(object));
|
|
3993
|
+
const parent = object.parent;
|
|
3994
|
+
if (parent && object !== explodeRoot)
|
|
3995
|
+
calcObjectOffset(parent, target);
|
|
3996
|
+
const depth = object.userData.depth;
|
|
3997
|
+
if (depth > 0 && depth <= explodeDepth) {
|
|
3814
3998
|
let objectScale = explodeScale * coeff;
|
|
3815
3999
|
if (depth === explodeDepth)
|
|
3816
4000
|
objectScale *= currentSegmentFraction;
|
|
3817
|
-
const parentCenter =
|
|
4001
|
+
const parentCenter = parent.userData.originalCenter;
|
|
3818
4002
|
const objectCenter = object.userData.originalCenter;
|
|
3819
|
-
const
|
|
3820
|
-
|
|
3821
|
-
const matrix = new Matrix4().makeTranslation(objectOffset.x, objectOffset.y, objectOffset.z);
|
|
3822
|
-
transformMap.set(object, matrix);
|
|
4003
|
+
const localOffset = objectCenter.clone().sub(parentCenter).multiplyScalar(objectScale);
|
|
4004
|
+
target.add(localOffset);
|
|
3823
4005
|
}
|
|
3824
|
-
object.
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
4006
|
+
offsetCache.set(object, target.clone());
|
|
4007
|
+
return target;
|
|
4008
|
+
};
|
|
4009
|
+
const transformMap = new Map();
|
|
4010
|
+
this.gltfLoader.originalObjects.forEach((object) => {
|
|
4011
|
+
const globalOffset = calcObjectOffset(object, new Vector3());
|
|
4012
|
+
transformMap.set(object, new Matrix4().makeTranslation(globalOffset));
|
|
4013
|
+
});
|
|
3830
4014
|
this.gltfLoader.applyObjectTransforms(transformMap);
|
|
4015
|
+
this.scene.updateMatrixWorld();
|
|
3831
4016
|
return this;
|
|
3832
4017
|
}
|
|
3833
4018
|
}
|
|
@@ -4404,6 +4589,8 @@ class DynamicGltfLoader {
|
|
|
4404
4589
|
this.oldOptimizeObjects = new Set();
|
|
4405
4590
|
this.objectTransforms = new Map();
|
|
4406
4591
|
this.transformedGeometries = new Map();
|
|
4592
|
+
this.syncTransformsToOriginalObjects = true;
|
|
4593
|
+
this._originalObjectMatrices = new Map();
|
|
4407
4594
|
this.activeChunkLoads = 0;
|
|
4408
4595
|
this.chunkQueue = [];
|
|
4409
4596
|
this.objectIdToIndex = new Map();
|
|
@@ -4413,6 +4600,81 @@ class DynamicGltfLoader {
|
|
|
4413
4600
|
this.mergedObjectMap = new Map();
|
|
4414
4601
|
this.mergedGeometryVisibility = new Map();
|
|
4415
4602
|
this._webglInfoCache = null;
|
|
4603
|
+
this.transformTextureSize = 1024;
|
|
4604
|
+
this.transformTexture = this.createDummyTexture();
|
|
4605
|
+
this.transformData = null;
|
|
4606
|
+
this.identityTransformData = null;
|
|
4607
|
+
this.visibilityMaterials = new Set();
|
|
4608
|
+
}
|
|
4609
|
+
createDummyTexture() {
|
|
4610
|
+
const data = new Float32Array(16);
|
|
4611
|
+
const identity = new Matrix4();
|
|
4612
|
+
identity.toArray(data);
|
|
4613
|
+
const dummyData = new Float32Array(16);
|
|
4614
|
+
identity.toArray(dummyData);
|
|
4615
|
+
const dummyTexture = new DataTexture(dummyData, 4, 1, RGBAFormat, FloatType);
|
|
4616
|
+
dummyTexture.minFilter = NearestFilter;
|
|
4617
|
+
dummyTexture.magFilter = NearestFilter;
|
|
4618
|
+
dummyTexture.needsUpdate = true;
|
|
4619
|
+
return dummyTexture;
|
|
4620
|
+
}
|
|
4621
|
+
initTransformTexture() {
|
|
4622
|
+
if (this.transformTexture) {
|
|
4623
|
+
this.transformTexture.dispose();
|
|
4624
|
+
}
|
|
4625
|
+
const maxInstanceCount = this.maxObjectId + 1;
|
|
4626
|
+
let size = Math.sqrt(maxInstanceCount * 4);
|
|
4627
|
+
size = Math.ceil(size / 4) * 4;
|
|
4628
|
+
size = Math.max(size, 4);
|
|
4629
|
+
this.transformTextureSize = size;
|
|
4630
|
+
const arraySize = size * size * 4;
|
|
4631
|
+
this.transformData = new Float32Array(arraySize);
|
|
4632
|
+
this.identityTransformData = new Float32Array(arraySize);
|
|
4633
|
+
for (let i = 0; i <= this.maxObjectId; i++) {
|
|
4634
|
+
const base = i * 16;
|
|
4635
|
+
if (base + 15 < arraySize) {
|
|
4636
|
+
this.identityTransformData[base + 0] = 1;
|
|
4637
|
+
this.identityTransformData[base + 5] = 1;
|
|
4638
|
+
this.identityTransformData[base + 10] = 1;
|
|
4639
|
+
this.identityTransformData[base + 15] = 1;
|
|
4640
|
+
}
|
|
4641
|
+
}
|
|
4642
|
+
this._resetTransformData(false);
|
|
4643
|
+
this.transformTexture = new DataTexture(this.transformData, size, size, RGBAFormat, FloatType);
|
|
4644
|
+
this.transformTexture.needsUpdate = true;
|
|
4645
|
+
this.transformTexture.generateMipmaps = false;
|
|
4646
|
+
console.log(`Initialized transform texture: ${size}x${size} for ${maxInstanceCount} objects`);
|
|
4647
|
+
this.updateMaterialUniforms();
|
|
4648
|
+
this.visibilityMaterials.forEach((material) => {
|
|
4649
|
+
material.needsUpdate = true;
|
|
4650
|
+
});
|
|
4651
|
+
}
|
|
4652
|
+
_resetTransformData(updateTexture = true) {
|
|
4653
|
+
if (!this.transformData || !this.identityTransformData) return;
|
|
4654
|
+
this.transformData.set(this.identityTransformData);
|
|
4655
|
+
if (updateTexture) {
|
|
4656
|
+
this.updateTransformTexture();
|
|
4657
|
+
}
|
|
4658
|
+
}
|
|
4659
|
+
updateMaterialUniforms() {
|
|
4660
|
+
if (
|
|
4661
|
+
this._lastTransformTexture === this.transformTexture &&
|
|
4662
|
+
this._lastTransformTextureSize === this.transformTextureSize
|
|
4663
|
+
) {
|
|
4664
|
+
return;
|
|
4665
|
+
}
|
|
4666
|
+
this._lastTransformTexture = this.transformTexture;
|
|
4667
|
+
this._lastTransformTextureSize = this.transformTextureSize;
|
|
4668
|
+
this.visibilityMaterials.forEach((material) => {
|
|
4669
|
+
if (material.userData && material.userData.visibilityUniforms) {
|
|
4670
|
+
material.userData.visibilityUniforms.transformTexture.value = this.transformTexture;
|
|
4671
|
+
material.userData.visibilityUniforms.transformTextureSize.value = this.transformTextureSize;
|
|
4672
|
+
}
|
|
4673
|
+
});
|
|
4674
|
+
}
|
|
4675
|
+
updateTransformTexture() {
|
|
4676
|
+
if (!this.transformTexture) return;
|
|
4677
|
+
this.transformTexture.needsUpdate = true;
|
|
4416
4678
|
}
|
|
4417
4679
|
setVisibleEdges(visible) {
|
|
4418
4680
|
this.visibleEdges = visible;
|
|
@@ -5302,36 +5564,82 @@ class DynamicGltfLoader {
|
|
|
5302
5564
|
}
|
|
5303
5565
|
}
|
|
5304
5566
|
createVisibilityMaterial(material) {
|
|
5567
|
+
this.visibilityMaterials.add(material);
|
|
5568
|
+
const uniforms = {
|
|
5569
|
+
transformTexture: { value: this.transformTexture },
|
|
5570
|
+
transformTextureSize: { value: this.transformTextureSize },
|
|
5571
|
+
};
|
|
5572
|
+
material.userData.visibilityUniforms = uniforms;
|
|
5305
5573
|
material.onBeforeCompile = (shader) => {
|
|
5574
|
+
shader.uniforms.transformTexture = uniforms.transformTexture;
|
|
5575
|
+
shader.uniforms.transformTextureSize = uniforms.transformTextureSize;
|
|
5306
5576
|
shader.vertexShader = shader.vertexShader.replace(
|
|
5307
5577
|
"#include <common>",
|
|
5308
5578
|
`
|
|
5309
5579
|
#include <common>
|
|
5580
|
+
|
|
5310
5581
|
attribute float visibility;
|
|
5582
|
+
attribute float objectId;
|
|
5311
5583
|
varying float vVisibility;
|
|
5584
|
+
uniform highp sampler2D transformTexture;
|
|
5585
|
+
uniform float transformTextureSize;
|
|
5586
|
+
|
|
5587
|
+
mat4 getTransformMatrix(float instanceId) {
|
|
5588
|
+
int size = int(transformTextureSize);
|
|
5589
|
+
int index = int(instanceId) * 4;
|
|
5590
|
+
|
|
5591
|
+
int x0 = index % size;
|
|
5592
|
+
int y0 = index / size;
|
|
5593
|
+
|
|
5594
|
+
vec4 row0 = texelFetch(transformTexture, ivec2(x0, y0), 0);
|
|
5595
|
+
vec4 row1 = texelFetch(transformTexture, ivec2(x0 + 1, y0), 0);
|
|
5596
|
+
vec4 row2 = texelFetch(transformTexture, ivec2(x0 + 2, y0), 0);
|
|
5597
|
+
vec4 row3 = texelFetch(transformTexture, ivec2(x0 + 3, y0), 0);
|
|
5598
|
+
|
|
5599
|
+
return mat4(row0, row1, row2, row3);
|
|
5600
|
+
}
|
|
5312
5601
|
`
|
|
5313
5602
|
);
|
|
5314
|
-
shader.
|
|
5315
|
-
"
|
|
5603
|
+
shader.vertexShader = shader.vertexShader.replace(
|
|
5604
|
+
"void main() {",
|
|
5316
5605
|
`
|
|
5317
|
-
|
|
5318
|
-
|
|
5606
|
+
void main() {
|
|
5607
|
+
mat4 batchingMatrix = getTransformMatrix(objectId);
|
|
5608
|
+
vVisibility = visibility;
|
|
5319
5609
|
`
|
|
5320
5610
|
);
|
|
5611
|
+
if (shader.vertexShader.includes("#include <beginnormal_vertex>")) {
|
|
5612
|
+
shader.vertexShader = shader.vertexShader.replace(
|
|
5613
|
+
"#include <beginnormal_vertex>",
|
|
5614
|
+
`
|
|
5615
|
+
vec3 objectNormal = vec3( normal );
|
|
5616
|
+
mat3 bm = mat3( batchingMatrix );
|
|
5617
|
+
objectNormal = bm * objectNormal;
|
|
5618
|
+
`
|
|
5619
|
+
);
|
|
5620
|
+
}
|
|
5321
5621
|
shader.vertexShader = shader.vertexShader.replace(
|
|
5322
|
-
"
|
|
5622
|
+
"#include <begin_vertex>",
|
|
5323
5623
|
`
|
|
5324
|
-
|
|
5325
|
-
|
|
5624
|
+
vec3 transformed = vec3( position );
|
|
5625
|
+
transformed = ( batchingMatrix * vec4( transformed, 1.0 ) ).xyz;
|
|
5326
5626
|
`
|
|
5327
5627
|
);
|
|
5328
|
-
shader.fragmentShader = shader.fragmentShader
|
|
5329
|
-
|
|
5628
|
+
shader.fragmentShader = shader.fragmentShader
|
|
5629
|
+
.replace(
|
|
5630
|
+
"#include <common>",
|
|
5631
|
+
`
|
|
5632
|
+
#include <common>
|
|
5633
|
+
varying float vVisibility;
|
|
5330
5634
|
`
|
|
5635
|
+
)
|
|
5636
|
+
.replace(
|
|
5637
|
+
"void main() {",
|
|
5638
|
+
`
|
|
5331
5639
|
void main() {
|
|
5332
5640
|
if (vVisibility < 0.5) discard;
|
|
5333
5641
|
`
|
|
5334
|
-
|
|
5642
|
+
);
|
|
5335
5643
|
};
|
|
5336
5644
|
material.needsUpdate = true;
|
|
5337
5645
|
return material;
|
|
@@ -5437,6 +5745,7 @@ class DynamicGltfLoader {
|
|
|
5437
5745
|
this.isolatedObjects = [];
|
|
5438
5746
|
this.objectTransforms.clear();
|
|
5439
5747
|
this.transformedGeometries.clear();
|
|
5748
|
+
this._originalObjectMatrices.clear();
|
|
5440
5749
|
this.totalLoadedObjects = 0;
|
|
5441
5750
|
this.currentMemoryUsage = 0;
|
|
5442
5751
|
this.pendingMemoryUsage = 0;
|
|
@@ -5446,6 +5755,8 @@ class DynamicGltfLoader {
|
|
|
5446
5755
|
this.objectIdToIndex.clear();
|
|
5447
5756
|
this.maxObjectId = 0;
|
|
5448
5757
|
this.objectVisibility = new Float32Array();
|
|
5758
|
+
this.meshToNodeMap = null;
|
|
5759
|
+
this.visibilityMaterials.clear();
|
|
5449
5760
|
}
|
|
5450
5761
|
setStructureTransform(structureId, matrix) {
|
|
5451
5762
|
const rootGroup = this.structureRoots.get(structureId);
|
|
@@ -5561,12 +5872,15 @@ class DynamicGltfLoader {
|
|
|
5561
5872
|
});
|
|
5562
5873
|
this.originalObjects.clear();
|
|
5563
5874
|
this.originalObjectsToSelection.clear();
|
|
5875
|
+
this.objectIdToIndex.clear();
|
|
5876
|
+
this.maxObjectId = 0;
|
|
5564
5877
|
const structureGroups = new Map();
|
|
5565
5878
|
this.dispatchEvent("optimizationprogress", {
|
|
5566
5879
|
phase: "collecting",
|
|
5567
5880
|
progress: 5,
|
|
5568
5881
|
message: "Collecting scene objects...",
|
|
5569
5882
|
});
|
|
5883
|
+
let totalObjectsToMerge = 0;
|
|
5570
5884
|
this.scene.traverse((object) => {
|
|
5571
5885
|
if (object.userData.structureId) {
|
|
5572
5886
|
const structureId = object.userData.structureId;
|
|
@@ -5584,17 +5898,32 @@ class DynamicGltfLoader {
|
|
|
5584
5898
|
});
|
|
5585
5899
|
}
|
|
5586
5900
|
const group = structureGroups.get(structureId);
|
|
5901
|
+
let added = false;
|
|
5587
5902
|
if (object instanceof Mesh) {
|
|
5588
5903
|
this.addToMaterialGroup(object, group.mapMeshes, group.meshes);
|
|
5904
|
+
added = true;
|
|
5589
5905
|
} else if (object instanceof LineSegments) {
|
|
5590
5906
|
this.addToMaterialGroup(object, group.mapLineSegments, group.lineSegments);
|
|
5907
|
+
added = true;
|
|
5591
5908
|
} else if (object instanceof Line) {
|
|
5592
5909
|
this.addToMaterialGroup(object, group.mapLines, group.lines);
|
|
5910
|
+
added = true;
|
|
5593
5911
|
} else if (object instanceof Points) {
|
|
5594
5912
|
this.addToMaterialGroup(object, group.mapPoints, group.points);
|
|
5913
|
+
added = true;
|
|
5914
|
+
}
|
|
5915
|
+
if (added) {
|
|
5916
|
+
totalObjectsToMerge++;
|
|
5595
5917
|
}
|
|
5596
5918
|
}
|
|
5597
5919
|
});
|
|
5920
|
+
if (totalObjectsToMerge > 0) {
|
|
5921
|
+
console.log(`Pre-allocating transform texture for ${totalObjectsToMerge} objects`);
|
|
5922
|
+
this.maxObjectId = totalObjectsToMerge;
|
|
5923
|
+
this.initTransformTexture();
|
|
5924
|
+
this.initializeObjectVisibility();
|
|
5925
|
+
this.maxObjectId = 0;
|
|
5926
|
+
}
|
|
5598
5927
|
let processedGroups = 0;
|
|
5599
5928
|
const totalGroups = structureGroups.size;
|
|
5600
5929
|
this.dispatchEvent("optimizationprogress", {
|
|
@@ -5639,7 +5968,6 @@ class DynamicGltfLoader {
|
|
|
5639
5968
|
this.originalObjectsToSelection.add(obj);
|
|
5640
5969
|
}
|
|
5641
5970
|
});
|
|
5642
|
-
this.initializeObjectVisibility();
|
|
5643
5971
|
console.log(`Optimization complete. Total objects: ${this.maxObjectId}`);
|
|
5644
5972
|
this.dispatchEvent("optimizationprogress", {
|
|
5645
5973
|
phase: "complete",
|
|
@@ -5708,6 +6036,7 @@ class DynamicGltfLoader {
|
|
|
5708
6036
|
}
|
|
5709
6037
|
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
5710
6038
|
const mergedMesh = new Mesh(mergedGeometry, visibilityMaterial);
|
|
6039
|
+
mergedMesh.frustumCulled = false;
|
|
5711
6040
|
mergedMesh.userData.isOptimized = true;
|
|
5712
6041
|
rootGroup.add(mergedMesh);
|
|
5713
6042
|
this.mergedMesh.add(mergedMesh);
|
|
@@ -5824,6 +6153,7 @@ class DynamicGltfLoader {
|
|
|
5824
6153
|
geometry.setAttribute("visibility", new BufferAttribute(visibilityArray, 1));
|
|
5825
6154
|
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
5826
6155
|
const mergedLine = new LineSegments(geometry, visibilityMaterial);
|
|
6156
|
+
mergedLine.frustumCulled = false;
|
|
5827
6157
|
mergedLine.userData.isEdge = isEdge;
|
|
5828
6158
|
mergedLine.userData.isOptimized = true;
|
|
5829
6159
|
const mergedObjects = [mergedLine];
|
|
@@ -5912,6 +6242,7 @@ class DynamicGltfLoader {
|
|
|
5912
6242
|
mergedGeometry.setAttribute("visibility", new BufferAttribute(visibilityArray, 1));
|
|
5913
6243
|
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
5914
6244
|
const mergedLine = new LineSegments(mergedGeometry, visibilityMaterial);
|
|
6245
|
+
mergedLine.frustumCulled = false;
|
|
5915
6246
|
mergedLine.userData.isEdge = isEdge;
|
|
5916
6247
|
mergedLine.userData.isOptimized = true;
|
|
5917
6248
|
if (this.useVAO) {
|
|
@@ -5981,7 +6312,27 @@ class DynamicGltfLoader {
|
|
|
5981
6312
|
const mergedObjects = [];
|
|
5982
6313
|
if (geometries.length > 0) {
|
|
5983
6314
|
const mergedGeometry = mergeGeometries(geometries, false);
|
|
5984
|
-
const
|
|
6315
|
+
const totalVertices = mergedGeometry.attributes.position.count;
|
|
6316
|
+
const objectIds = new Float32Array(totalVertices);
|
|
6317
|
+
let vertexOffset = 0;
|
|
6318
|
+
group.objects.forEach((points) => {
|
|
6319
|
+
const handle = points.userData.handle;
|
|
6320
|
+
if (!this.objectIdToIndex.has(handle)) {
|
|
6321
|
+
this.objectIdToIndex.set(handle, this.maxObjectId++);
|
|
6322
|
+
}
|
|
6323
|
+
const objectId = this.objectIdToIndex.get(handle);
|
|
6324
|
+
const count = points.geometry.attributes.position.count;
|
|
6325
|
+
for (let i = 0; i < count; i++) {
|
|
6326
|
+
objectIds[vertexOffset++] = objectId;
|
|
6327
|
+
}
|
|
6328
|
+
});
|
|
6329
|
+
mergedGeometry.setAttribute("objectId", new BufferAttribute(objectIds, 1));
|
|
6330
|
+
const visibilityArray = new Float32Array(totalVertices);
|
|
6331
|
+
visibilityArray.fill(1.0);
|
|
6332
|
+
mergedGeometry.setAttribute("visibility", new BufferAttribute(visibilityArray, 1));
|
|
6333
|
+
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
6334
|
+
const mergedPoints = new Points(mergedGeometry, visibilityMaterial);
|
|
6335
|
+
mergedPoints.frustumCulled = false;
|
|
5985
6336
|
mergedPoints.userData.isOptimized = true;
|
|
5986
6337
|
if (this.useVAO) {
|
|
5987
6338
|
this.createVAO(mergedPoints);
|
|
@@ -6050,13 +6401,33 @@ class DynamicGltfLoader {
|
|
|
6050
6401
|
geometriesWithIndex.push(clonedGeometry);
|
|
6051
6402
|
});
|
|
6052
6403
|
const finalGeometry = mergeGeometries(geometriesWithIndex, false);
|
|
6404
|
+
const totalVertices = finalGeometry.attributes.position.count;
|
|
6405
|
+
const objectIds = new Float32Array(totalVertices);
|
|
6406
|
+
let vertexOffset = 0;
|
|
6407
|
+
lineSegmentsArray.forEach((segment) => {
|
|
6408
|
+
const handle = segment.userData.handle;
|
|
6409
|
+
if (!this.objectIdToIndex.has(handle)) {
|
|
6410
|
+
this.objectIdToIndex.set(handle, this.maxObjectId++);
|
|
6411
|
+
}
|
|
6412
|
+
const objectId = this.objectIdToIndex.get(handle);
|
|
6413
|
+
const count = segment.geometry.attributes.position.count;
|
|
6414
|
+
for (let i = 0; i < count; i++) {
|
|
6415
|
+
objectIds[vertexOffset++] = objectId;
|
|
6416
|
+
}
|
|
6417
|
+
});
|
|
6418
|
+
finalGeometry.setAttribute("objectId", new BufferAttribute(objectIds, 1));
|
|
6419
|
+
const visibilityArray = new Float32Array(totalVertices);
|
|
6420
|
+
visibilityArray.fill(1.0);
|
|
6421
|
+
finalGeometry.setAttribute("visibility", new BufferAttribute(visibilityArray, 1));
|
|
6053
6422
|
const material = new LineBasicMaterial({
|
|
6054
6423
|
vertexColors: true,
|
|
6055
6424
|
});
|
|
6425
|
+
const visibilityMaterial = this.createVisibilityMaterial(material);
|
|
6056
6426
|
if (this.useVAO) {
|
|
6057
6427
|
this.createVAO(finalGeometry);
|
|
6058
6428
|
}
|
|
6059
|
-
const mergedLine = new LineSegments(finalGeometry,
|
|
6429
|
+
const mergedLine = new LineSegments(finalGeometry, visibilityMaterial);
|
|
6430
|
+
mergedLine.frustumCulled = false;
|
|
6060
6431
|
mergedLine.userData.structureId = structureId;
|
|
6061
6432
|
mergedLine.userData.isOptimized = true;
|
|
6062
6433
|
rootGroup.add(mergedLine);
|
|
@@ -6175,18 +6546,91 @@ class DynamicGltfLoader {
|
|
|
6175
6546
|
console.warn("No merged objects to transform");
|
|
6176
6547
|
return;
|
|
6177
6548
|
}
|
|
6178
|
-
this.
|
|
6179
|
-
|
|
6180
|
-
|
|
6549
|
+
if (!this.transformData) {
|
|
6550
|
+
console.warn("Transform texture not initialized");
|
|
6551
|
+
return;
|
|
6181
6552
|
}
|
|
6182
|
-
|
|
6183
|
-
|
|
6553
|
+
this.objectTransforms = objectTransformMap;
|
|
6554
|
+
this._resetTransformData(false);
|
|
6555
|
+
const transformData = this.transformData;
|
|
6556
|
+
const objectIdToIndex = this.objectIdToIndex;
|
|
6557
|
+
let textureNeedsUpdate = false;
|
|
6558
|
+
if (objectTransformMap instanceof Map) {
|
|
6559
|
+
for (const [object, matrix] of objectTransformMap.entries()) {
|
|
6560
|
+
const userData = object.userData;
|
|
6561
|
+
if (!userData) continue;
|
|
6562
|
+
const handle = userData.handle;
|
|
6563
|
+
if (handle === undefined) continue;
|
|
6564
|
+
const objectId = objectIdToIndex.get(handle);
|
|
6565
|
+
if (objectId !== undefined) {
|
|
6566
|
+
transformData.set(matrix.elements, objectId * 16);
|
|
6567
|
+
textureNeedsUpdate = true;
|
|
6568
|
+
}
|
|
6569
|
+
}
|
|
6570
|
+
} else {
|
|
6571
|
+
const len = objectTransformMap.length;
|
|
6572
|
+
for (let i = 0; i < len; i++) {
|
|
6573
|
+
const pair = objectTransformMap[i];
|
|
6574
|
+
const userData = pair[0].userData;
|
|
6575
|
+
if (!userData) continue;
|
|
6576
|
+
const handle = userData.handle;
|
|
6577
|
+
if (handle === undefined) continue;
|
|
6578
|
+
const objectId = objectIdToIndex.get(handle);
|
|
6579
|
+
if (objectId !== undefined) {
|
|
6580
|
+
transformData.set(pair[1].elements, objectId * 16);
|
|
6581
|
+
textureNeedsUpdate = true;
|
|
6582
|
+
}
|
|
6583
|
+
}
|
|
6584
|
+
}
|
|
6585
|
+
if (textureNeedsUpdate) {
|
|
6586
|
+
this.updateTransformTexture();
|
|
6587
|
+
if (
|
|
6588
|
+
this._lastTransformTexture !== this.transformTexture ||
|
|
6589
|
+
this._lastTransformTextureSize !== this.transformTextureSize
|
|
6590
|
+
) {
|
|
6591
|
+
this.updateMaterialUniforms();
|
|
6592
|
+
}
|
|
6184
6593
|
}
|
|
6185
|
-
|
|
6186
|
-
this.
|
|
6594
|
+
if (this.syncTransformsToOriginalObjects) {
|
|
6595
|
+
this._syncOriginalObjectTransforms(objectTransformMap);
|
|
6187
6596
|
}
|
|
6188
|
-
|
|
6189
|
-
|
|
6597
|
+
}
|
|
6598
|
+
_syncOriginalObjectTransforms(objectTransformMap) {
|
|
6599
|
+
for (const [obj, savedPos] of this._originalObjectMatrices) {
|
|
6600
|
+
obj.position.copy(savedPos);
|
|
6601
|
+
if (obj.userData.highlight) {
|
|
6602
|
+
obj.userData.highlight.position.copy(savedPos);
|
|
6603
|
+
}
|
|
6604
|
+
}
|
|
6605
|
+
this._originalObjectMatrices.clear();
|
|
6606
|
+
const _offset = new Vector3();
|
|
6607
|
+
const _parentInverse = new Matrix4();
|
|
6608
|
+
if (objectTransformMap instanceof Map) {
|
|
6609
|
+
for (const [object, matrix] of objectTransformMap.entries()) {
|
|
6610
|
+
if (!object.userData?.handle) continue;
|
|
6611
|
+
if (!this._originalObjectMatrices.has(object)) {
|
|
6612
|
+
this._originalObjectMatrices.set(object, object.position.clone());
|
|
6613
|
+
}
|
|
6614
|
+
_offset.setFromMatrixPosition(matrix);
|
|
6615
|
+
if (object.userData.structureId) {
|
|
6616
|
+
const rootGroup = this.structureRoots.get(object.userData.structureId);
|
|
6617
|
+
if (rootGroup && object.parent && object.parent !== rootGroup) {
|
|
6618
|
+
const origin = new Vector3(0, 0, 0);
|
|
6619
|
+
origin.applyMatrix4(rootGroup.matrixWorld);
|
|
6620
|
+
_offset.applyMatrix4(rootGroup.matrixWorld);
|
|
6621
|
+
_offset.sub(origin);
|
|
6622
|
+
const parentOrigin = new Vector3(0, 0, 0);
|
|
6623
|
+
_parentInverse.copy(object.parent.matrixWorld).invert();
|
|
6624
|
+
parentOrigin.applyMatrix4(_parentInverse);
|
|
6625
|
+
_offset.applyMatrix4(_parentInverse);
|
|
6626
|
+
_offset.sub(parentOrigin);
|
|
6627
|
+
}
|
|
6628
|
+
}
|
|
6629
|
+
object.position.add(_offset);
|
|
6630
|
+
if (object.userData.highlight) {
|
|
6631
|
+
object.userData.highlight.position.copy(object.position);
|
|
6632
|
+
}
|
|
6633
|
+
}
|
|
6190
6634
|
}
|
|
6191
6635
|
}
|
|
6192
6636
|
createExplodeTransforms(objects = null, explodeCenter = null, explodeFactor = 1.5) {
|
|
@@ -6203,21 +6647,66 @@ class DynamicGltfLoader {
|
|
|
6203
6647
|
? objects
|
|
6204
6648
|
: Array.from(objects)
|
|
6205
6649
|
: Array.from(this.originalObjects);
|
|
6650
|
+
const structureInverseMatrices = new Map();
|
|
6651
|
+
if (!this.meshToNodeMap) {
|
|
6652
|
+
this.meshToNodeMap = new Map();
|
|
6653
|
+
for (const node of this.nodes.values()) {
|
|
6654
|
+
if (node.object) {
|
|
6655
|
+
this.meshToNodeMap.set(node.object, node);
|
|
6656
|
+
}
|
|
6657
|
+
}
|
|
6658
|
+
}
|
|
6206
6659
|
for (const obj of objectsArray) {
|
|
6207
6660
|
if (!obj.geometry || !obj.geometry.attributes.position) continue;
|
|
6208
|
-
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
|
|
6213
|
-
|
|
6214
|
-
|
|
6215
|
-
|
|
6216
|
-
|
|
6661
|
+
if (!obj.userData.explodeVector) {
|
|
6662
|
+
let center = null;
|
|
6663
|
+
const node = this.meshToNodeMap.get(obj);
|
|
6664
|
+
if (node && node.geometryExtents) {
|
|
6665
|
+
const box = node.geometryExtents.clone();
|
|
6666
|
+
box.applyMatrix4(obj.matrixWorld);
|
|
6667
|
+
center = new Vector3();
|
|
6668
|
+
box.getCenter(center);
|
|
6669
|
+
}
|
|
6670
|
+
if (!center) {
|
|
6671
|
+
if (!obj.geometry.boundingBox) obj.geometry.computeBoundingBox();
|
|
6672
|
+
const box = obj.geometry.boundingBox.clone();
|
|
6673
|
+
box.applyMatrix4(obj.matrixWorld);
|
|
6674
|
+
center = new Vector3();
|
|
6675
|
+
box.getCenter(center);
|
|
6676
|
+
}
|
|
6677
|
+
const explodeVector = center.sub(explodeCenter);
|
|
6678
|
+
obj.userData.explodeVector = explodeVector;
|
|
6679
|
+
}
|
|
6680
|
+
const explodeVector = obj.userData.explodeVector;
|
|
6681
|
+
const distance = explodeVector.length();
|
|
6217
6682
|
if (distance > 0) {
|
|
6218
|
-
|
|
6219
|
-
const
|
|
6220
|
-
|
|
6683
|
+
const offset = explodeVector.clone().multiplyScalar(explodeFactor - 1.0);
|
|
6684
|
+
const localOffset = offset.clone();
|
|
6685
|
+
if (obj.userData.structureId) {
|
|
6686
|
+
const structureId = obj.userData.structureId;
|
|
6687
|
+
let inverseMatrix = structureInverseMatrices.get(structureId);
|
|
6688
|
+
if (!inverseMatrix) {
|
|
6689
|
+
const rootGroup = this.structureRoots.get(structureId);
|
|
6690
|
+
if (rootGroup) {
|
|
6691
|
+
if (!rootGroup.userData.inverseWorldMatrix) {
|
|
6692
|
+
rootGroup.userData.inverseWorldMatrix = new Matrix4().copy(rootGroup.matrixWorld).invert();
|
|
6693
|
+
}
|
|
6694
|
+
inverseMatrix = rootGroup.userData.inverseWorldMatrix;
|
|
6695
|
+
structureInverseMatrices.set(structureId, inverseMatrix);
|
|
6696
|
+
}
|
|
6697
|
+
}
|
|
6698
|
+
if (inverseMatrix) {
|
|
6699
|
+
const zero = new Vector3(0, 0, 0).applyMatrix4(inverseMatrix);
|
|
6700
|
+
const vec = offset.clone().applyMatrix4(inverseMatrix).sub(zero);
|
|
6701
|
+
localOffset.copy(vec);
|
|
6702
|
+
}
|
|
6703
|
+
}
|
|
6704
|
+
let matrix = obj.userData.explodeMatrix;
|
|
6705
|
+
if (!matrix) {
|
|
6706
|
+
matrix = new Matrix4();
|
|
6707
|
+
obj.userData.explodeMatrix = matrix;
|
|
6708
|
+
}
|
|
6709
|
+
matrix.makeTranslation(localOffset.x, localOffset.y, localOffset.z);
|
|
6221
6710
|
transformMap.set(obj, matrix);
|
|
6222
6711
|
}
|
|
6223
6712
|
}
|
|
@@ -6225,115 +6714,19 @@ class DynamicGltfLoader {
|
|
|
6225
6714
|
}
|
|
6226
6715
|
clearTransforms() {
|
|
6227
6716
|
this.objectTransforms.clear();
|
|
6228
|
-
|
|
6229
|
-
|
|
6230
|
-
|
|
6231
|
-
|
|
6232
|
-
|
|
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
|
-
}
|
|
6240
|
-
}
|
|
6241
|
-
clearHandleTransforms() {
|
|
6242
|
-
this.clearTransforms();
|
|
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];
|
|
6717
|
+
this._resetTransformData(true);
|
|
6718
|
+
if (this.syncTransformsToOriginalObjects) {
|
|
6719
|
+
for (const [obj, savedPos] of this._originalObjectMatrices) {
|
|
6720
|
+
obj.position.copy(savedPos);
|
|
6721
|
+
if (obj.userData.highlight) {
|
|
6722
|
+
obj.userData.highlight.position.copy(savedPos);
|
|
6302
6723
|
}
|
|
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
6724
|
}
|
|
6725
|
+
this._originalObjectMatrices.clear();
|
|
6316
6726
|
}
|
|
6317
|
-
normalAttr.needsUpdate = true;
|
|
6318
6727
|
}
|
|
6319
|
-
|
|
6320
|
-
|
|
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();
|
|
6728
|
+
clearHandleTransforms() {
|
|
6729
|
+
this.clearTransforms();
|
|
6337
6730
|
}
|
|
6338
6731
|
syncHiddenObjects() {
|
|
6339
6732
|
if (this.mergedObjectMap.size === 0) {
|