@inweb/viewer-three 27.2.2 → 27.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/viewer-three.js +723 -358
- package/dist/viewer-three.js.map +1 -1
- package/dist/viewer-three.min.js +3 -3
- package/dist/viewer-three.module.js +724 -359
- package/dist/viewer-three.module.js.map +1 -1
- 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/components/SelectionComponent.ts +1 -1
- package/src/Viewer/controls/WalkControls.ts +10 -2
- package/src/Viewer/draggers/CuttingPlaneDragger.ts +191 -31
- package/src/Viewer/draggers/CuttingPlaneXAxis.ts +2 -3
- package/src/Viewer/draggers/CuttingPlaneYAxis.ts +2 -3
- package/src/Viewer/draggers/CuttingPlaneZAxis.ts +2 -3
- package/src/Viewer/draggers/index.ts +2 -0
- package/src/Viewer/helpers/PlaneHelper2.ts +30 -17
- package/src/Viewer/loaders/DynamicGltfLoader/DynamicGltfLoader.js +495 -182
- package/src/Viewer/loaders/DynamicGltfLoader/DynamicModelImpl.ts +44 -33
- package/src/Viewer/measurement/Snapper.ts +13 -5
- package/src/Viewer/models/ModelImpl.ts +13 -10
package/dist/viewer-three.js
CHANGED
|
@@ -33644,41 +33644,6 @@ void main() {
|
|
|
33644
33644
|
}
|
|
33645
33645
|
}
|
|
33646
33646
|
|
|
33647
|
-
class PlaneHelper2 extends Line$1 {
|
|
33648
|
-
constructor(size = 1, color = 0xc0c0c0) {
|
|
33649
|
-
const positions = [1, 1, 0, -1, 1, 0, -1, -1, 0, 1, -1, 0, 1, 1, 0];
|
|
33650
|
-
const geometry = new BufferGeometry();
|
|
33651
|
-
geometry.setAttribute("position", new Float32BufferAttribute(positions, 3));
|
|
33652
|
-
geometry.computeBoundingSphere();
|
|
33653
|
-
super(geometry, new LineBasicMaterial({ color, toneMapped: false }));
|
|
33654
|
-
this.type = "PlaneHelper2";
|
|
33655
|
-
this.size = size;
|
|
33656
|
-
const positions2 = [1, 1, 0, -1, 1, 0, -1, -1, 0, 1, 1, 0, -1, -1, 0, 1, -1, 0];
|
|
33657
|
-
const geometry2 = new BufferGeometry();
|
|
33658
|
-
geometry2.setAttribute("position", new Float32BufferAttribute(positions2, 3));
|
|
33659
|
-
geometry2.computeBoundingSphere();
|
|
33660
|
-
this.helper = new Mesh(geometry2, new MeshBasicMaterial({
|
|
33661
|
-
color,
|
|
33662
|
-
opacity: 0.2,
|
|
33663
|
-
transparent: true,
|
|
33664
|
-
depthWrite: false,
|
|
33665
|
-
toneMapped: false,
|
|
33666
|
-
side: DoubleSide,
|
|
33667
|
-
}));
|
|
33668
|
-
this.add(this.helper);
|
|
33669
|
-
}
|
|
33670
|
-
dispose() {
|
|
33671
|
-
this.geometry.dispose();
|
|
33672
|
-
this.material.dispose();
|
|
33673
|
-
this.helper.geometry.dispose();
|
|
33674
|
-
this.helper.material.dispose();
|
|
33675
|
-
}
|
|
33676
|
-
updateMatrixWorld(force) {
|
|
33677
|
-
this.scale.set(0.5 * this.size, 0.5 * this.size, 1);
|
|
33678
|
-
super.updateMatrixWorld(force);
|
|
33679
|
-
}
|
|
33680
|
-
}
|
|
33681
|
-
|
|
33682
33647
|
const _changeEvent = { type: "change" };
|
|
33683
33648
|
const _startEvent = { type: "start" };
|
|
33684
33649
|
const _endEvent = { type: "end" };
|
|
@@ -34337,6 +34302,166 @@ void main() {
|
|
|
34337
34302
|
}
|
|
34338
34303
|
}
|
|
34339
34304
|
|
|
34305
|
+
class PlaneHelper2 extends Object3D {
|
|
34306
|
+
constructor(size = 1, color = 0xf0f0f0, opacity = 0.15) {
|
|
34307
|
+
super();
|
|
34308
|
+
this.type = "PlaneHelper2";
|
|
34309
|
+
this.size = size;
|
|
34310
|
+
const positions = [1, 1, 0, -1, 1, 0, -1, -1, 0, 1, -1, 0, 1, 1, 0];
|
|
34311
|
+
const geometry = new BufferGeometry();
|
|
34312
|
+
geometry.setAttribute("position", new Float32BufferAttribute(positions, 3));
|
|
34313
|
+
geometry.computeBoundingSphere();
|
|
34314
|
+
this.outline = new Line$1(geometry, new LineBasicMaterial({ color, toneMapped: false }));
|
|
34315
|
+
const positions2 = [1, 1, 0, -1, 1, 0, -1, -1, 0, 1, 1, 0, -1, -1, 0, 1, -1, 0];
|
|
34316
|
+
const geometry2 = new BufferGeometry();
|
|
34317
|
+
geometry2.setAttribute("position", new Float32BufferAttribute(positions2, 3));
|
|
34318
|
+
geometry2.computeBoundingSphere();
|
|
34319
|
+
this.mesh = new Mesh(geometry2, new MeshBasicMaterial({
|
|
34320
|
+
color,
|
|
34321
|
+
opacity,
|
|
34322
|
+
transparent: true,
|
|
34323
|
+
depthWrite: false,
|
|
34324
|
+
toneMapped: false,
|
|
34325
|
+
side: DoubleSide,
|
|
34326
|
+
}));
|
|
34327
|
+
this.add(this.outline);
|
|
34328
|
+
this.add(this.mesh);
|
|
34329
|
+
}
|
|
34330
|
+
dispose() {
|
|
34331
|
+
this.outline.geometry.dispose();
|
|
34332
|
+
this.outline.material.dispose();
|
|
34333
|
+
this.mesh.geometry.dispose();
|
|
34334
|
+
this.mesh.material.dispose();
|
|
34335
|
+
}
|
|
34336
|
+
updateMatrixWorld(force) {
|
|
34337
|
+
this.scale.set(0.5 * this.size, 0.5 * this.size, 1);
|
|
34338
|
+
super.updateMatrixWorld(force);
|
|
34339
|
+
}
|
|
34340
|
+
getLineMaterial() {
|
|
34341
|
+
return this.outline.material;
|
|
34342
|
+
}
|
|
34343
|
+
getMeshMaterial() {
|
|
34344
|
+
return this.mesh.material;
|
|
34345
|
+
}
|
|
34346
|
+
}
|
|
34347
|
+
|
|
34348
|
+
const DESKTOP_SNAP_DISTANCE = 10;
|
|
34349
|
+
const MOBILE_SNAP_DISTANCE = 50;
|
|
34350
|
+
const _vertex = new Vector3();
|
|
34351
|
+
const _start$1 = new Vector3();
|
|
34352
|
+
const _end$1 = new Vector3();
|
|
34353
|
+
const _line = new Line3();
|
|
34354
|
+
const _center = new Vector3();
|
|
34355
|
+
const _projection = new Vector3();
|
|
34356
|
+
class Snapper {
|
|
34357
|
+
constructor(camera, renderer, canvas) {
|
|
34358
|
+
this.camera = camera;
|
|
34359
|
+
this.renderer = renderer;
|
|
34360
|
+
this.canvas = canvas;
|
|
34361
|
+
this.threshold = 0.0001;
|
|
34362
|
+
this.raycaster = new Raycaster();
|
|
34363
|
+
this.detectRadiusInPixels = this.isMobile() ? MOBILE_SNAP_DISTANCE : DESKTOP_SNAP_DISTANCE;
|
|
34364
|
+
this.edgesCache = new WeakMap();
|
|
34365
|
+
}
|
|
34366
|
+
isMobile() {
|
|
34367
|
+
if (typeof navigator === "undefined")
|
|
34368
|
+
return false;
|
|
34369
|
+
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent);
|
|
34370
|
+
}
|
|
34371
|
+
getMousePosition(event, target) {
|
|
34372
|
+
return target.set(event.clientX, event.clientY);
|
|
34373
|
+
}
|
|
34374
|
+
getPointerIntersects(mouse, objects, recursive = false, clip = true) {
|
|
34375
|
+
const rect = this.canvas.getBoundingClientRect();
|
|
34376
|
+
const x = ((mouse.x - rect.left) / rect.width) * 2 - 1;
|
|
34377
|
+
const y = (-(mouse.y - rect.top) / rect.height) * 2 + 1;
|
|
34378
|
+
const coords = new Vector2(x, y);
|
|
34379
|
+
this.raycaster.setFromCamera(coords, this.camera);
|
|
34380
|
+
this.raycaster.params = {
|
|
34381
|
+
Mesh: {},
|
|
34382
|
+
Line: { threshold: this.threshold },
|
|
34383
|
+
Line2: { threshold: this.threshold },
|
|
34384
|
+
LOD: {},
|
|
34385
|
+
Points: { threshold: this.threshold },
|
|
34386
|
+
Sprite: {},
|
|
34387
|
+
};
|
|
34388
|
+
let intersects = this.raycaster.intersectObjects(objects, recursive);
|
|
34389
|
+
if (clip) {
|
|
34390
|
+
const clippingPlanes = this.renderer.clippingPlanes || [];
|
|
34391
|
+
clippingPlanes.forEach((plane) => {
|
|
34392
|
+
intersects = intersects.filter((intersect) => plane.distanceToPoint(intersect.point) >= 0);
|
|
34393
|
+
});
|
|
34394
|
+
}
|
|
34395
|
+
return intersects;
|
|
34396
|
+
}
|
|
34397
|
+
getDetectRadius(point) {
|
|
34398
|
+
const camera = this.camera;
|
|
34399
|
+
if (camera.isOrthographicCamera) {
|
|
34400
|
+
const fieldHeight = (camera.top - camera.bottom) / camera.zoom;
|
|
34401
|
+
const canvasHeight = this.canvas.height;
|
|
34402
|
+
const worldUnitsPerPixel = fieldHeight / canvasHeight;
|
|
34403
|
+
return this.detectRadiusInPixels * worldUnitsPerPixel;
|
|
34404
|
+
}
|
|
34405
|
+
if (camera.isPerspectiveCamera) {
|
|
34406
|
+
const distance = camera.position.distanceTo(point);
|
|
34407
|
+
const fieldHeight = 2 * Math.tan(MathUtils.degToRad(camera.fov * 0.5)) * distance;
|
|
34408
|
+
const canvasHeight = this.canvas.height;
|
|
34409
|
+
const worldUnitsPerPixel = fieldHeight / canvasHeight;
|
|
34410
|
+
return this.detectRadiusInPixels * worldUnitsPerPixel;
|
|
34411
|
+
}
|
|
34412
|
+
return 0.1;
|
|
34413
|
+
}
|
|
34414
|
+
getSnapPoint(mouse, objects) {
|
|
34415
|
+
const intersections = this.getPointerIntersects(mouse, objects);
|
|
34416
|
+
if (intersections.length === 0)
|
|
34417
|
+
return undefined;
|
|
34418
|
+
const object = intersections[0].object;
|
|
34419
|
+
const intersectionPoint = intersections[0].point;
|
|
34420
|
+
const localPoint = object.worldToLocal(intersectionPoint.clone());
|
|
34421
|
+
let snapPoint;
|
|
34422
|
+
let snapDistance = this.getDetectRadius(intersectionPoint);
|
|
34423
|
+
const geometry = object.geometry;
|
|
34424
|
+
const positions = geometry.attributes.position.array;
|
|
34425
|
+
for (let i = 0; i < positions.length; i += 3) {
|
|
34426
|
+
_vertex.set(positions[i], positions[i + 1], positions[i + 2]);
|
|
34427
|
+
const distance = _vertex.distanceTo(localPoint);
|
|
34428
|
+
if (distance < snapDistance) {
|
|
34429
|
+
snapDistance = distance;
|
|
34430
|
+
snapPoint = _vertex.clone();
|
|
34431
|
+
}
|
|
34432
|
+
}
|
|
34433
|
+
if (snapPoint)
|
|
34434
|
+
return object.localToWorld(snapPoint);
|
|
34435
|
+
let edges = this.edgesCache.get(geometry);
|
|
34436
|
+
if (!edges) {
|
|
34437
|
+
edges = new EdgesGeometry(geometry);
|
|
34438
|
+
this.edgesCache.set(geometry, edges);
|
|
34439
|
+
}
|
|
34440
|
+
const edgePositions = edges.attributes.position.array;
|
|
34441
|
+
for (let i = 0; i < edgePositions.length; i += 6) {
|
|
34442
|
+
_start$1.set(edgePositions[i], edgePositions[i + 1], edgePositions[i + 2]);
|
|
34443
|
+
_end$1.set(edgePositions[i + 3], edgePositions[i + 4], edgePositions[i + 5]);
|
|
34444
|
+
_line.set(_start$1, _end$1);
|
|
34445
|
+
_line.getCenter(_center);
|
|
34446
|
+
const centerDistance = _center.distanceTo(localPoint);
|
|
34447
|
+
if (centerDistance < snapDistance) {
|
|
34448
|
+
snapDistance = centerDistance;
|
|
34449
|
+
snapPoint = _center.clone();
|
|
34450
|
+
continue;
|
|
34451
|
+
}
|
|
34452
|
+
_line.closestPointToPoint(localPoint, true, _projection);
|
|
34453
|
+
const lineDistance = _projection.distanceTo(localPoint);
|
|
34454
|
+
if (lineDistance < snapDistance) {
|
|
34455
|
+
snapDistance = lineDistance;
|
|
34456
|
+
snapPoint = _projection.clone();
|
|
34457
|
+
}
|
|
34458
|
+
}
|
|
34459
|
+
if (snapPoint)
|
|
34460
|
+
return object.localToWorld(snapPoint);
|
|
34461
|
+
return intersectionPoint.clone();
|
|
34462
|
+
}
|
|
34463
|
+
}
|
|
34464
|
+
|
|
34340
34465
|
class OrbitDragger {
|
|
34341
34466
|
constructor(viewer) {
|
|
34342
34467
|
this.updateControls = () => {
|
|
@@ -34429,12 +34554,18 @@ void main() {
|
|
|
34429
34554
|
}
|
|
34430
34555
|
|
|
34431
34556
|
class CuttingPlaneDragger extends OrbitDragger {
|
|
34432
|
-
constructor(viewer
|
|
34557
|
+
constructor(viewer) {
|
|
34433
34558
|
super(viewer);
|
|
34559
|
+
this.helpers = [];
|
|
34560
|
+
this.activeHelper = null;
|
|
34434
34561
|
this.transformChange = () => {
|
|
34435
|
-
|
|
34436
|
-
|
|
34562
|
+
if (!this.activeHelper)
|
|
34563
|
+
return;
|
|
34564
|
+
const plane = this.activeHelper.plane;
|
|
34565
|
+
plane.normal.copy(new Vector3(0, 0, -1)).applyQuaternion(this.activeHelper.quaternion);
|
|
34566
|
+
plane.constant = -this.activeHelper.position.dot(plane.normal);
|
|
34437
34567
|
this.viewer.update();
|
|
34568
|
+
this.changed = true;
|
|
34438
34569
|
};
|
|
34439
34570
|
this.translateDrag = (event) => {
|
|
34440
34571
|
this.orbit.enabled = !event.value;
|
|
@@ -34445,45 +34576,83 @@ void main() {
|
|
|
34445
34576
|
this.translate.enabled = !event.value;
|
|
34446
34577
|
};
|
|
34447
34578
|
this.updatePlaneSize = () => {
|
|
34448
|
-
|
|
34579
|
+
const extentsSize = this.viewer.extents.getSize(new Vector3()).length() || 1;
|
|
34580
|
+
this.helpers.forEach((planeHelper) => (planeHelper.size = extentsSize));
|
|
34449
34581
|
this.viewer.update();
|
|
34450
34582
|
};
|
|
34451
34583
|
this.updateTransformCamera = () => {
|
|
34452
34584
|
this.translate.camera = this.viewer.camera;
|
|
34453
34585
|
this.rotate.camera = this.viewer.camera;
|
|
34586
|
+
this.snapper.camera = this.viewer.camera;
|
|
34587
|
+
};
|
|
34588
|
+
this.clearHelpers = () => {
|
|
34589
|
+
this.setActiveHelper();
|
|
34590
|
+
this.helpers.forEach((helper) => {
|
|
34591
|
+
helper.removeFromParent();
|
|
34592
|
+
helper.dispose();
|
|
34593
|
+
});
|
|
34594
|
+
this.helpers = [];
|
|
34595
|
+
this.viewer.update();
|
|
34454
34596
|
};
|
|
34455
34597
|
this.onKeyDown = (event) => {
|
|
34456
34598
|
if (event.key === "Shift")
|
|
34457
34599
|
this.rotate.setRotationSnap(Math.PI / 4);
|
|
34600
|
+
if (event.key === "Delete" || event.key === "Backspace")
|
|
34601
|
+
this.deleteActivePlane();
|
|
34602
|
+
if (event.key === "Escape" && (this.translate.dragging || this.rotate.dragging))
|
|
34603
|
+
this.reset();
|
|
34458
34604
|
};
|
|
34459
34605
|
this.onKeyUp = (event) => {
|
|
34460
34606
|
if (event.key === "Shift")
|
|
34461
34607
|
this.rotate.setRotationSnap(null);
|
|
34462
34608
|
};
|
|
34609
|
+
this.onPointerDown = (event) => {
|
|
34610
|
+
if (event.button !== 0 || !event.isPrimary)
|
|
34611
|
+
return;
|
|
34612
|
+
this.snapper.getMousePosition(event, this.downPosition);
|
|
34613
|
+
this.saveState();
|
|
34614
|
+
};
|
|
34615
|
+
this.onPointerUp = (event) => {
|
|
34616
|
+
if (event.button !== 0)
|
|
34617
|
+
return;
|
|
34618
|
+
const upPosition = this.snapper.getMousePosition(event, new Vector2());
|
|
34619
|
+
if (upPosition.distanceTo(this.downPosition) !== 0)
|
|
34620
|
+
return;
|
|
34621
|
+
const intersects = this.snapper.getPointerIntersects(upPosition, this.helpers, true, false);
|
|
34622
|
+
if (intersects.length === 0)
|
|
34623
|
+
return;
|
|
34624
|
+
this.setActiveHelper(intersects[0].object.parent);
|
|
34625
|
+
};
|
|
34626
|
+
this.onPointerCancel = (event) => {
|
|
34627
|
+
this.viewer.canvas.dispatchEvent(new PointerEvent("pointerup", event));
|
|
34628
|
+
};
|
|
34463
34629
|
this.onDoubleClick = (event) => {
|
|
34464
|
-
|
|
34465
|
-
|
|
34630
|
+
if (!this.activeHelper)
|
|
34631
|
+
return;
|
|
34632
|
+
const mousePosition = this.snapper.getMousePosition(event, new Vector2());
|
|
34633
|
+
const intersects = this.snapper.getPointerIntersects(mousePosition, [this.activeHelper], true, false);
|
|
34634
|
+
if (intersects.length === 0)
|
|
34635
|
+
return;
|
|
34636
|
+
this.activeHelper.rotateOnAxis(new Vector3(0, 1, 0), Math.PI);
|
|
34466
34637
|
this.transformChange();
|
|
34638
|
+
event.stopPropagation();
|
|
34467
34639
|
};
|
|
34468
|
-
const extentsSize = viewer.extents.getSize(new Vector3()).length() || 1;
|
|
34469
|
-
const extentsCenter = viewer.extents.getCenter(new Vector3());
|
|
34470
|
-
const constant = -extentsCenter.dot(normal);
|
|
34471
|
-
this.plane = new Plane(normal, constant);
|
|
34472
34640
|
if (!viewer.renderer.clippingPlanes)
|
|
34473
34641
|
viewer.renderer.clippingPlanes = [];
|
|
34474
|
-
viewer.renderer.clippingPlanes
|
|
34475
|
-
this.
|
|
34476
|
-
|
|
34477
|
-
this.
|
|
34478
|
-
this.
|
|
34479
|
-
this.
|
|
34480
|
-
this.
|
|
34642
|
+
this.clippingPlanes = viewer.renderer.clippingPlanes;
|
|
34643
|
+
this.clippingPlanes.forEach((plane) => this.addHelper(plane));
|
|
34644
|
+
const extentsSize = viewer.extents.getSize(new Vector3()).length() || 1;
|
|
34645
|
+
this.snapper = new Snapper(viewer.camera, viewer.renderer, viewer.canvas);
|
|
34646
|
+
this.snapper.threshold = extentsSize / 10000;
|
|
34647
|
+
this.downPosition = new Vector2();
|
|
34648
|
+
this.position0 = new Vector3();
|
|
34649
|
+
this.quaternion0 = new Quaternion();
|
|
34481
34650
|
this.translate = new TransformControls(viewer.camera, viewer.canvas);
|
|
34651
|
+
this.translate.setMode("translate");
|
|
34482
34652
|
this.translate.setSpace("local");
|
|
34483
34653
|
this.translate.showX = false;
|
|
34484
34654
|
this.translate.showY = false;
|
|
34485
34655
|
this.translate.showZ = true;
|
|
34486
|
-
this.translate.attach(this.planeCenter);
|
|
34487
34656
|
this.translate.addEventListener("change", this.transformChange);
|
|
34488
34657
|
this.translate.addEventListener("dragging-changed", this.translateDrag);
|
|
34489
34658
|
this.viewer.helpers.add(this.translate.getHelper());
|
|
@@ -34493,14 +34662,18 @@ void main() {
|
|
|
34493
34662
|
this.rotate.showX = true;
|
|
34494
34663
|
this.rotate.showY = true;
|
|
34495
34664
|
this.rotate.showZ = false;
|
|
34496
|
-
this.rotate.attach(this.planeCenter);
|
|
34497
34665
|
this.rotate.addEventListener("change", this.transformChange);
|
|
34498
34666
|
this.rotate.addEventListener("dragging-changed", this.rotateDrag);
|
|
34499
34667
|
this.viewer.helpers.add(this.rotate.getHelper());
|
|
34668
|
+
this.setActiveHelper(this.helpers[this.helpers.length - 1]);
|
|
34500
34669
|
this.viewer.addEventListener("explode", this.updatePlaneSize);
|
|
34501
34670
|
this.viewer.addEventListener("show", this.updatePlaneSize);
|
|
34502
34671
|
this.viewer.addEventListener("showall", this.updatePlaneSize);
|
|
34503
34672
|
this.viewer.addEventListener("changecameramode", this.updateTransformCamera);
|
|
34673
|
+
this.viewer.addEventListener("clearslices", this.clearHelpers);
|
|
34674
|
+
this.viewer.canvas.addEventListener("pointerdown", this.onPointerDown, true);
|
|
34675
|
+
this.viewer.canvas.addEventListener("pointerup", this.onPointerUp, true);
|
|
34676
|
+
this.viewer.canvas.addEventListener("pointercancel", this.onPointerCancel, true);
|
|
34504
34677
|
this.viewer.canvas.addEventListener("dblclick", this.onDoubleClick, true);
|
|
34505
34678
|
window.addEventListener("keydown", this.onKeyDown);
|
|
34506
34679
|
window.addEventListener("keyup", this.onKeyUp);
|
|
@@ -34511,6 +34684,10 @@ void main() {
|
|
|
34511
34684
|
this.viewer.removeEventListener("show", this.updatePlaneSize);
|
|
34512
34685
|
this.viewer.removeEventListener("showall", this.updatePlaneSize);
|
|
34513
34686
|
this.viewer.removeEventListener("changecameramode", this.updateTransformCamera);
|
|
34687
|
+
this.viewer.removeEventListener("clearslices", this.clearHelpers);
|
|
34688
|
+
this.viewer.canvas.removeEventListener("pointerdown", this.onPointerDown, true);
|
|
34689
|
+
this.viewer.canvas.removeEventListener("pointerup", this.onPointerUp, true);
|
|
34690
|
+
this.viewer.canvas.removeEventListener("pointercancel", this.onPointerCancel, true);
|
|
34514
34691
|
this.viewer.canvas.removeEventListener("dblclick", this.onDoubleClick, true);
|
|
34515
34692
|
window.removeEventListener("keydown", this.onKeyDown);
|
|
34516
34693
|
window.removeEventListener("keyup", this.onKeyUp);
|
|
@@ -34524,28 +34701,108 @@ void main() {
|
|
|
34524
34701
|
this.rotate.getHelper().removeFromParent();
|
|
34525
34702
|
this.rotate.detach();
|
|
34526
34703
|
this.rotate.dispose();
|
|
34527
|
-
this.
|
|
34528
|
-
|
|
34529
|
-
|
|
34704
|
+
this.helpers.forEach((helper) => {
|
|
34705
|
+
helper.removeFromParent();
|
|
34706
|
+
helper.dispose();
|
|
34707
|
+
});
|
|
34708
|
+
this.helpers = [];
|
|
34709
|
+
this.activeHelper = null;
|
|
34530
34710
|
super.dispose();
|
|
34531
34711
|
}
|
|
34712
|
+
addHelper(plane) {
|
|
34713
|
+
const extentsSize = this.viewer.extents.getSize(new Vector3()).length() || 1;
|
|
34714
|
+
const extentsCenter = this.viewer.extents.getCenter(new Vector3());
|
|
34715
|
+
const helper = new PlaneHelper2(extentsSize);
|
|
34716
|
+
helper.plane = plane;
|
|
34717
|
+
helper.position.copy(plane.projectPoint(extentsCenter, new Vector3()));
|
|
34718
|
+
helper.quaternion.setFromUnitVectors(new Vector3(0, 0, -1), plane.normal);
|
|
34719
|
+
this.helpers.push(helper);
|
|
34720
|
+
this.viewer.helpers.add(helper);
|
|
34721
|
+
return helper;
|
|
34722
|
+
}
|
|
34723
|
+
setActiveHelper(helper) {
|
|
34724
|
+
if (helper === this.activeHelper)
|
|
34725
|
+
return;
|
|
34726
|
+
if (this.activeHelper) {
|
|
34727
|
+
this.activeHelper.getLineMaterial().color.setHex(0xf0f0f0);
|
|
34728
|
+
this.activeHelper.getMeshMaterial().opacity = 0.15;
|
|
34729
|
+
this.translate.detach();
|
|
34730
|
+
this.rotate.detach();
|
|
34731
|
+
}
|
|
34732
|
+
this.activeHelper = helper;
|
|
34733
|
+
if (this.activeHelper) {
|
|
34734
|
+
this.activeHelper.getLineMaterial().color.setHex(0xd0d0d0);
|
|
34735
|
+
this.activeHelper.getMeshMaterial().opacity = 0.3;
|
|
34736
|
+
this.translate.attach(this.activeHelper);
|
|
34737
|
+
this.rotate.attach(this.activeHelper);
|
|
34738
|
+
}
|
|
34739
|
+
this.viewer.update();
|
|
34740
|
+
}
|
|
34741
|
+
saveState() {
|
|
34742
|
+
if (!this.activeHelper)
|
|
34743
|
+
return;
|
|
34744
|
+
this.position0.copy(this.activeHelper.position);
|
|
34745
|
+
this.quaternion0.copy(this.activeHelper.quaternion);
|
|
34746
|
+
}
|
|
34747
|
+
reset() {
|
|
34748
|
+
if (!this.activeHelper)
|
|
34749
|
+
return;
|
|
34750
|
+
this.translate.dragging = false;
|
|
34751
|
+
this.rotate.dragging = false;
|
|
34752
|
+
this.orbit.state = STATE.NONE;
|
|
34753
|
+
this.activeHelper.position.copy(this.position0);
|
|
34754
|
+
this.activeHelper.quaternion.copy(this.quaternion0);
|
|
34755
|
+
this.transformChange();
|
|
34756
|
+
}
|
|
34757
|
+
addPlane(normal) {
|
|
34758
|
+
const extentsCenter = this.viewer.extents.getCenter(new Vector3());
|
|
34759
|
+
const constant = -extentsCenter.dot(normal);
|
|
34760
|
+
const plane = new Plane(normal, constant);
|
|
34761
|
+
this.clippingPlanes.push(plane);
|
|
34762
|
+
const helper = this.addHelper(plane);
|
|
34763
|
+
this.setActiveHelper(helper);
|
|
34764
|
+
}
|
|
34765
|
+
addPlaneX() {
|
|
34766
|
+
this.addPlane(new Vector3(-1, 0, 0));
|
|
34767
|
+
}
|
|
34768
|
+
addPlaneY() {
|
|
34769
|
+
this.addPlane(new Vector3(0, -1, 0));
|
|
34770
|
+
}
|
|
34771
|
+
addPlaneZ() {
|
|
34772
|
+
this.addPlane(new Vector3(0, 0, -1));
|
|
34773
|
+
}
|
|
34774
|
+
deleteActivePlane() {
|
|
34775
|
+
if (!this.activeHelper)
|
|
34776
|
+
return;
|
|
34777
|
+
const helper = this.activeHelper;
|
|
34778
|
+
const index = this.clippingPlanes.indexOf(helper.plane);
|
|
34779
|
+
if (index !== -1)
|
|
34780
|
+
this.clippingPlanes.splice(index, 1);
|
|
34781
|
+
this.helpers = this.helpers.filter((x) => x !== helper);
|
|
34782
|
+
helper.removeFromParent();
|
|
34783
|
+
helper.dispose();
|
|
34784
|
+
this.setActiveHelper(this.helpers[this.helpers.length - 1]);
|
|
34785
|
+
}
|
|
34532
34786
|
}
|
|
34533
34787
|
|
|
34534
34788
|
class CuttingPlaneXAxisDragger extends CuttingPlaneDragger {
|
|
34535
34789
|
constructor(viewer) {
|
|
34536
|
-
super(viewer
|
|
34790
|
+
super(viewer);
|
|
34791
|
+
this.addPlaneX();
|
|
34537
34792
|
}
|
|
34538
34793
|
}
|
|
34539
34794
|
|
|
34540
34795
|
class CuttingPlaneYAxisDragger extends CuttingPlaneDragger {
|
|
34541
34796
|
constructor(viewer) {
|
|
34542
|
-
super(viewer
|
|
34797
|
+
super(viewer);
|
|
34798
|
+
this.addPlaneY();
|
|
34543
34799
|
}
|
|
34544
34800
|
}
|
|
34545
34801
|
|
|
34546
34802
|
class CuttingPlaneZAxisDragger extends CuttingPlaneDragger {
|
|
34547
34803
|
constructor(viewer) {
|
|
34548
|
-
super(viewer
|
|
34804
|
+
super(viewer);
|
|
34805
|
+
this.addPlaneZ();
|
|
34549
34806
|
}
|
|
34550
34807
|
}
|
|
34551
34808
|
|
|
@@ -34622,120 +34879,6 @@ void main() {
|
|
|
34622
34879
|
}
|
|
34623
34880
|
}
|
|
34624
34881
|
|
|
34625
|
-
const DESKTOP_SNAP_DISTANCE = 10;
|
|
34626
|
-
const MOBILE_SNAP_DISTANCE = 50;
|
|
34627
|
-
const _vertex = new Vector3();
|
|
34628
|
-
const _start$1 = new Vector3();
|
|
34629
|
-
const _end$1 = new Vector3();
|
|
34630
|
-
const _line = new Line3();
|
|
34631
|
-
const _center = new Vector3();
|
|
34632
|
-
const _projection = new Vector3();
|
|
34633
|
-
class Snapper {
|
|
34634
|
-
constructor(camera, renderer, canvas) {
|
|
34635
|
-
this.camera = camera;
|
|
34636
|
-
this.renderer = renderer;
|
|
34637
|
-
this.canvas = canvas;
|
|
34638
|
-
this.threshold = 0.0001;
|
|
34639
|
-
this.raycaster = new Raycaster();
|
|
34640
|
-
this.detectRadiusInPixels = this.isMobile() ? MOBILE_SNAP_DISTANCE : DESKTOP_SNAP_DISTANCE;
|
|
34641
|
-
this.edgesCache = new WeakMap();
|
|
34642
|
-
}
|
|
34643
|
-
isMobile() {
|
|
34644
|
-
if (typeof navigator === "undefined")
|
|
34645
|
-
return false;
|
|
34646
|
-
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent);
|
|
34647
|
-
}
|
|
34648
|
-
getMousePosition(event, target) {
|
|
34649
|
-
return target.set(event.clientX, event.clientY);
|
|
34650
|
-
}
|
|
34651
|
-
getPointerIntersects(mouse, objects) {
|
|
34652
|
-
const rect = this.canvas.getBoundingClientRect();
|
|
34653
|
-
const x = ((mouse.x - rect.left) / rect.width) * 2 - 1;
|
|
34654
|
-
const y = (-(mouse.y - rect.top) / rect.height) * 2 + 1;
|
|
34655
|
-
const coords = new Vector2(x, y);
|
|
34656
|
-
this.raycaster.setFromCamera(coords, this.camera);
|
|
34657
|
-
this.raycaster.params = {
|
|
34658
|
-
Mesh: {},
|
|
34659
|
-
Line: { threshold: this.threshold },
|
|
34660
|
-
Line2: { threshold: this.threshold },
|
|
34661
|
-
LOD: {},
|
|
34662
|
-
Points: { threshold: this.threshold },
|
|
34663
|
-
Sprite: {},
|
|
34664
|
-
};
|
|
34665
|
-
let intersects = this.raycaster.intersectObjects(objects, false);
|
|
34666
|
-
(this.renderer.clippingPlanes || []).forEach((plane) => {
|
|
34667
|
-
intersects = intersects.filter((intersect) => plane.distanceToPoint(intersect.point) >= 0);
|
|
34668
|
-
});
|
|
34669
|
-
return intersects;
|
|
34670
|
-
}
|
|
34671
|
-
getDetectRadius(point) {
|
|
34672
|
-
const camera = this.camera;
|
|
34673
|
-
if (camera.isOrthographicCamera) {
|
|
34674
|
-
const fieldHeight = (camera.top - camera.bottom) / camera.zoom;
|
|
34675
|
-
const canvasHeight = this.canvas.height;
|
|
34676
|
-
const worldUnitsPerPixel = fieldHeight / canvasHeight;
|
|
34677
|
-
return this.detectRadiusInPixels * worldUnitsPerPixel;
|
|
34678
|
-
}
|
|
34679
|
-
if (camera.isPerspectiveCamera) {
|
|
34680
|
-
const distance = camera.position.distanceTo(point);
|
|
34681
|
-
const fieldHeight = 2 * Math.tan(MathUtils.degToRad(camera.fov * 0.5)) * distance;
|
|
34682
|
-
const canvasHeight = this.canvas.height;
|
|
34683
|
-
const worldUnitsPerPixel = fieldHeight / canvasHeight;
|
|
34684
|
-
return this.detectRadiusInPixels * worldUnitsPerPixel;
|
|
34685
|
-
}
|
|
34686
|
-
return 0.1;
|
|
34687
|
-
}
|
|
34688
|
-
getSnapPoint(mouse, objects) {
|
|
34689
|
-
const intersections = this.getPointerIntersects(mouse, objects);
|
|
34690
|
-
if (intersections.length === 0)
|
|
34691
|
-
return undefined;
|
|
34692
|
-
const object = intersections[0].object;
|
|
34693
|
-
const intersectionPoint = intersections[0].point;
|
|
34694
|
-
const localPoint = object.worldToLocal(intersectionPoint.clone());
|
|
34695
|
-
let snapPoint;
|
|
34696
|
-
let snapDistance = this.getDetectRadius(intersectionPoint);
|
|
34697
|
-
const geometry = object.geometry;
|
|
34698
|
-
const positions = geometry.attributes.position.array;
|
|
34699
|
-
for (let i = 0; i < positions.length; i += 3) {
|
|
34700
|
-
_vertex.set(positions[i], positions[i + 1], positions[i + 2]);
|
|
34701
|
-
const distance = _vertex.distanceTo(localPoint);
|
|
34702
|
-
if (distance < snapDistance) {
|
|
34703
|
-
snapDistance = distance;
|
|
34704
|
-
snapPoint = _vertex.clone();
|
|
34705
|
-
}
|
|
34706
|
-
}
|
|
34707
|
-
if (snapPoint)
|
|
34708
|
-
return object.localToWorld(snapPoint);
|
|
34709
|
-
let edges = this.edgesCache.get(geometry);
|
|
34710
|
-
if (!edges) {
|
|
34711
|
-
edges = new EdgesGeometry(geometry);
|
|
34712
|
-
this.edgesCache.set(geometry, edges);
|
|
34713
|
-
}
|
|
34714
|
-
const edgePositions = edges.attributes.position.array;
|
|
34715
|
-
for (let i = 0; i < edgePositions.length; i += 6) {
|
|
34716
|
-
_start$1.set(edgePositions[i], edgePositions[i + 1], edgePositions[i + 2]);
|
|
34717
|
-
_end$1.set(edgePositions[i + 3], edgePositions[i + 4], edgePositions[i + 5]);
|
|
34718
|
-
_line.set(_start$1, _end$1);
|
|
34719
|
-
_line.getCenter(_center);
|
|
34720
|
-
const centerDistance = _center.distanceTo(localPoint);
|
|
34721
|
-
if (centerDistance < snapDistance) {
|
|
34722
|
-
snapDistance = centerDistance;
|
|
34723
|
-
snapPoint = _center.clone();
|
|
34724
|
-
continue;
|
|
34725
|
-
}
|
|
34726
|
-
_line.closestPointToPoint(localPoint, true, _projection);
|
|
34727
|
-
const lineDistance = _projection.distanceTo(localPoint);
|
|
34728
|
-
if (lineDistance < snapDistance) {
|
|
34729
|
-
snapDistance = lineDistance;
|
|
34730
|
-
snapPoint = _projection.clone();
|
|
34731
|
-
}
|
|
34732
|
-
}
|
|
34733
|
-
if (snapPoint)
|
|
34734
|
-
return object.localToWorld(snapPoint);
|
|
34735
|
-
return intersectionPoint.clone();
|
|
34736
|
-
}
|
|
34737
|
-
}
|
|
34738
|
-
|
|
34739
34882
|
const _downPoint = new Vector2();
|
|
34740
34883
|
class MeasureLineDragger extends OrbitDragger {
|
|
34741
34884
|
constructor(viewer) {
|
|
@@ -35219,14 +35362,20 @@ void main() {
|
|
|
35219
35362
|
}
|
|
35220
35363
|
};
|
|
35221
35364
|
this.onKeyUp = (event) => {
|
|
35222
|
-
if (this.moveKeys.delete(event.code))
|
|
35365
|
+
if (this.moveKeys.delete(event.code)) {
|
|
35366
|
+
if (this.moveKeys.size === 0) {
|
|
35367
|
+
this._rebuildGroundBox(this.object.position);
|
|
35368
|
+
}
|
|
35223
35369
|
this.update();
|
|
35370
|
+
}
|
|
35224
35371
|
};
|
|
35225
35372
|
this.camera = camera;
|
|
35226
35373
|
this.groundObjects = groundObjects;
|
|
35227
35374
|
for (const obj of groundObjects) {
|
|
35228
35375
|
this._groundObjectBoxes.set(obj, new Box3().setFromObject(obj));
|
|
35229
35376
|
}
|
|
35377
|
+
const pos = this.object.position;
|
|
35378
|
+
this._rebuildGroundBox(pos);
|
|
35230
35379
|
this.raycaster = new Raycaster();
|
|
35231
35380
|
this.raycaster.near = 0;
|
|
35232
35381
|
this.raycaster.far = this.EYE_HEIGHT + this.FAILING_DISTANCE;
|
|
@@ -35835,6 +35984,7 @@ void main() {
|
|
|
35835
35984
|
draggers.registerDragger("Orbit", (viewer) => new OrbitDragger(viewer));
|
|
35836
35985
|
draggers.registerDragger("Zoom", (viewer) => new ZoomDragger(viewer));
|
|
35837
35986
|
draggers.registerDragger("MeasureLine", (viewer) => new MeasureLineDragger(viewer));
|
|
35987
|
+
draggers.registerDragger("CuttingPlane", (viewer) => new CuttingPlaneDragger(viewer));
|
|
35838
35988
|
draggers.registerDragger("CuttingPlaneXAxis", (viewer) => new CuttingPlaneXAxisDragger(viewer));
|
|
35839
35989
|
draggers.registerDragger("CuttingPlaneYAxis", (viewer) => new CuttingPlaneYAxisDragger(viewer));
|
|
35840
35990
|
draggers.registerDragger("CuttingPlaneZAxis", (viewer) => new CuttingPlaneZAxisDragger(viewer));
|
|
@@ -37369,7 +37519,7 @@ void main() {
|
|
|
37369
37519
|
this.getMousePosition(event, this.downPosition);
|
|
37370
37520
|
};
|
|
37371
37521
|
this.onPointerUp = (event) => {
|
|
37372
|
-
if (!event.isPrimary)
|
|
37522
|
+
if (!event.isPrimary || event.button !== 0)
|
|
37373
37523
|
return;
|
|
37374
37524
|
const upPosition = this.getMousePosition(event, new Vector2());
|
|
37375
37525
|
if (upPosition.distanceTo(this.downPosition) !== 0)
|
|
@@ -37898,19 +38048,19 @@ void main() {
|
|
|
37898
38048
|
return this;
|
|
37899
38049
|
}
|
|
37900
38050
|
explode(scale = 0, coeff = 4) {
|
|
37901
|
-
const
|
|
37902
|
-
const
|
|
38051
|
+
const centersCache = new Map();
|
|
38052
|
+
const calcObjectCenter = (object, target) => {
|
|
37903
38053
|
const extents = new Box3().setFromObject(object);
|
|
37904
38054
|
const handle = object.userData.handle;
|
|
37905
38055
|
if (!handle)
|
|
37906
38056
|
return extents.getCenter(target);
|
|
37907
|
-
const center =
|
|
38057
|
+
const center = centersCache.get(handle);
|
|
37908
38058
|
if (center)
|
|
37909
38059
|
return target.copy(center);
|
|
37910
38060
|
const objects = this.getObjectsByHandles(handle);
|
|
37911
38061
|
objects.forEach((x) => extents.expandByObject(x));
|
|
37912
38062
|
extents.getCenter(target);
|
|
37913
|
-
|
|
38063
|
+
centersCache.set(handle, target.clone());
|
|
37914
38064
|
return target;
|
|
37915
38065
|
};
|
|
37916
38066
|
function calcExplodeDepth(object, depth) {
|
|
@@ -37921,13 +38071,14 @@ void main() {
|
|
|
37921
38071
|
result = objectDepth;
|
|
37922
38072
|
});
|
|
37923
38073
|
object.userData.originalPosition = object.position.clone();
|
|
37924
|
-
object.userData.originalCenter =
|
|
38074
|
+
object.userData.originalCenter = calcObjectCenter(object, new Vector3());
|
|
37925
38075
|
return result;
|
|
37926
38076
|
}
|
|
37927
38077
|
const explodeScale = scale / 100;
|
|
37928
38078
|
const explodeRoot = this.scene;
|
|
37929
|
-
if (!explodeRoot.userData.explodeDepth)
|
|
38079
|
+
if (!explodeRoot.userData.explodeDepth) {
|
|
37930
38080
|
explodeRoot.userData.explodeDepth = calcExplodeDepth(explodeRoot, 1);
|
|
38081
|
+
}
|
|
37931
38082
|
const maxDepth = explodeRoot.userData.explodeDepth;
|
|
37932
38083
|
const scaledExplodeDepth = explodeScale * maxDepth + 1;
|
|
37933
38084
|
const explodeDepth = 0 | scaledExplodeDepth;
|
|
@@ -37944,8 +38095,8 @@ void main() {
|
|
|
37944
38095
|
objectScale *= currentSegmentFraction;
|
|
37945
38096
|
const parentCenter = object.parent.userData.originalCenter;
|
|
37946
38097
|
const objectCenter = object.userData.originalCenter;
|
|
37947
|
-
const
|
|
37948
|
-
object.position.add(
|
|
38098
|
+
const localOffset = objectCenter.clone().sub(parentCenter).multiplyScalar(objectScale);
|
|
38099
|
+
object.position.add(localOffset);
|
|
37949
38100
|
}
|
|
37950
38101
|
object.children.forEach((x) => explodeObject(x, depth + 1));
|
|
37951
38102
|
}
|
|
@@ -38037,67 +38188,73 @@ void main() {
|
|
|
38037
38188
|
return this;
|
|
38038
38189
|
}
|
|
38039
38190
|
explode(scale = 0, coeff = 4) {
|
|
38040
|
-
const
|
|
38191
|
+
const centersCache = new Map();
|
|
38041
38192
|
const calcObjectCenter = (object, target) => {
|
|
38042
38193
|
const extents = new Box3().setFromObject(object);
|
|
38043
38194
|
const handle = object.userData.handle;
|
|
38044
38195
|
if (!handle)
|
|
38045
38196
|
return extents.getCenter(target);
|
|
38046
|
-
const center =
|
|
38197
|
+
const center = centersCache.get(handle);
|
|
38047
38198
|
if (center)
|
|
38048
38199
|
return target.copy(center);
|
|
38049
38200
|
const objects = this.getObjectsByHandles(handle);
|
|
38050
38201
|
objects.forEach((x) => extents.expandByObject(x));
|
|
38051
38202
|
extents.getCenter(target);
|
|
38052
|
-
|
|
38203
|
+
centersCache.set(handle, target.clone());
|
|
38053
38204
|
return target;
|
|
38054
38205
|
};
|
|
38055
|
-
|
|
38056
|
-
|
|
38057
|
-
|
|
38058
|
-
|
|
38059
|
-
|
|
38060
|
-
|
|
38061
|
-
if (result < objectDepth)
|
|
38062
|
-
result = objectDepth;
|
|
38063
|
-
});
|
|
38206
|
+
const calcObjectDepth = (object) => {
|
|
38207
|
+
if (object.userData.depth !== undefined)
|
|
38208
|
+
return object.userData.depth;
|
|
38209
|
+
const parent = object.parent;
|
|
38210
|
+
const depth = parent && object !== explodeRoot ? calcObjectDepth(parent) + 1 : 0;
|
|
38211
|
+
object.userData.depth = depth;
|
|
38064
38212
|
object.userData.originalPosition = object.position.clone();
|
|
38065
38213
|
object.userData.originalCenter = calcObjectCenter(object, new Vector3());
|
|
38066
|
-
return
|
|
38067
|
-
}
|
|
38214
|
+
return depth;
|
|
38215
|
+
};
|
|
38068
38216
|
const explodeScale = scale / 100;
|
|
38069
38217
|
const explodeRoot = this.scene.children[0];
|
|
38070
|
-
if (!explodeRoot.userData.explodeDepth)
|
|
38071
|
-
|
|
38218
|
+
if (!explodeRoot.userData.explodeDepth) {
|
|
38219
|
+
let maxDepth = 0;
|
|
38220
|
+
this.gltfLoader.originalObjects.forEach((object) => {
|
|
38221
|
+
const depth = calcObjectDepth(object);
|
|
38222
|
+
if (depth > maxDepth)
|
|
38223
|
+
maxDepth = depth;
|
|
38224
|
+
});
|
|
38225
|
+
explodeRoot.userData.explodeDepth = maxDepth;
|
|
38226
|
+
}
|
|
38072
38227
|
const maxDepth = explodeRoot.userData.explodeDepth;
|
|
38073
38228
|
const scaledExplodeDepth = explodeScale * maxDepth + 1;
|
|
38074
38229
|
const explodeDepth = 0 | scaledExplodeDepth;
|
|
38075
38230
|
const currentSegmentFraction = scaledExplodeDepth - explodeDepth;
|
|
38076
|
-
const
|
|
38077
|
-
|
|
38078
|
-
if (object
|
|
38079
|
-
return;
|
|
38080
|
-
|
|
38081
|
-
|
|
38082
|
-
|
|
38083
|
-
|
|
38231
|
+
const offsetCache = new Map();
|
|
38232
|
+
const calcObjectOffset = (object, target) => {
|
|
38233
|
+
if (offsetCache.has(object))
|
|
38234
|
+
return target.copy(offsetCache.get(object));
|
|
38235
|
+
const parent = object.parent;
|
|
38236
|
+
if (parent && object !== explodeRoot)
|
|
38237
|
+
calcObjectOffset(parent, target);
|
|
38238
|
+
const depth = object.userData.depth;
|
|
38239
|
+
if (depth > 0 && depth <= explodeDepth) {
|
|
38084
38240
|
let objectScale = explodeScale * coeff;
|
|
38085
38241
|
if (depth === explodeDepth)
|
|
38086
38242
|
objectScale *= currentSegmentFraction;
|
|
38087
|
-
const parentCenter =
|
|
38243
|
+
const parentCenter = parent.userData.originalCenter;
|
|
38088
38244
|
const objectCenter = object.userData.originalCenter;
|
|
38089
|
-
const
|
|
38090
|
-
|
|
38091
|
-
const matrix = new Matrix4().makeTranslation(objectOffset.x, objectOffset.y, objectOffset.z);
|
|
38092
|
-
transformMap.set(object, matrix);
|
|
38245
|
+
const localOffset = objectCenter.clone().sub(parentCenter).multiplyScalar(objectScale);
|
|
38246
|
+
target.add(localOffset);
|
|
38093
38247
|
}
|
|
38094
|
-
object.
|
|
38095
|
-
|
|
38096
|
-
|
|
38097
|
-
|
|
38098
|
-
|
|
38099
|
-
|
|
38248
|
+
offsetCache.set(object, target.clone());
|
|
38249
|
+
return target;
|
|
38250
|
+
};
|
|
38251
|
+
const transformMap = new Map();
|
|
38252
|
+
this.gltfLoader.originalObjects.forEach((object) => {
|
|
38253
|
+
const globalOffset = calcObjectOffset(object, new Vector3());
|
|
38254
|
+
transformMap.set(object, new Matrix4().makeTranslation(globalOffset));
|
|
38255
|
+
});
|
|
38100
38256
|
this.gltfLoader.applyObjectTransforms(transformMap);
|
|
38257
|
+
this.scene.updateMatrixWorld();
|
|
38101
38258
|
return this;
|
|
38102
38259
|
}
|
|
38103
38260
|
}
|
|
@@ -38823,6 +38980,8 @@ void main() {
|
|
|
38823
38980
|
this.oldOptimizeObjects = new Set();
|
|
38824
38981
|
this.objectTransforms = new Map();
|
|
38825
38982
|
this.transformedGeometries = new Map();
|
|
38983
|
+
this.syncTransformsToOriginalObjects = true;
|
|
38984
|
+
this._originalObjectMatrices = new Map();
|
|
38826
38985
|
this.activeChunkLoads = 0;
|
|
38827
38986
|
this.chunkQueue = [];
|
|
38828
38987
|
this.objectIdToIndex = new Map();
|
|
@@ -38832,6 +38991,81 @@ void main() {
|
|
|
38832
38991
|
this.mergedObjectMap = new Map();
|
|
38833
38992
|
this.mergedGeometryVisibility = new Map();
|
|
38834
38993
|
this._webglInfoCache = null;
|
|
38994
|
+
this.transformTextureSize = 1024;
|
|
38995
|
+
this.transformTexture = this.createDummyTexture();
|
|
38996
|
+
this.transformData = null;
|
|
38997
|
+
this.identityTransformData = null;
|
|
38998
|
+
this.visibilityMaterials = new Set();
|
|
38999
|
+
}
|
|
39000
|
+
createDummyTexture() {
|
|
39001
|
+
const data = new Float32Array(16);
|
|
39002
|
+
const identity = new Matrix4();
|
|
39003
|
+
identity.toArray(data);
|
|
39004
|
+
const dummyData = new Float32Array(16);
|
|
39005
|
+
identity.toArray(dummyData);
|
|
39006
|
+
const dummyTexture = new DataTexture(dummyData, 4, 1, RGBAFormat, FloatType);
|
|
39007
|
+
dummyTexture.minFilter = NearestFilter;
|
|
39008
|
+
dummyTexture.magFilter = NearestFilter;
|
|
39009
|
+
dummyTexture.needsUpdate = true;
|
|
39010
|
+
return dummyTexture;
|
|
39011
|
+
}
|
|
39012
|
+
initTransformTexture() {
|
|
39013
|
+
if (this.transformTexture) {
|
|
39014
|
+
this.transformTexture.dispose();
|
|
39015
|
+
}
|
|
39016
|
+
const maxInstanceCount = this.maxObjectId + 1;
|
|
39017
|
+
let size = Math.sqrt(maxInstanceCount * 4);
|
|
39018
|
+
size = Math.ceil(size / 4) * 4;
|
|
39019
|
+
size = Math.max(size, 4);
|
|
39020
|
+
this.transformTextureSize = size;
|
|
39021
|
+
const arraySize = size * size * 4;
|
|
39022
|
+
this.transformData = new Float32Array(arraySize);
|
|
39023
|
+
this.identityTransformData = new Float32Array(arraySize);
|
|
39024
|
+
for (let i = 0; i <= this.maxObjectId; i++) {
|
|
39025
|
+
const base = i * 16;
|
|
39026
|
+
if (base + 15 < arraySize) {
|
|
39027
|
+
this.identityTransformData[base + 0] = 1;
|
|
39028
|
+
this.identityTransformData[base + 5] = 1;
|
|
39029
|
+
this.identityTransformData[base + 10] = 1;
|
|
39030
|
+
this.identityTransformData[base + 15] = 1;
|
|
39031
|
+
}
|
|
39032
|
+
}
|
|
39033
|
+
this._resetTransformData(false);
|
|
39034
|
+
this.transformTexture = new DataTexture(this.transformData, size, size, RGBAFormat, FloatType);
|
|
39035
|
+
this.transformTexture.needsUpdate = true;
|
|
39036
|
+
this.transformTexture.generateMipmaps = false;
|
|
39037
|
+
console.log(`Initialized transform texture: ${size}x${size} for ${maxInstanceCount} objects`);
|
|
39038
|
+
this.updateMaterialUniforms();
|
|
39039
|
+
this.visibilityMaterials.forEach((material) => {
|
|
39040
|
+
material.needsUpdate = true;
|
|
39041
|
+
});
|
|
39042
|
+
}
|
|
39043
|
+
_resetTransformData(updateTexture = true) {
|
|
39044
|
+
if (!this.transformData || !this.identityTransformData) return;
|
|
39045
|
+
this.transformData.set(this.identityTransformData);
|
|
39046
|
+
if (updateTexture) {
|
|
39047
|
+
this.updateTransformTexture();
|
|
39048
|
+
}
|
|
39049
|
+
}
|
|
39050
|
+
updateMaterialUniforms() {
|
|
39051
|
+
if (
|
|
39052
|
+
this._lastTransformTexture === this.transformTexture &&
|
|
39053
|
+
this._lastTransformTextureSize === this.transformTextureSize
|
|
39054
|
+
) {
|
|
39055
|
+
return;
|
|
39056
|
+
}
|
|
39057
|
+
this._lastTransformTexture = this.transformTexture;
|
|
39058
|
+
this._lastTransformTextureSize = this.transformTextureSize;
|
|
39059
|
+
this.visibilityMaterials.forEach((material) => {
|
|
39060
|
+
if (material.userData && material.userData.visibilityUniforms) {
|
|
39061
|
+
material.userData.visibilityUniforms.transformTexture.value = this.transformTexture;
|
|
39062
|
+
material.userData.visibilityUniforms.transformTextureSize.value = this.transformTextureSize;
|
|
39063
|
+
}
|
|
39064
|
+
});
|
|
39065
|
+
}
|
|
39066
|
+
updateTransformTexture() {
|
|
39067
|
+
if (!this.transformTexture) return;
|
|
39068
|
+
this.transformTexture.needsUpdate = true;
|
|
38835
39069
|
}
|
|
38836
39070
|
setVisibleEdges(visible) {
|
|
38837
39071
|
this.visibleEdges = visible;
|
|
@@ -39721,36 +39955,82 @@ void main() {
|
|
|
39721
39955
|
}
|
|
39722
39956
|
}
|
|
39723
39957
|
createVisibilityMaterial(material) {
|
|
39958
|
+
this.visibilityMaterials.add(material);
|
|
39959
|
+
const uniforms = {
|
|
39960
|
+
transformTexture: { value: this.transformTexture },
|
|
39961
|
+
transformTextureSize: { value: this.transformTextureSize },
|
|
39962
|
+
};
|
|
39963
|
+
material.userData.visibilityUniforms = uniforms;
|
|
39724
39964
|
material.onBeforeCompile = (shader) => {
|
|
39965
|
+
shader.uniforms.transformTexture = uniforms.transformTexture;
|
|
39966
|
+
shader.uniforms.transformTextureSize = uniforms.transformTextureSize;
|
|
39725
39967
|
shader.vertexShader = shader.vertexShader.replace(
|
|
39726
39968
|
"#include <common>",
|
|
39727
39969
|
`
|
|
39728
39970
|
#include <common>
|
|
39971
|
+
|
|
39729
39972
|
attribute float visibility;
|
|
39973
|
+
attribute float objectId;
|
|
39730
39974
|
varying float vVisibility;
|
|
39731
|
-
|
|
39732
|
-
|
|
39733
|
-
|
|
39734
|
-
|
|
39735
|
-
|
|
39736
|
-
|
|
39737
|
-
|
|
39975
|
+
uniform highp sampler2D transformTexture;
|
|
39976
|
+
uniform float transformTextureSize;
|
|
39977
|
+
|
|
39978
|
+
mat4 getTransformMatrix(float instanceId) {
|
|
39979
|
+
int size = int(transformTextureSize);
|
|
39980
|
+
int index = int(instanceId) * 4;
|
|
39981
|
+
|
|
39982
|
+
int x0 = index % size;
|
|
39983
|
+
int y0 = index / size;
|
|
39984
|
+
|
|
39985
|
+
vec4 row0 = texelFetch(transformTexture, ivec2(x0, y0), 0);
|
|
39986
|
+
vec4 row1 = texelFetch(transformTexture, ivec2(x0 + 1, y0), 0);
|
|
39987
|
+
vec4 row2 = texelFetch(transformTexture, ivec2(x0 + 2, y0), 0);
|
|
39988
|
+
vec4 row3 = texelFetch(transformTexture, ivec2(x0 + 3, y0), 0);
|
|
39989
|
+
|
|
39990
|
+
return mat4(row0, row1, row2, row3);
|
|
39991
|
+
}
|
|
39738
39992
|
`
|
|
39739
39993
|
);
|
|
39740
39994
|
shader.vertexShader = shader.vertexShader.replace(
|
|
39741
39995
|
"void main() {",
|
|
39742
39996
|
`
|
|
39743
39997
|
void main() {
|
|
39744
|
-
|
|
39998
|
+
mat4 batchingMatrix = getTransformMatrix(objectId);
|
|
39999
|
+
vVisibility = visibility;
|
|
39745
40000
|
`
|
|
39746
40001
|
);
|
|
39747
|
-
|
|
39748
|
-
|
|
40002
|
+
if (shader.vertexShader.includes("#include <beginnormal_vertex>")) {
|
|
40003
|
+
shader.vertexShader = shader.vertexShader.replace(
|
|
40004
|
+
"#include <beginnormal_vertex>",
|
|
40005
|
+
`
|
|
40006
|
+
vec3 objectNormal = vec3( normal );
|
|
40007
|
+
mat3 bm = mat3( batchingMatrix );
|
|
40008
|
+
objectNormal = bm * objectNormal;
|
|
40009
|
+
`
|
|
40010
|
+
);
|
|
40011
|
+
}
|
|
40012
|
+
shader.vertexShader = shader.vertexShader.replace(
|
|
40013
|
+
"#include <begin_vertex>",
|
|
39749
40014
|
`
|
|
40015
|
+
vec3 transformed = vec3( position );
|
|
40016
|
+
transformed = ( batchingMatrix * vec4( transformed, 1.0 ) ).xyz;
|
|
40017
|
+
`
|
|
40018
|
+
);
|
|
40019
|
+
shader.fragmentShader = shader.fragmentShader
|
|
40020
|
+
.replace(
|
|
40021
|
+
"#include <common>",
|
|
40022
|
+
`
|
|
40023
|
+
#include <common>
|
|
40024
|
+
varying float vVisibility;
|
|
40025
|
+
`
|
|
40026
|
+
)
|
|
40027
|
+
.replace(
|
|
40028
|
+
"void main() {",
|
|
40029
|
+
`
|
|
39750
40030
|
void main() {
|
|
39751
40031
|
if (vVisibility < 0.5) discard;
|
|
39752
40032
|
`
|
|
39753
|
-
|
|
40033
|
+
);
|
|
39754
40034
|
};
|
|
39755
40035
|
material.needsUpdate = true;
|
|
39756
40036
|
return material;
|
|
@@ -39856,6 +40136,7 @@ void main() {
|
|
|
39856
40136
|
this.isolatedObjects = [];
|
|
39857
40137
|
this.objectTransforms.clear();
|
|
39858
40138
|
this.transformedGeometries.clear();
|
|
40139
|
+
this._originalObjectMatrices.clear();
|
|
39859
40140
|
this.totalLoadedObjects = 0;
|
|
39860
40141
|
this.currentMemoryUsage = 0;
|
|
39861
40142
|
this.pendingMemoryUsage = 0;
|
|
@@ -39865,6 +40146,8 @@ void main() {
|
|
|
39865
40146
|
this.objectIdToIndex.clear();
|
|
39866
40147
|
this.maxObjectId = 0;
|
|
39867
40148
|
this.objectVisibility = new Float32Array();
|
|
40149
|
+
this.meshToNodeMap = null;
|
|
40150
|
+
this.visibilityMaterials.clear();
|
|
39868
40151
|
}
|
|
39869
40152
|
setStructureTransform(structureId, matrix) {
|
|
39870
40153
|
const rootGroup = this.structureRoots.get(structureId);
|
|
@@ -39980,12 +40263,15 @@ void main() {
|
|
|
39980
40263
|
});
|
|
39981
40264
|
this.originalObjects.clear();
|
|
39982
40265
|
this.originalObjectsToSelection.clear();
|
|
40266
|
+
this.objectIdToIndex.clear();
|
|
40267
|
+
this.maxObjectId = 0;
|
|
39983
40268
|
const structureGroups = new Map();
|
|
39984
40269
|
this.dispatchEvent("optimizationprogress", {
|
|
39985
40270
|
phase: "collecting",
|
|
39986
40271
|
progress: 5,
|
|
39987
40272
|
message: "Collecting scene objects...",
|
|
39988
40273
|
});
|
|
40274
|
+
let totalObjectsToMerge = 0;
|
|
39989
40275
|
this.scene.traverse((object) => {
|
|
39990
40276
|
if (object.userData.structureId) {
|
|
39991
40277
|
const structureId = object.userData.structureId;
|
|
@@ -40003,17 +40289,32 @@ void main() {
|
|
|
40003
40289
|
});
|
|
40004
40290
|
}
|
|
40005
40291
|
const group = structureGroups.get(structureId);
|
|
40292
|
+
let added = false;
|
|
40006
40293
|
if (object instanceof Mesh) {
|
|
40007
40294
|
this.addToMaterialGroup(object, group.mapMeshes, group.meshes);
|
|
40295
|
+
added = true;
|
|
40008
40296
|
} else if (object instanceof LineSegments) {
|
|
40009
40297
|
this.addToMaterialGroup(object, group.mapLineSegments, group.lineSegments);
|
|
40298
|
+
added = true;
|
|
40010
40299
|
} else if (object instanceof Line$1) {
|
|
40011
40300
|
this.addToMaterialGroup(object, group.mapLines, group.lines);
|
|
40301
|
+
added = true;
|
|
40012
40302
|
} else if (object instanceof Points) {
|
|
40013
40303
|
this.addToMaterialGroup(object, group.mapPoints, group.points);
|
|
40304
|
+
added = true;
|
|
40305
|
+
}
|
|
40306
|
+
if (added) {
|
|
40307
|
+
totalObjectsToMerge++;
|
|
40014
40308
|
}
|
|
40015
40309
|
}
|
|
40016
40310
|
});
|
|
40311
|
+
if (totalObjectsToMerge > 0) {
|
|
40312
|
+
console.log(`Pre-allocating transform texture for ${totalObjectsToMerge} objects`);
|
|
40313
|
+
this.maxObjectId = totalObjectsToMerge;
|
|
40314
|
+
this.initTransformTexture();
|
|
40315
|
+
this.initializeObjectVisibility();
|
|
40316
|
+
this.maxObjectId = 0;
|
|
40317
|
+
}
|
|
40017
40318
|
let processedGroups = 0;
|
|
40018
40319
|
const totalGroups = structureGroups.size;
|
|
40019
40320
|
this.dispatchEvent("optimizationprogress", {
|
|
@@ -40058,7 +40359,6 @@ void main() {
|
|
|
40058
40359
|
this.originalObjectsToSelection.add(obj);
|
|
40059
40360
|
}
|
|
40060
40361
|
});
|
|
40061
|
-
this.initializeObjectVisibility();
|
|
40062
40362
|
console.log(`Optimization complete. Total objects: ${this.maxObjectId}`);
|
|
40063
40363
|
this.dispatchEvent("optimizationprogress", {
|
|
40064
40364
|
phase: "complete",
|
|
@@ -40127,6 +40427,7 @@ void main() {
|
|
|
40127
40427
|
}
|
|
40128
40428
|
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
40129
40429
|
const mergedMesh = new Mesh(mergedGeometry, visibilityMaterial);
|
|
40430
|
+
mergedMesh.frustumCulled = false;
|
|
40130
40431
|
mergedMesh.userData.isOptimized = true;
|
|
40131
40432
|
rootGroup.add(mergedMesh);
|
|
40132
40433
|
this.mergedMesh.add(mergedMesh);
|
|
@@ -40243,6 +40544,7 @@ void main() {
|
|
|
40243
40544
|
geometry.setAttribute("visibility", new BufferAttribute(visibilityArray, 1));
|
|
40244
40545
|
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
40245
40546
|
const mergedLine = new LineSegments(geometry, visibilityMaterial);
|
|
40547
|
+
mergedLine.frustumCulled = false;
|
|
40246
40548
|
mergedLine.userData.isEdge = isEdge;
|
|
40247
40549
|
mergedLine.userData.isOptimized = true;
|
|
40248
40550
|
const mergedObjects = [mergedLine];
|
|
@@ -40331,6 +40633,7 @@ void main() {
|
|
|
40331
40633
|
mergedGeometry.setAttribute("visibility", new BufferAttribute(visibilityArray, 1));
|
|
40332
40634
|
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
40333
40635
|
const mergedLine = new LineSegments(mergedGeometry, visibilityMaterial);
|
|
40636
|
+
mergedLine.frustumCulled = false;
|
|
40334
40637
|
mergedLine.userData.isEdge = isEdge;
|
|
40335
40638
|
mergedLine.userData.isOptimized = true;
|
|
40336
40639
|
if (this.useVAO) {
|
|
@@ -40400,7 +40703,27 @@ void main() {
|
|
|
40400
40703
|
const mergedObjects = [];
|
|
40401
40704
|
if (geometries.length > 0) {
|
|
40402
40705
|
const mergedGeometry = mergeGeometries(geometries, false);
|
|
40403
|
-
const
|
|
40706
|
+
const totalVertices = mergedGeometry.attributes.position.count;
|
|
40707
|
+
const objectIds = new Float32Array(totalVertices);
|
|
40708
|
+
let vertexOffset = 0;
|
|
40709
|
+
group.objects.forEach((points) => {
|
|
40710
|
+
const handle = points.userData.handle;
|
|
40711
|
+
if (!this.objectIdToIndex.has(handle)) {
|
|
40712
|
+
this.objectIdToIndex.set(handle, this.maxObjectId++);
|
|
40713
|
+
}
|
|
40714
|
+
const objectId = this.objectIdToIndex.get(handle);
|
|
40715
|
+
const count = points.geometry.attributes.position.count;
|
|
40716
|
+
for (let i = 0; i < count; i++) {
|
|
40717
|
+
objectIds[vertexOffset++] = objectId;
|
|
40718
|
+
}
|
|
40719
|
+
});
|
|
40720
|
+
mergedGeometry.setAttribute("objectId", new BufferAttribute(objectIds, 1));
|
|
40721
|
+
const visibilityArray = new Float32Array(totalVertices);
|
|
40722
|
+
visibilityArray.fill(1.0);
|
|
40723
|
+
mergedGeometry.setAttribute("visibility", new BufferAttribute(visibilityArray, 1));
|
|
40724
|
+
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
40725
|
+
const mergedPoints = new Points(mergedGeometry, visibilityMaterial);
|
|
40726
|
+
mergedPoints.frustumCulled = false;
|
|
40404
40727
|
mergedPoints.userData.isOptimized = true;
|
|
40405
40728
|
if (this.useVAO) {
|
|
40406
40729
|
this.createVAO(mergedPoints);
|
|
@@ -40469,13 +40792,33 @@ void main() {
|
|
|
40469
40792
|
geometriesWithIndex.push(clonedGeometry);
|
|
40470
40793
|
});
|
|
40471
40794
|
const finalGeometry = mergeGeometries(geometriesWithIndex, false);
|
|
40795
|
+
const totalVertices = finalGeometry.attributes.position.count;
|
|
40796
|
+
const objectIds = new Float32Array(totalVertices);
|
|
40797
|
+
let vertexOffset = 0;
|
|
40798
|
+
lineSegmentsArray.forEach((segment) => {
|
|
40799
|
+
const handle = segment.userData.handle;
|
|
40800
|
+
if (!this.objectIdToIndex.has(handle)) {
|
|
40801
|
+
this.objectIdToIndex.set(handle, this.maxObjectId++);
|
|
40802
|
+
}
|
|
40803
|
+
const objectId = this.objectIdToIndex.get(handle);
|
|
40804
|
+
const count = segment.geometry.attributes.position.count;
|
|
40805
|
+
for (let i = 0; i < count; i++) {
|
|
40806
|
+
objectIds[vertexOffset++] = objectId;
|
|
40807
|
+
}
|
|
40808
|
+
});
|
|
40809
|
+
finalGeometry.setAttribute("objectId", new BufferAttribute(objectIds, 1));
|
|
40810
|
+
const visibilityArray = new Float32Array(totalVertices);
|
|
40811
|
+
visibilityArray.fill(1.0);
|
|
40812
|
+
finalGeometry.setAttribute("visibility", new BufferAttribute(visibilityArray, 1));
|
|
40472
40813
|
const material = new LineBasicMaterial({
|
|
40473
40814
|
vertexColors: true,
|
|
40474
40815
|
});
|
|
40816
|
+
const visibilityMaterial = this.createVisibilityMaterial(material);
|
|
40475
40817
|
if (this.useVAO) {
|
|
40476
40818
|
this.createVAO(finalGeometry);
|
|
40477
40819
|
}
|
|
40478
|
-
const mergedLine = new LineSegments(finalGeometry,
|
|
40820
|
+
const mergedLine = new LineSegments(finalGeometry, visibilityMaterial);
|
|
40821
|
+
mergedLine.frustumCulled = false;
|
|
40479
40822
|
mergedLine.userData.structureId = structureId;
|
|
40480
40823
|
mergedLine.userData.isOptimized = true;
|
|
40481
40824
|
rootGroup.add(mergedLine);
|
|
@@ -40594,18 +40937,91 @@ void main() {
|
|
|
40594
40937
|
console.warn("No merged objects to transform");
|
|
40595
40938
|
return;
|
|
40596
40939
|
}
|
|
40597
|
-
this.
|
|
40598
|
-
|
|
40599
|
-
|
|
40940
|
+
if (!this.transformData) {
|
|
40941
|
+
console.warn("Transform texture not initialized");
|
|
40942
|
+
return;
|
|
40600
40943
|
}
|
|
40601
|
-
|
|
40602
|
-
|
|
40944
|
+
this.objectTransforms = objectTransformMap;
|
|
40945
|
+
this._resetTransformData(false);
|
|
40946
|
+
const transformData = this.transformData;
|
|
40947
|
+
const objectIdToIndex = this.objectIdToIndex;
|
|
40948
|
+
let textureNeedsUpdate = false;
|
|
40949
|
+
if (objectTransformMap instanceof Map) {
|
|
40950
|
+
for (const [object, matrix] of objectTransformMap.entries()) {
|
|
40951
|
+
const userData = object.userData;
|
|
40952
|
+
if (!userData) continue;
|
|
40953
|
+
const handle = userData.handle;
|
|
40954
|
+
if (handle === undefined) continue;
|
|
40955
|
+
const objectId = objectIdToIndex.get(handle);
|
|
40956
|
+
if (objectId !== undefined) {
|
|
40957
|
+
transformData.set(matrix.elements, objectId * 16);
|
|
40958
|
+
textureNeedsUpdate = true;
|
|
40959
|
+
}
|
|
40960
|
+
}
|
|
40961
|
+
} else {
|
|
40962
|
+
const len = objectTransformMap.length;
|
|
40963
|
+
for (let i = 0; i < len; i++) {
|
|
40964
|
+
const pair = objectTransformMap[i];
|
|
40965
|
+
const userData = pair[0].userData;
|
|
40966
|
+
if (!userData) continue;
|
|
40967
|
+
const handle = userData.handle;
|
|
40968
|
+
if (handle === undefined) continue;
|
|
40969
|
+
const objectId = objectIdToIndex.get(handle);
|
|
40970
|
+
if (objectId !== undefined) {
|
|
40971
|
+
transformData.set(pair[1].elements, objectId * 16);
|
|
40972
|
+
textureNeedsUpdate = true;
|
|
40973
|
+
}
|
|
40974
|
+
}
|
|
40603
40975
|
}
|
|
40604
|
-
|
|
40605
|
-
this.
|
|
40976
|
+
if (textureNeedsUpdate) {
|
|
40977
|
+
this.updateTransformTexture();
|
|
40978
|
+
if (
|
|
40979
|
+
this._lastTransformTexture !== this.transformTexture ||
|
|
40980
|
+
this._lastTransformTextureSize !== this.transformTextureSize
|
|
40981
|
+
) {
|
|
40982
|
+
this.updateMaterialUniforms();
|
|
40983
|
+
}
|
|
40606
40984
|
}
|
|
40607
|
-
|
|
40608
|
-
this.
|
|
40985
|
+
if (this.syncTransformsToOriginalObjects) {
|
|
40986
|
+
this._syncOriginalObjectTransforms(objectTransformMap);
|
|
40987
|
+
}
|
|
40988
|
+
}
|
|
40989
|
+
_syncOriginalObjectTransforms(objectTransformMap) {
|
|
40990
|
+
for (const [obj, savedPos] of this._originalObjectMatrices) {
|
|
40991
|
+
obj.position.copy(savedPos);
|
|
40992
|
+
if (obj.userData.highlight) {
|
|
40993
|
+
obj.userData.highlight.position.copy(savedPos);
|
|
40994
|
+
}
|
|
40995
|
+
}
|
|
40996
|
+
this._originalObjectMatrices.clear();
|
|
40997
|
+
const _offset = new Vector3();
|
|
40998
|
+
const _parentInverse = new Matrix4();
|
|
40999
|
+
if (objectTransformMap instanceof Map) {
|
|
41000
|
+
for (const [object, matrix] of objectTransformMap.entries()) {
|
|
41001
|
+
if (!object.userData?.handle) continue;
|
|
41002
|
+
if (!this._originalObjectMatrices.has(object)) {
|
|
41003
|
+
this._originalObjectMatrices.set(object, object.position.clone());
|
|
41004
|
+
}
|
|
41005
|
+
_offset.setFromMatrixPosition(matrix);
|
|
41006
|
+
if (object.userData.structureId) {
|
|
41007
|
+
const rootGroup = this.structureRoots.get(object.userData.structureId);
|
|
41008
|
+
if (rootGroup && object.parent && object.parent !== rootGroup) {
|
|
41009
|
+
const origin = new Vector3(0, 0, 0);
|
|
41010
|
+
origin.applyMatrix4(rootGroup.matrixWorld);
|
|
41011
|
+
_offset.applyMatrix4(rootGroup.matrixWorld);
|
|
41012
|
+
_offset.sub(origin);
|
|
41013
|
+
const parentOrigin = new Vector3(0, 0, 0);
|
|
41014
|
+
_parentInverse.copy(object.parent.matrixWorld).invert();
|
|
41015
|
+
parentOrigin.applyMatrix4(_parentInverse);
|
|
41016
|
+
_offset.applyMatrix4(_parentInverse);
|
|
41017
|
+
_offset.sub(parentOrigin);
|
|
41018
|
+
}
|
|
41019
|
+
}
|
|
41020
|
+
object.position.add(_offset);
|
|
41021
|
+
if (object.userData.highlight) {
|
|
41022
|
+
object.userData.highlight.position.copy(object.position);
|
|
41023
|
+
}
|
|
41024
|
+
}
|
|
40609
41025
|
}
|
|
40610
41026
|
}
|
|
40611
41027
|
createExplodeTransforms(objects = null, explodeCenter = null, explodeFactor = 1.5) {
|
|
@@ -40622,21 +41038,66 @@ void main() {
|
|
|
40622
41038
|
? objects
|
|
40623
41039
|
: Array.from(objects)
|
|
40624
41040
|
: Array.from(this.originalObjects);
|
|
41041
|
+
const structureInverseMatrices = new Map();
|
|
41042
|
+
if (!this.meshToNodeMap) {
|
|
41043
|
+
this.meshToNodeMap = new Map();
|
|
41044
|
+
for (const node of this.nodes.values()) {
|
|
41045
|
+
if (node.object) {
|
|
41046
|
+
this.meshToNodeMap.set(node.object, node);
|
|
41047
|
+
}
|
|
41048
|
+
}
|
|
41049
|
+
}
|
|
40625
41050
|
for (const obj of objectsArray) {
|
|
40626
41051
|
if (!obj.geometry || !obj.geometry.attributes.position) continue;
|
|
40627
|
-
|
|
40628
|
-
|
|
40629
|
-
|
|
41052
|
+
if (!obj.userData.explodeVector) {
|
|
41053
|
+
let center = null;
|
|
41054
|
+
const node = this.meshToNodeMap.get(obj);
|
|
41055
|
+
if (node && node.geometryExtents) {
|
|
41056
|
+
const box = node.geometryExtents.clone();
|
|
41057
|
+
box.applyMatrix4(obj.matrixWorld);
|
|
41058
|
+
center = new Vector3();
|
|
41059
|
+
box.getCenter(center);
|
|
41060
|
+
}
|
|
41061
|
+
if (!center) {
|
|
41062
|
+
if (!obj.geometry.boundingBox) obj.geometry.computeBoundingBox();
|
|
41063
|
+
const box = obj.geometry.boundingBox.clone();
|
|
41064
|
+
box.applyMatrix4(obj.matrixWorld);
|
|
41065
|
+
center = new Vector3();
|
|
41066
|
+
box.getCenter(center);
|
|
41067
|
+
}
|
|
41068
|
+
const explodeVector = center.sub(explodeCenter);
|
|
41069
|
+
obj.userData.explodeVector = explodeVector;
|
|
40630
41070
|
}
|
|
40631
|
-
|
|
40632
|
-
const
|
|
40633
|
-
boundingBox.getCenter(objectCenter);
|
|
40634
|
-
const direction = objectCenter.clone().sub(explodeCenter);
|
|
40635
|
-
const distance = direction.length();
|
|
41071
|
+
const explodeVector = obj.userData.explodeVector;
|
|
41072
|
+
const distance = explodeVector.length();
|
|
40636
41073
|
if (distance > 0) {
|
|
40637
|
-
|
|
40638
|
-
const
|
|
40639
|
-
|
|
41074
|
+
const offset = explodeVector.clone().multiplyScalar(explodeFactor - 1.0);
|
|
41075
|
+
const localOffset = offset.clone();
|
|
41076
|
+
if (obj.userData.structureId) {
|
|
41077
|
+
const structureId = obj.userData.structureId;
|
|
41078
|
+
let inverseMatrix = structureInverseMatrices.get(structureId);
|
|
41079
|
+
if (!inverseMatrix) {
|
|
41080
|
+
const rootGroup = this.structureRoots.get(structureId);
|
|
41081
|
+
if (rootGroup) {
|
|
41082
|
+
if (!rootGroup.userData.inverseWorldMatrix) {
|
|
41083
|
+
rootGroup.userData.inverseWorldMatrix = new Matrix4().copy(rootGroup.matrixWorld).invert();
|
|
41084
|
+
}
|
|
41085
|
+
inverseMatrix = rootGroup.userData.inverseWorldMatrix;
|
|
41086
|
+
structureInverseMatrices.set(structureId, inverseMatrix);
|
|
41087
|
+
}
|
|
41088
|
+
}
|
|
41089
|
+
if (inverseMatrix) {
|
|
41090
|
+
const zero = new Vector3(0, 0, 0).applyMatrix4(inverseMatrix);
|
|
41091
|
+
const vec = offset.clone().applyMatrix4(inverseMatrix).sub(zero);
|
|
41092
|
+
localOffset.copy(vec);
|
|
41093
|
+
}
|
|
41094
|
+
}
|
|
41095
|
+
let matrix = obj.userData.explodeMatrix;
|
|
41096
|
+
if (!matrix) {
|
|
41097
|
+
matrix = new Matrix4();
|
|
41098
|
+
obj.userData.explodeMatrix = matrix;
|
|
41099
|
+
}
|
|
41100
|
+
matrix.makeTranslation(localOffset.x, localOffset.y, localOffset.z);
|
|
40640
41101
|
transformMap.set(obj, matrix);
|
|
40641
41102
|
}
|
|
40642
41103
|
}
|
|
@@ -40644,115 +41105,19 @@ void main() {
|
|
|
40644
41105
|
}
|
|
40645
41106
|
clearTransforms() {
|
|
40646
41107
|
this.objectTransforms.clear();
|
|
40647
|
-
|
|
40648
|
-
|
|
40649
|
-
|
|
40650
|
-
|
|
40651
|
-
|
|
40652
|
-
|
|
40653
|
-
for (const lineSegment of this.mergedLineSegments) {
|
|
40654
|
-
this._restoreOriginalGeometry(lineSegment);
|
|
40655
|
-
}
|
|
40656
|
-
for (const point of this.mergedPoints) {
|
|
40657
|
-
this._restoreOriginalGeometry(point);
|
|
40658
|
-
}
|
|
40659
|
-
}
|
|
40660
|
-
clearHandleTransforms() {
|
|
40661
|
-
this.clearTransforms();
|
|
40662
|
-
}
|
|
40663
|
-
_applyTransformToMergedObject(mergedObject) {
|
|
40664
|
-
const objectData = this.mergedObjectMap.get(mergedObject.uuid);
|
|
40665
|
-
if (!objectData || !objectData.objectMapping) return;
|
|
40666
|
-
const geometry = mergedObject.geometry;
|
|
40667
|
-
if (!geometry || !geometry.attributes.position) return;
|
|
40668
|
-
const positionAttr = geometry.attributes.position;
|
|
40669
|
-
const positions = positionAttr.array;
|
|
40670
|
-
if (!this.transformedGeometries.has(mergedObject.uuid)) {
|
|
40671
|
-
this.transformedGeometries.set(mergedObject.uuid, new Float32Array(positions));
|
|
40672
|
-
}
|
|
40673
|
-
const originalPositions = this.transformedGeometries.get(mergedObject.uuid);
|
|
40674
|
-
const tempVector = new Vector3();
|
|
40675
|
-
for (const [originalMesh, mappingData] of objectData.objectMapping) {
|
|
40676
|
-
const transform = this.objectTransforms.get(originalMesh);
|
|
40677
|
-
if (!transform) {
|
|
40678
|
-
const startIdx = mappingData.startVertexIndex * 3;
|
|
40679
|
-
const endIdx = (mappingData.startVertexIndex + mappingData.vertexCount) * 3;
|
|
40680
|
-
for (let i = startIdx; i < endIdx; i++) {
|
|
40681
|
-
positions[i] = originalPositions[i];
|
|
40682
|
-
}
|
|
40683
|
-
continue;
|
|
40684
|
-
}
|
|
40685
|
-
const startVertex = mappingData.startVertexIndex;
|
|
40686
|
-
const vertexCount = mappingData.vertexCount;
|
|
40687
|
-
for (let i = 0; i < vertexCount; i++) {
|
|
40688
|
-
const idx = (startVertex + i) * 3;
|
|
40689
|
-
tempVector.set(originalPositions[idx], originalPositions[idx + 1], originalPositions[idx + 2]);
|
|
40690
|
-
tempVector.applyMatrix4(transform);
|
|
40691
|
-
positions[idx] = tempVector.x;
|
|
40692
|
-
positions[idx + 1] = tempVector.y;
|
|
40693
|
-
positions[idx + 2] = tempVector.z;
|
|
40694
|
-
}
|
|
40695
|
-
}
|
|
40696
|
-
if (geometry.attributes.normal) {
|
|
40697
|
-
this._updateNormalsForTransform(geometry, objectData, originalPositions);
|
|
40698
|
-
}
|
|
40699
|
-
positionAttr.needsUpdate = true;
|
|
40700
|
-
geometry.computeBoundingSphere();
|
|
40701
|
-
geometry.computeBoundingBox();
|
|
40702
|
-
}
|
|
40703
|
-
_updateNormalsForTransform(geometry, objectData, originalPositions) {
|
|
40704
|
-
const normalAttr = geometry.attributes.normal;
|
|
40705
|
-
if (!normalAttr) return;
|
|
40706
|
-
const normals = normalAttr.array;
|
|
40707
|
-
const tempVector = new Vector3();
|
|
40708
|
-
const normalMatrix = new Matrix4();
|
|
40709
|
-
const normalsKey = `${geometry.uuid}_normals`;
|
|
40710
|
-
if (!this.transformedGeometries.has(normalsKey)) {
|
|
40711
|
-
this.transformedGeometries.set(normalsKey, new Float32Array(normals));
|
|
40712
|
-
}
|
|
40713
|
-
const originalNormals = this.transformedGeometries.get(normalsKey);
|
|
40714
|
-
for (const [originalMesh, mappingData] of objectData.objectMapping) {
|
|
40715
|
-
const transform = this.objectTransforms.get(originalMesh);
|
|
40716
|
-
if (!transform) {
|
|
40717
|
-
const startIdx = mappingData.startVertexIndex * 3;
|
|
40718
|
-
const endIdx = (mappingData.startVertexIndex + mappingData.vertexCount) * 3;
|
|
40719
|
-
for (let i = startIdx; i < endIdx; i++) {
|
|
40720
|
-
normals[i] = originalNormals[i];
|
|
41108
|
+
this._resetTransformData(true);
|
|
41109
|
+
if (this.syncTransformsToOriginalObjects) {
|
|
41110
|
+
for (const [obj, savedPos] of this._originalObjectMatrices) {
|
|
41111
|
+
obj.position.copy(savedPos);
|
|
41112
|
+
if (obj.userData.highlight) {
|
|
41113
|
+
obj.userData.highlight.position.copy(savedPos);
|
|
40721
41114
|
}
|
|
40722
|
-
continue;
|
|
40723
|
-
}
|
|
40724
|
-
normalMatrix.copy(transform).invert().transpose();
|
|
40725
|
-
const startVertex = mappingData.startVertexIndex;
|
|
40726
|
-
const vertexCount = mappingData.vertexCount;
|
|
40727
|
-
for (let i = 0; i < vertexCount; i++) {
|
|
40728
|
-
const idx = (startVertex + i) * 3;
|
|
40729
|
-
tempVector.set(originalNormals[idx], originalNormals[idx + 1], originalNormals[idx + 2]);
|
|
40730
|
-
tempVector.applyMatrix4(normalMatrix).normalize();
|
|
40731
|
-
normals[idx] = tempVector.x;
|
|
40732
|
-
normals[idx + 1] = tempVector.y;
|
|
40733
|
-
normals[idx + 2] = tempVector.z;
|
|
40734
41115
|
}
|
|
41116
|
+
this._originalObjectMatrices.clear();
|
|
40735
41117
|
}
|
|
40736
|
-
normalAttr.needsUpdate = true;
|
|
40737
41118
|
}
|
|
40738
|
-
|
|
40739
|
-
|
|
40740
|
-
if (!geometry || !geometry.attributes.position) return;
|
|
40741
|
-
const originalPositions = this.transformedGeometries.get(mergedObject.uuid);
|
|
40742
|
-
if (originalPositions) {
|
|
40743
|
-
const positions = geometry.attributes.position.array;
|
|
40744
|
-
positions.set(originalPositions);
|
|
40745
|
-
geometry.attributes.position.needsUpdate = true;
|
|
40746
|
-
}
|
|
40747
|
-
const normalsKey = `${geometry.uuid}_normals`;
|
|
40748
|
-
const originalNormals = this.transformedGeometries.get(normalsKey);
|
|
40749
|
-
if (originalNormals && geometry.attributes.normal) {
|
|
40750
|
-
const normals = geometry.attributes.normal.array;
|
|
40751
|
-
normals.set(originalNormals);
|
|
40752
|
-
geometry.attributes.normal.needsUpdate = true;
|
|
40753
|
-
}
|
|
40754
|
-
geometry.computeBoundingSphere();
|
|
40755
|
-
geometry.computeBoundingBox();
|
|
41119
|
+
clearHandleTransforms() {
|
|
41120
|
+
this.clearTransforms();
|
|
40756
41121
|
}
|
|
40757
41122
|
syncHiddenObjects() {
|
|
40758
41123
|
if (this.mergedObjectMap.size === 0) {
|