@inweb/viewer-three 26.9.7 → 26.9.8
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 +344 -125
- package/dist/viewer-three.js.map +1 -1
- package/dist/viewer-three.min.js +3 -3
- package/dist/viewer-three.module.js +329 -110
- package/dist/viewer-three.module.js.map +1 -1
- package/package.json +5 -5
- package/src/Viewer/commands/ZoomTo.ts +1 -1
- package/src/Viewer/components/SelectionComponent.ts +4 -4
- package/src/Viewer/draggers/MeasureLineDragger.ts +175 -17
- package/src/Viewer/loaders/DynamicGltfLoader/DynamicGltfLoader.js +272 -105
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
|
|
24
24
|
import { draggersRegistry, commandsRegistry, componentsRegistry, Loader, loadersRegistry, Options, CANVAS_EVENTS } from '@inweb/viewer-core';
|
|
25
25
|
export * from '@inweb/viewer-core';
|
|
26
|
-
import { Line, Vector3, BufferGeometry, Float32BufferAttribute, LineBasicMaterial, Mesh, MeshBasicMaterial, DoubleSide, EventDispatcher, MOUSE, TOUCH, Spherical, Quaternion, Vector2, Plane, Object3D, Matrix4, Vector4, Raycaster, Controls, Clock,
|
|
26
|
+
import { Line, Vector3, BufferGeometry, Float32BufferAttribute, LineBasicMaterial, Mesh, MeshBasicMaterial, DoubleSide, EventDispatcher, MOUSE, TOUCH, Spherical, Quaternion, Vector2, Plane, Object3D, Line3, Matrix4, Vector4, MathUtils, Raycaster, EdgesGeometry, Controls, Clock, Sphere, Box3, Color, AmbientLight, DirectionalLight, HemisphereLight, MeshPhongMaterial, WebGLRenderTarget, UnsignedByteType, RGBAFormat, OrthographicCamera, CylinderGeometry, Sprite, CanvasTexture, SRGBColorSpace, SpriteMaterial, LoadingManager, LoaderUtils, TextureLoader, BufferAttribute, PointsMaterial, Points, TriangleStripDrawMode, TriangleFanDrawMode, LineSegments, LineLoop, Group, NormalBlending, PerspectiveCamera, 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';
|
|
@@ -900,6 +900,8 @@ class CuttingPlaneZAxisDragger extends CuttingPlaneDragger {
|
|
|
900
900
|
}
|
|
901
901
|
|
|
902
902
|
const PRECISION = 0.01;
|
|
903
|
+
const DESKTOP_SNAP_DISTANCE = 10;
|
|
904
|
+
const MOBILE_SNAP_DISTANCE = 50;
|
|
903
905
|
class MeasureLineDragger extends OrbitDragger {
|
|
904
906
|
constructor(viewer) {
|
|
905
907
|
super(viewer);
|
|
@@ -914,7 +916,10 @@ class MeasureLineDragger extends OrbitDragger {
|
|
|
914
916
|
this.onPointerMove = (event) => {
|
|
915
917
|
if (this.orbit.enabled && this.orbit.state !== -1)
|
|
916
918
|
return;
|
|
917
|
-
|
|
919
|
+
const snapPoint = this.snapper.getSnapPoint(event);
|
|
920
|
+
if (snapPoint && this.line.endPoint && snapPoint.equals(this.line.endPoint))
|
|
921
|
+
return;
|
|
922
|
+
this.line.endPoint = snapPoint;
|
|
918
923
|
this.line.render();
|
|
919
924
|
if (this.line.startPoint)
|
|
920
925
|
this.changed = true;
|
|
@@ -943,14 +948,14 @@ class MeasureLineDragger extends OrbitDragger {
|
|
|
943
948
|
this.overlay.render();
|
|
944
949
|
};
|
|
945
950
|
this.updateSnapper = () => {
|
|
946
|
-
this.snapper.update(this.viewer
|
|
951
|
+
this.snapper.update(this.viewer);
|
|
947
952
|
};
|
|
948
953
|
this.overlay = new MeasureOverlay(viewer.camera, viewer.canvas);
|
|
949
954
|
this.overlay.attach();
|
|
950
955
|
this.line = new MeasureLine(this.overlay);
|
|
951
956
|
this.overlay.addLine(this.line);
|
|
952
957
|
this.snapper = new MeasureSnapper(viewer.camera, viewer.canvas);
|
|
953
|
-
this.
|
|
958
|
+
this.updateSnapper();
|
|
954
959
|
this.viewer.canvas.addEventListener("pointerdown", this.onPointerDown);
|
|
955
960
|
this.viewer.canvas.addEventListener("pointermove", this.onPointerMove);
|
|
956
961
|
this.viewer.canvas.addEventListener("pointerup", this.onPointerUp);
|
|
@@ -973,20 +978,39 @@ class MeasureLineDragger extends OrbitDragger {
|
|
|
973
978
|
this.viewer.removeEventListener("isolate", this.updateSnapper);
|
|
974
979
|
this.viewer.removeEventListener("show", this.updateSnapper);
|
|
975
980
|
this.viewer.removeEventListener("showall", this.updateSnapper);
|
|
981
|
+
this.snapper.dispose();
|
|
976
982
|
this.overlay.detach();
|
|
977
983
|
this.overlay.dispose();
|
|
978
984
|
super.dispose();
|
|
979
985
|
}
|
|
980
986
|
}
|
|
987
|
+
const _vertex = new Vector3();
|
|
988
|
+
const _start = new Vector3();
|
|
989
|
+
const _end = new Vector3();
|
|
990
|
+
const _line = new Line3();
|
|
991
|
+
const _center = new Vector3();
|
|
992
|
+
const _projection = new Vector3();
|
|
981
993
|
class MeasureSnapper {
|
|
982
994
|
constructor(camera, canvas) {
|
|
983
|
-
this.objects = [];
|
|
984
995
|
this.camera = camera;
|
|
985
996
|
this.canvas = canvas;
|
|
997
|
+
this.objects = [];
|
|
986
998
|
this.raycaster = new Raycaster();
|
|
999
|
+
this.detectRadiusInPixels = this.isMobile() ? MOBILE_SNAP_DISTANCE : DESKTOP_SNAP_DISTANCE;
|
|
1000
|
+
this.edgesCache = new WeakMap();
|
|
987
1001
|
}
|
|
988
|
-
|
|
989
|
-
|
|
1002
|
+
dispose() {
|
|
1003
|
+
this.objects = [];
|
|
1004
|
+
}
|
|
1005
|
+
isMobile() {
|
|
1006
|
+
if (typeof navigator === "undefined")
|
|
1007
|
+
return false;
|
|
1008
|
+
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent);
|
|
1009
|
+
}
|
|
1010
|
+
getMousePosition(event, target) {
|
|
1011
|
+
return target.set(event.clientX, event.clientY);
|
|
1012
|
+
}
|
|
1013
|
+
getPointerIntersects(mouse, objects) {
|
|
990
1014
|
const rect = this.canvas.getBoundingClientRect();
|
|
991
1015
|
const x = ((mouse.x - rect.left) / rect.width) * 2 - 1;
|
|
992
1016
|
const y = (-(mouse.y - rect.top) / rect.height) * 2 + 1;
|
|
@@ -994,20 +1018,86 @@ class MeasureSnapper {
|
|
|
994
1018
|
this.raycaster.setFromCamera(coords, this.camera);
|
|
995
1019
|
this.raycaster.params = {
|
|
996
1020
|
Mesh: {},
|
|
997
|
-
Line: { threshold: 0.
|
|
998
|
-
Line2: { threshold: 0.
|
|
1021
|
+
Line: { threshold: 0.05 },
|
|
1022
|
+
Line2: { threshold: 0.05 },
|
|
999
1023
|
LOD: {},
|
|
1000
|
-
Points: { threshold: 0.
|
|
1024
|
+
Points: { threshold: 0.01 },
|
|
1001
1025
|
Sprite: {},
|
|
1002
1026
|
};
|
|
1003
|
-
|
|
1004
|
-
if (intersects.length === 0)
|
|
1005
|
-
return undefined;
|
|
1006
|
-
return intersects[0].point;
|
|
1027
|
+
return this.raycaster.intersectObjects(objects, false);
|
|
1007
1028
|
}
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1029
|
+
getDetectRadius(point) {
|
|
1030
|
+
const camera = this.camera;
|
|
1031
|
+
if (camera.isOrthographicCamera) {
|
|
1032
|
+
const worldHeight = camera.top - camera.bottom;
|
|
1033
|
+
const canvasHeight = this.canvas.height;
|
|
1034
|
+
const worldUnitsPerPixel = worldHeight / canvasHeight;
|
|
1035
|
+
return this.detectRadiusInPixels * worldUnitsPerPixel;
|
|
1036
|
+
}
|
|
1037
|
+
if (camera.isPerspectiveCamera) {
|
|
1038
|
+
const distance = camera.position.distanceTo(point);
|
|
1039
|
+
const worldHeight = 2 * Math.tan(MathUtils.degToRad(camera.fov * 0.5)) * distance;
|
|
1040
|
+
const canvasHeight = this.canvas.height;
|
|
1041
|
+
const worldUnitsPerPixel = worldHeight / canvasHeight;
|
|
1042
|
+
return this.detectRadiusInPixels * worldUnitsPerPixel;
|
|
1043
|
+
}
|
|
1044
|
+
return 0.1;
|
|
1045
|
+
}
|
|
1046
|
+
getSnapPoint(event) {
|
|
1047
|
+
const mouse = this.getMousePosition(event, new Vector2());
|
|
1048
|
+
const intersections = this.getPointerIntersects(mouse, this.objects);
|
|
1049
|
+
if (intersections.length === 0)
|
|
1050
|
+
return undefined;
|
|
1051
|
+
const object = intersections[0].object;
|
|
1052
|
+
const intersectionPoint = intersections[0].point;
|
|
1053
|
+
const localPoint = object.worldToLocal(intersectionPoint.clone());
|
|
1054
|
+
let snapPoint;
|
|
1055
|
+
let snapDistance = this.getDetectRadius(intersectionPoint);
|
|
1056
|
+
const geometry = object.geometry;
|
|
1057
|
+
const positions = geometry.attributes.position.array;
|
|
1058
|
+
for (let i = 0; i < positions.length; i += 3) {
|
|
1059
|
+
_vertex.set(positions[i], positions[i + 1], positions[i + 2]);
|
|
1060
|
+
const distance = _vertex.distanceTo(localPoint);
|
|
1061
|
+
if (distance < snapDistance) {
|
|
1062
|
+
snapDistance = distance;
|
|
1063
|
+
snapPoint = _vertex.clone();
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
if (snapPoint)
|
|
1067
|
+
return object.localToWorld(snapPoint);
|
|
1068
|
+
let edges = this.edgesCache.get(geometry);
|
|
1069
|
+
if (!edges) {
|
|
1070
|
+
edges = new EdgesGeometry(geometry);
|
|
1071
|
+
this.edgesCache.set(geometry, edges);
|
|
1072
|
+
}
|
|
1073
|
+
const edgePositions = edges.attributes.position.array;
|
|
1074
|
+
for (let i = 0; i < edgePositions.length; i += 6) {
|
|
1075
|
+
_start.set(edgePositions[i], edgePositions[i + 1], edgePositions[i + 2]);
|
|
1076
|
+
_end.set(edgePositions[i + 3], edgePositions[i + 4], edgePositions[i + 5]);
|
|
1077
|
+
_line.set(_start, _end);
|
|
1078
|
+
_line.getCenter(_center);
|
|
1079
|
+
const centerDistance = _center.distanceTo(localPoint);
|
|
1080
|
+
if (centerDistance < snapDistance) {
|
|
1081
|
+
snapDistance = centerDistance;
|
|
1082
|
+
snapPoint = _center.clone();
|
|
1083
|
+
continue;
|
|
1084
|
+
}
|
|
1085
|
+
_line.closestPointToPoint(localPoint, true, _projection);
|
|
1086
|
+
const lineDistance = _projection.distanceTo(localPoint);
|
|
1087
|
+
if (lineDistance < snapDistance) {
|
|
1088
|
+
snapDistance = lineDistance;
|
|
1089
|
+
snapPoint = _projection.clone();
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
if (snapPoint)
|
|
1093
|
+
return object.localToWorld(snapPoint);
|
|
1094
|
+
return intersectionPoint.clone();
|
|
1095
|
+
}
|
|
1096
|
+
update(viewer) {
|
|
1097
|
+
this.objects.length = 0;
|
|
1098
|
+
viewer.models.forEach((model) => {
|
|
1099
|
+
model.getVisibleObjects().forEach((object) => this.objects.push(object));
|
|
1100
|
+
});
|
|
1011
1101
|
}
|
|
1012
1102
|
}
|
|
1013
1103
|
class MeasureOverlay {
|
|
@@ -1029,6 +1119,8 @@ class MeasureOverlay {
|
|
|
1029
1119
|
this.container.style.outline = "none";
|
|
1030
1120
|
this.container.style.pointerEvents = "none";
|
|
1031
1121
|
this.container.style.overflow = "hidden";
|
|
1122
|
+
if (!this.canvas.parentElement)
|
|
1123
|
+
return;
|
|
1032
1124
|
this.canvas.parentElement.appendChild(this.container);
|
|
1033
1125
|
}
|
|
1034
1126
|
dispose() {
|
|
@@ -1059,7 +1151,7 @@ class MeasureOverlay {
|
|
|
1059
1151
|
const _middlePoint = new Vector3();
|
|
1060
1152
|
class MeasureLine {
|
|
1061
1153
|
constructor(overlay) {
|
|
1062
|
-
this.id =
|
|
1154
|
+
this.id = MathUtils.generateUUID();
|
|
1063
1155
|
this.unit = "";
|
|
1064
1156
|
this.scale = 1.0;
|
|
1065
1157
|
this.size = 10.0;
|
|
@@ -1083,6 +1175,10 @@ class MeasureLine {
|
|
|
1083
1175
|
this.elementEndPoint.remove();
|
|
1084
1176
|
this.elementLine.remove();
|
|
1085
1177
|
this.elementLabel.remove();
|
|
1178
|
+
this.elementStartPoint = undefined;
|
|
1179
|
+
this.elementEndPoint = undefined;
|
|
1180
|
+
this.elementLine = undefined;
|
|
1181
|
+
this.elementLabel = undefined;
|
|
1086
1182
|
}
|
|
1087
1183
|
render() {
|
|
1088
1184
|
const projector = this.overlay.projector;
|
|
@@ -1739,7 +1835,7 @@ function zoomTo(viewer, box) {
|
|
|
1739
1835
|
if (camera.isPerspectiveCamera) {
|
|
1740
1836
|
const offset = new Vector3(0, 0, 1)
|
|
1741
1837
|
.applyQuaternion(camera.quaternion)
|
|
1742
|
-
.multiplyScalar(boxSize / Math.tan(MathUtils.
|
|
1838
|
+
.multiplyScalar(boxSize / Math.tan(MathUtils.degToRad(camera.fov * 0.5)));
|
|
1743
1839
|
camera.position.copy(offset).add(boxCenter);
|
|
1744
1840
|
camera.updateMatrixWorld();
|
|
1745
1841
|
}
|
|
@@ -2401,12 +2497,12 @@ class SelectionComponent {
|
|
|
2401
2497
|
const y = (-(mouse.y - rect.top) / rect.height) * 2 + 1;
|
|
2402
2498
|
const coords = new Vector2(x, y);
|
|
2403
2499
|
this.raycaster.setFromCamera(coords, this.viewer.camera);
|
|
2404
|
-
this.raycaster.params =
|
|
2500
|
+
this.raycaster.params = {
|
|
2405
2501
|
Mesh: {},
|
|
2406
|
-
Line: { threshold: 0.
|
|
2407
|
-
Line2: { threshold: 0.
|
|
2502
|
+
Line: { threshold: 0.05 },
|
|
2503
|
+
Line2: { threshold: 0.05 },
|
|
2408
2504
|
LOD: {},
|
|
2409
|
-
Points: { threshold: 0.
|
|
2505
|
+
Points: { threshold: 0.01 },
|
|
2410
2506
|
Sprite: {},
|
|
2411
2507
|
};
|
|
2412
2508
|
return this.raycaster.intersectObjects(objects, false);
|
|
@@ -3398,6 +3494,12 @@ class DynamicGltfLoader {
|
|
|
3398
3494
|
this.maxConcurrentChunks = 8;
|
|
3399
3495
|
this.activeChunkLoads = 0;
|
|
3400
3496
|
this.chunkQueue = [];
|
|
3497
|
+
this.objectIdToIndex = new Map();
|
|
3498
|
+
this.maxObjectId = 0;
|
|
3499
|
+
this.objectVisibility = new Float32Array();
|
|
3500
|
+
this.maxConcurrentChunks = 6;
|
|
3501
|
+
this.mergedObjectMap = new Map();
|
|
3502
|
+
this.mergedGeometryVisibility = new Map();
|
|
3401
3503
|
}
|
|
3402
3504
|
setVisibleEdges(visible) {
|
|
3403
3505
|
this.visibleEdges = visible;
|
|
@@ -4104,6 +4206,50 @@ class DynamicGltfLoader {
|
|
|
4104
4206
|
this.originalObjects.clear();
|
|
4105
4207
|
this.originalObjectsToSelection.clear();
|
|
4106
4208
|
}
|
|
4209
|
+
initializeObjectVisibility() {
|
|
4210
|
+
if (this.maxObjectId > 0) {
|
|
4211
|
+
this.objectVisibility = new Float32Array(this.maxObjectId);
|
|
4212
|
+
for (let i = 0; i < this.maxObjectId; i++) {
|
|
4213
|
+
this.objectVisibility[i] = 1.0;
|
|
4214
|
+
}
|
|
4215
|
+
console.log(`Initialized object visibility array: ${this.maxObjectId} objects`);
|
|
4216
|
+
}
|
|
4217
|
+
}
|
|
4218
|
+
createVisibilityMaterial(material) {
|
|
4219
|
+
material.onBeforeCompile = (shader) => {
|
|
4220
|
+
shader.vertexShader = shader.vertexShader.replace(
|
|
4221
|
+
"#include <common>",
|
|
4222
|
+
`
|
|
4223
|
+
#include <common>
|
|
4224
|
+
attribute float visibility;
|
|
4225
|
+
varying float vVisibility;
|
|
4226
|
+
`
|
|
4227
|
+
);
|
|
4228
|
+
shader.fragmentShader = shader.fragmentShader.replace(
|
|
4229
|
+
"#include <common>",
|
|
4230
|
+
`
|
|
4231
|
+
#include <common>
|
|
4232
|
+
varying float vVisibility;
|
|
4233
|
+
`
|
|
4234
|
+
);
|
|
4235
|
+
shader.vertexShader = shader.vertexShader.replace(
|
|
4236
|
+
"void main() {",
|
|
4237
|
+
`
|
|
4238
|
+
void main() {
|
|
4239
|
+
vVisibility = visibility;
|
|
4240
|
+
`
|
|
4241
|
+
);
|
|
4242
|
+
shader.fragmentShader = shader.fragmentShader.replace(
|
|
4243
|
+
"void main() {",
|
|
4244
|
+
`
|
|
4245
|
+
void main() {
|
|
4246
|
+
if (vVisibility < 0.5) discard;
|
|
4247
|
+
`
|
|
4248
|
+
);
|
|
4249
|
+
};
|
|
4250
|
+
material.needsUpdate = true;
|
|
4251
|
+
return material;
|
|
4252
|
+
}
|
|
4107
4253
|
clear() {
|
|
4108
4254
|
this.chunkQueue = [];
|
|
4109
4255
|
this.structures.forEach((structure) => {
|
|
@@ -4209,6 +4355,9 @@ class DynamicGltfLoader {
|
|
|
4209
4355
|
this.loadedGeometrySize = 0;
|
|
4210
4356
|
this.abortController = new AbortController();
|
|
4211
4357
|
this.updateMemoryIndicator();
|
|
4358
|
+
this.objectIdToIndex.clear();
|
|
4359
|
+
this.maxObjectId = 0;
|
|
4360
|
+
this.objectVisibility = new Float32Array();
|
|
4212
4361
|
}
|
|
4213
4362
|
setStructureTransform(structureId, matrix) {
|
|
4214
4363
|
const rootGroup = this.structureRoots.get(structureId);
|
|
@@ -4358,18 +4507,43 @@ class DynamicGltfLoader {
|
|
|
4358
4507
|
this.originalObjectsToSelection.add(obj);
|
|
4359
4508
|
}
|
|
4360
4509
|
});
|
|
4510
|
+
this.initializeObjectVisibility();
|
|
4511
|
+
console.log(`Optimization complete. Total objects: ${this.maxObjectId}`);
|
|
4361
4512
|
this.dispatchEvent("update");
|
|
4362
4513
|
}
|
|
4363
4514
|
mergeMeshGroups(materialGroups, rootGroup) {
|
|
4364
4515
|
for (const group of materialGroups) {
|
|
4516
|
+
if (!group.material) {
|
|
4517
|
+
console.warn("Skipping mesh group with null material");
|
|
4518
|
+
continue;
|
|
4519
|
+
}
|
|
4365
4520
|
try {
|
|
4366
4521
|
const geometries = [];
|
|
4367
4522
|
const handles = new Set();
|
|
4368
4523
|
const optimizedObjects = [];
|
|
4524
|
+
const objectMapping = new Map();
|
|
4525
|
+
let currentVertexOffset = 0;
|
|
4369
4526
|
for (const mesh of group.objects) {
|
|
4370
4527
|
const geometry = mesh.geometry.clone();
|
|
4371
4528
|
mesh.updateWorldMatrix(true, false);
|
|
4372
4529
|
geometry.applyMatrix4(mesh.matrixWorld);
|
|
4530
|
+
const handle = mesh.userData.handle;
|
|
4531
|
+
if (!this.objectIdToIndex.has(handle)) {
|
|
4532
|
+
this.objectIdToIndex.set(handle, this.maxObjectId++);
|
|
4533
|
+
}
|
|
4534
|
+
const objectId = this.objectIdToIndex.get(handle);
|
|
4535
|
+
const vertexCount = geometry.attributes.position.count;
|
|
4536
|
+
const objectIds = new Float32Array(vertexCount);
|
|
4537
|
+
for (let i = 0; i < vertexCount; i++) {
|
|
4538
|
+
objectIds[i] = objectId;
|
|
4539
|
+
}
|
|
4540
|
+
geometry.setAttribute("objectId", new BufferAttribute(objectIds, 1));
|
|
4541
|
+
objectMapping.set(mesh, {
|
|
4542
|
+
geometry,
|
|
4543
|
+
startVertexIndex: currentVertexOffset,
|
|
4544
|
+
vertexCount: geometry.attributes.position.count,
|
|
4545
|
+
});
|
|
4546
|
+
currentVertexOffset += geometry.attributes.position.count;
|
|
4373
4547
|
geometries.push(geometry);
|
|
4374
4548
|
optimizedObjects.push(mesh);
|
|
4375
4549
|
handles.add(mesh.userData.handle);
|
|
@@ -4377,13 +4551,26 @@ class DynamicGltfLoader {
|
|
|
4377
4551
|
const mergedObjects = [];
|
|
4378
4552
|
if (geometries.length > 0) {
|
|
4379
4553
|
const mergedGeometry = mergeGeometries(geometries);
|
|
4554
|
+
const totalVertices = mergedGeometry.attributes.position.count;
|
|
4555
|
+
const visibilityArray = new Float32Array(totalVertices);
|
|
4556
|
+
for (let i = 0; i < totalVertices; i++) {
|
|
4557
|
+
visibilityArray[i] = 1.0;
|
|
4558
|
+
}
|
|
4559
|
+
mergedGeometry.setAttribute("visibility", new BufferAttribute(visibilityArray, 1));
|
|
4380
4560
|
if (this.useVAO) {
|
|
4381
4561
|
this.createVAO(mergedGeometry);
|
|
4382
4562
|
}
|
|
4383
|
-
const
|
|
4563
|
+
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
4564
|
+
const mergedMesh = new Mesh(mergedGeometry, visibilityMaterial);
|
|
4384
4565
|
rootGroup.add(mergedMesh);
|
|
4385
4566
|
this.mergedMesh.add(mergedMesh);
|
|
4386
4567
|
this.optimizedOriginalMap.set(mergedMesh, optimizedObjects);
|
|
4568
|
+
this.mergedObjectMap.set(mergedMesh.uuid, {
|
|
4569
|
+
objectMapping,
|
|
4570
|
+
visibilityArray,
|
|
4571
|
+
totalVertices,
|
|
4572
|
+
});
|
|
4573
|
+
this.mergedGeometryVisibility.set(mergedMesh, visibilityArray);
|
|
4387
4574
|
mergedObjects.push(mergedMesh);
|
|
4388
4575
|
geometries.forEach((geometry) => {
|
|
4389
4576
|
geometry.dispose();
|
|
@@ -4409,8 +4596,14 @@ class DynamicGltfLoader {
|
|
|
4409
4596
|
mergeLineGroups(materialGroups, rootGroup) {
|
|
4410
4597
|
for (const group of materialGroups) {
|
|
4411
4598
|
if (group.objects.length === 0) continue;
|
|
4599
|
+
if (!group.material) {
|
|
4600
|
+
console.warn("Skipping line group with null material");
|
|
4601
|
+
continue;
|
|
4602
|
+
}
|
|
4412
4603
|
const handles = new Set();
|
|
4413
4604
|
let totalVertices = 0;
|
|
4605
|
+
const objectMapping = new Map();
|
|
4606
|
+
let currentVertexOffset = 0;
|
|
4414
4607
|
group.objects.map((line) => {
|
|
4415
4608
|
handles.add(line.userData.handle);
|
|
4416
4609
|
totalVertices += line.geometry.attributes.position.count;
|
|
@@ -4423,6 +4616,15 @@ class DynamicGltfLoader {
|
|
|
4423
4616
|
const geometry = line.geometry;
|
|
4424
4617
|
const positionAttr = geometry.attributes.position;
|
|
4425
4618
|
const vertexCount = positionAttr.count;
|
|
4619
|
+
const handle = line.userData.handle;
|
|
4620
|
+
if (!this.objectIdToIndex.has(handle)) {
|
|
4621
|
+
this.objectIdToIndex.set(handle, this.maxObjectId++);
|
|
4622
|
+
}
|
|
4623
|
+
objectMapping.set(line, {
|
|
4624
|
+
startVertexIndex: currentVertexOffset,
|
|
4625
|
+
vertexCount,
|
|
4626
|
+
});
|
|
4627
|
+
currentVertexOffset += vertexCount;
|
|
4426
4628
|
line.updateWorldMatrix(true, false);
|
|
4427
4629
|
const matrix = line.matrixWorld;
|
|
4428
4630
|
const vector = new Vector3();
|
|
@@ -4443,7 +4645,24 @@ class DynamicGltfLoader {
|
|
|
4443
4645
|
geometry.setIndex(indices);
|
|
4444
4646
|
geometry.computeBoundingSphere();
|
|
4445
4647
|
geometry.computeBoundingBox();
|
|
4446
|
-
const
|
|
4648
|
+
const objectIds = new Float32Array(totalVertices);
|
|
4649
|
+
let vertexIndex = 0;
|
|
4650
|
+
group.objects.forEach((line) => {
|
|
4651
|
+
const vertexCount = line.geometry.attributes.position.count;
|
|
4652
|
+
const handle = line.userData.handle;
|
|
4653
|
+
const objectId = this.objectIdToIndex.get(handle);
|
|
4654
|
+
for (let i = 0; i < vertexCount; i++) {
|
|
4655
|
+
objectIds[vertexIndex++] = objectId;
|
|
4656
|
+
}
|
|
4657
|
+
});
|
|
4658
|
+
geometry.setAttribute("objectId", new BufferAttribute(objectIds, 1));
|
|
4659
|
+
const visibilityArray = new Float32Array(totalVertices);
|
|
4660
|
+
for (let i = 0; i < totalVertices; i++) {
|
|
4661
|
+
visibilityArray[i] = 1.0;
|
|
4662
|
+
}
|
|
4663
|
+
geometry.setAttribute("visibility", new BufferAttribute(visibilityArray, 1));
|
|
4664
|
+
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
4665
|
+
const mergedLine = new LineSegments(geometry, visibilityMaterial);
|
|
4447
4666
|
const mergedObjects = [mergedLine];
|
|
4448
4667
|
if (this.useVAO) {
|
|
4449
4668
|
this.createVAO(mergedLine);
|
|
@@ -4451,6 +4670,12 @@ class DynamicGltfLoader {
|
|
|
4451
4670
|
rootGroup.add(mergedLine);
|
|
4452
4671
|
this.mergedLines.add(mergedLine);
|
|
4453
4672
|
this.optimizedOriginalMap.set(mergedLine, group.objects);
|
|
4673
|
+
this.mergedObjectMap.set(mergedLine.uuid, {
|
|
4674
|
+
objectMapping,
|
|
4675
|
+
visibilityArray,
|
|
4676
|
+
totalVertices,
|
|
4677
|
+
});
|
|
4678
|
+
this.mergedGeometryVisibility.set(mergedLine, visibilityArray);
|
|
4454
4679
|
handles.forEach((handle) => {
|
|
4455
4680
|
if (this.handleToOptimizedObjects.has(handle)) {
|
|
4456
4681
|
const existingObjects = this.handleToOptimizedObjects.get(handle);
|
|
@@ -4464,14 +4689,37 @@ class DynamicGltfLoader {
|
|
|
4464
4689
|
}
|
|
4465
4690
|
mergeLineSegmentGroups(materialGroups, rootGroup) {
|
|
4466
4691
|
for (const group of materialGroups) {
|
|
4692
|
+
if (!group.material) {
|
|
4693
|
+
console.warn("Skipping line segment group with null material");
|
|
4694
|
+
continue;
|
|
4695
|
+
}
|
|
4467
4696
|
try {
|
|
4468
4697
|
const geometries = [];
|
|
4469
4698
|
const optimizedObjects = [];
|
|
4470
4699
|
const handles = new Set();
|
|
4700
|
+
const objectMapping = new Map();
|
|
4701
|
+
let currentVertexOffset = 0;
|
|
4471
4702
|
for (const line of group.objects) {
|
|
4472
4703
|
const geometry = line.geometry.clone();
|
|
4473
4704
|
line.updateWorldMatrix(true, false);
|
|
4474
4705
|
geometry.applyMatrix4(line.matrixWorld);
|
|
4706
|
+
const handle = line.userData.handle;
|
|
4707
|
+
if (!this.objectIdToIndex.has(handle)) {
|
|
4708
|
+
this.objectIdToIndex.set(handle, this.maxObjectId++);
|
|
4709
|
+
}
|
|
4710
|
+
const objectId = this.objectIdToIndex.get(handle);
|
|
4711
|
+
const vertexCount = geometry.attributes.position.count;
|
|
4712
|
+
const objectIds = new Float32Array(vertexCount);
|
|
4713
|
+
for (let i = 0; i < vertexCount; i++) {
|
|
4714
|
+
objectIds[i] = objectId;
|
|
4715
|
+
}
|
|
4716
|
+
geometry.setAttribute("objectId", new BufferAttribute(objectIds, 1));
|
|
4717
|
+
objectMapping.set(line, {
|
|
4718
|
+
geometry,
|
|
4719
|
+
startVertexIndex: currentVertexOffset,
|
|
4720
|
+
vertexCount: geometry.attributes.position.count,
|
|
4721
|
+
});
|
|
4722
|
+
currentVertexOffset += geometry.attributes.position.count;
|
|
4475
4723
|
geometries.push(geometry);
|
|
4476
4724
|
optimizedObjects.push(line);
|
|
4477
4725
|
handles.add(line.userData.handle);
|
|
@@ -4479,13 +4727,26 @@ class DynamicGltfLoader {
|
|
|
4479
4727
|
const mergedObjects = [];
|
|
4480
4728
|
if (geometries.length > 0) {
|
|
4481
4729
|
const mergedGeometry = mergeGeometries(geometries, false);
|
|
4482
|
-
const
|
|
4730
|
+
const totalVertices = mergedGeometry.attributes.position.count;
|
|
4731
|
+
const visibilityArray = new Float32Array(totalVertices);
|
|
4732
|
+
for (let i = 0; i < totalVertices; i++) {
|
|
4733
|
+
visibilityArray[i] = 1.0;
|
|
4734
|
+
}
|
|
4735
|
+
mergedGeometry.setAttribute("visibility", new BufferAttribute(visibilityArray, 1));
|
|
4736
|
+
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
4737
|
+
const mergedLine = new LineSegments(mergedGeometry, visibilityMaterial);
|
|
4483
4738
|
if (this.useVAO) {
|
|
4484
4739
|
this.createVAO(mergedLine);
|
|
4485
4740
|
}
|
|
4486
4741
|
rootGroup.add(mergedLine);
|
|
4487
4742
|
this.mergedLineSegments.add(mergedLine);
|
|
4488
4743
|
this.optimizedOriginalMap.set(mergedLine, optimizedObjects);
|
|
4744
|
+
this.mergedObjectMap.set(mergedLine.uuid, {
|
|
4745
|
+
objectMapping,
|
|
4746
|
+
visibilityArray,
|
|
4747
|
+
totalVertices,
|
|
4748
|
+
});
|
|
4749
|
+
this.mergedGeometryVisibility.set(mergedLine, visibilityArray);
|
|
4489
4750
|
mergedObjects.push(mergedLine);
|
|
4490
4751
|
geometries.forEach((geometry) => {
|
|
4491
4752
|
geometry.dispose();
|
|
@@ -4510,6 +4771,10 @@ class DynamicGltfLoader {
|
|
|
4510
4771
|
}
|
|
4511
4772
|
mergePointsGroups(materialGroups, rootGroup) {
|
|
4512
4773
|
for (const group of materialGroups) {
|
|
4774
|
+
if (!group.material) {
|
|
4775
|
+
console.warn("Skipping points group with null material");
|
|
4776
|
+
continue;
|
|
4777
|
+
}
|
|
4513
4778
|
try {
|
|
4514
4779
|
const geometries = [];
|
|
4515
4780
|
const optimizedObjects = [];
|
|
@@ -4692,97 +4957,51 @@ class DynamicGltfLoader {
|
|
|
4692
4957
|
});
|
|
4693
4958
|
this.syncHiddenObjects();
|
|
4694
4959
|
}
|
|
4695
|
-
|
|
4696
|
-
if (
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
for (
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4960
|
+
_updateVisibilityAttribute(mergedObject) {
|
|
4961
|
+
if (
|
|
4962
|
+
mergedObject.geometry &&
|
|
4963
|
+
mergedObject.geometry.attributes.visibility &&
|
|
4964
|
+
mergedObject.geometry.attributes.objectId
|
|
4965
|
+
) {
|
|
4966
|
+
const visibilityArray = mergedObject.geometry.attributes.visibility.array;
|
|
4967
|
+
const objectIdArray = mergedObject.geometry.attributes.objectId.array;
|
|
4968
|
+
for (let i = 0; i < visibilityArray.length; i++) {
|
|
4969
|
+
const objectId = objectIdArray[i];
|
|
4970
|
+
if (objectId < this.objectVisibility.length) {
|
|
4971
|
+
visibilityArray[i] = this.objectVisibility[objectId];
|
|
4972
|
+
}
|
|
4707
4973
|
}
|
|
4708
|
-
|
|
4974
|
+
mergedObject.geometry.attributes.visibility.needsUpdate = true;
|
|
4709
4975
|
}
|
|
4710
|
-
|
|
4976
|
+
}
|
|
4977
|
+
syncHiddenObjects() {
|
|
4978
|
+
if (this.mergedObjectMap.size === 0) {
|
|
4979
|
+
console.log("No merged objects to sync");
|
|
4711
4980
|
return;
|
|
4712
4981
|
}
|
|
4713
|
-
this.
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
objects.forEach((x) => this.oldOptimizeObjects.add(x));
|
|
4982
|
+
if (this.objectVisibility.length > 0) {
|
|
4983
|
+
for (let i = 0; i < this.objectVisibility.length; i++) {
|
|
4984
|
+
this.objectVisibility[i] = 1.0;
|
|
4717
4985
|
}
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
const updateListToOptimize = [];
|
|
4723
|
-
originObjects.forEach((obj) => {
|
|
4724
|
-
if (!this.hiddenHandles.has(obj.userData.handle)) {
|
|
4725
|
-
updateListToOptimize.push(obj);
|
|
4986
|
+
this.hiddenHandles.forEach((handle) => {
|
|
4987
|
+
const index = this.objectIdToIndex.get(handle);
|
|
4988
|
+
if (index !== undefined && index < this.objectVisibility.length) {
|
|
4989
|
+
this.objectVisibility[index] = 0.0;
|
|
4726
4990
|
}
|
|
4727
4991
|
});
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
|
|
4741
|
-
mergedObject.visible = true;
|
|
4742
|
-
optimizedObject.parent.add(mergedObject);
|
|
4743
|
-
this.newOptimizedObjects.add(mergedObject);
|
|
4744
|
-
geometries.forEach((geometry) => {
|
|
4745
|
-
geometry.dispose();
|
|
4746
|
-
});
|
|
4747
|
-
} else if (firstObject instanceof Line) {
|
|
4748
|
-
let totalVertices = 0;
|
|
4749
|
-
updateListToOptimize.map((line) => {
|
|
4750
|
-
totalVertices += line.geometry.attributes.position.count;
|
|
4751
|
-
});
|
|
4752
|
-
const positions = new Float32Array(totalVertices * 3);
|
|
4753
|
-
let posOffset = 0;
|
|
4754
|
-
const indices = [];
|
|
4755
|
-
let vertexOffset = 0;
|
|
4756
|
-
updateListToOptimize.forEach((line) => {
|
|
4757
|
-
const geometry = line.geometry;
|
|
4758
|
-
const positionAttr = geometry.attributes.position;
|
|
4759
|
-
const vertexCount = positionAttr.count;
|
|
4760
|
-
line.updateWorldMatrix(true, false);
|
|
4761
|
-
const matrix = line.matrixWorld;
|
|
4762
|
-
const vector = new Vector3();
|
|
4763
|
-
for (let i = 0; i < vertexCount; i++) {
|
|
4764
|
-
vector.fromBufferAttribute(positionAttr, i);
|
|
4765
|
-
vector.applyMatrix4(matrix);
|
|
4766
|
-
positions[posOffset++] = vector.x;
|
|
4767
|
-
positions[posOffset++] = vector.y;
|
|
4768
|
-
positions[posOffset++] = vector.z;
|
|
4769
|
-
}
|
|
4770
|
-
for (let i = 0; i < vertexCount - 1; i++) {
|
|
4771
|
-
indices.push(vertexOffset + i, vertexOffset + i + 1);
|
|
4772
|
-
}
|
|
4773
|
-
vertexOffset += vertexCount;
|
|
4774
|
-
});
|
|
4775
|
-
const geometry = new BufferGeometry();
|
|
4776
|
-
geometry.setAttribute("position", new BufferAttribute(positions, 3));
|
|
4777
|
-
geometry.setIndex(indices);
|
|
4778
|
-
geometry.computeBoundingSphere();
|
|
4779
|
-
geometry.computeBoundingBox();
|
|
4780
|
-
const mergedLine = new LineSegments(geometry, optimizedObject.material);
|
|
4781
|
-
mergedLine.visible = true;
|
|
4782
|
-
optimizedObject.parent.add(mergedLine);
|
|
4783
|
-
this.newOptimizedObjects.add(mergedLine);
|
|
4784
|
-
}
|
|
4785
|
-
});
|
|
4992
|
+
}
|
|
4993
|
+
for (const mesh of this.mergedMesh) {
|
|
4994
|
+
this._updateVisibilityAttribute(mesh);
|
|
4995
|
+
}
|
|
4996
|
+
for (const line of this.mergedLines) {
|
|
4997
|
+
this._updateVisibilityAttribute(line);
|
|
4998
|
+
}
|
|
4999
|
+
for (const lineSegment of this.mergedLineSegments) {
|
|
5000
|
+
this._updateVisibilityAttribute(lineSegment);
|
|
5001
|
+
}
|
|
5002
|
+
for (const point of this.mergedPoints) {
|
|
5003
|
+
this._updateVisibilityAttribute(point);
|
|
5004
|
+
}
|
|
4786
5005
|
}
|
|
4787
5006
|
getStructureGeometryExtent(structureId) {
|
|
4788
5007
|
const extent = new Box3();
|