@giszhc/three-model-viewer 1.0.0 → 1.1.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/README.md +34 -4
- package/dist/core/Viewer.d.ts +55 -0
- package/dist/index.cjs +4 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +377 -128
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +39 -37
- package/dist/index.umd.js.map +1 -1
- package/dist/loaders/ModelLoader.d.ts +57 -4
- package/dist/loaders/ZipExtractor.d.ts +7 -4
- package/dist/types/index.d.ts +8 -0
- package/package.json +10 -2
package/dist/index.js
CHANGED
|
@@ -5,10 +5,14 @@ import { CSS2DObject as r, CSS2DRenderer as i } from "three/addons/renderers/CSS
|
|
|
5
5
|
import * as a from "@tweenjs/tween.js";
|
|
6
6
|
import { OBJLoader as o } from "three/addons/loaders/OBJLoader.js";
|
|
7
7
|
import { MTLLoader as s } from "three/addons/loaders/MTLLoader.js";
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
8
|
+
import { GLTFLoader as c } from "three/addons/loaders/GLTFLoader.js";
|
|
9
|
+
import { DRACOLoader as l } from "three/addons/loaders/DRACOLoader.js";
|
|
10
|
+
import { KTX2Loader as u } from "three/addons/loaders/KTX2Loader.js";
|
|
11
|
+
import { MeshoptDecoder as d } from "three/addons/libs/meshopt_decoder.module.js";
|
|
12
|
+
import { acceleratedRaycast as f, computeBoundsTree as p, disposeBoundsTree as m } from "three-mesh-bvh";
|
|
13
|
+
import h from "jszip";
|
|
10
14
|
//#region src/core/SceneManager.ts
|
|
11
|
-
var
|
|
15
|
+
var g = class {
|
|
12
16
|
container;
|
|
13
17
|
scene;
|
|
14
18
|
camera;
|
|
@@ -73,7 +77,7 @@ var f = class {
|
|
|
73
77
|
destroy() {
|
|
74
78
|
this.isDestroyed = !0, this.animationFrameId !== null && cancelAnimationFrame(this.animationFrameId), this.resizeObserver && this.resizeObserver.disconnect(), this.controls.dispose(), this.renderer.dispose(), this.renderer.domElement.parentElement && this.renderer.domElement.parentElement.removeChild(this.renderer.domElement), this.labelRenderer.domElement.parentElement && this.labelRenderer.domElement.parentElement.removeChild(this.labelRenderer.domElement);
|
|
75
79
|
}
|
|
76
|
-
},
|
|
80
|
+
}, _ = class {
|
|
77
81
|
events;
|
|
78
82
|
constructor() {
|
|
79
83
|
this.events = /* @__PURE__ */ new Map();
|
|
@@ -100,52 +104,69 @@ var f = class {
|
|
|
100
104
|
removeAllListeners(e) {
|
|
101
105
|
return e ? this.events.delete(e) : this.events.clear(), this;
|
|
102
106
|
}
|
|
103
|
-
},
|
|
107
|
+
}, v = class {
|
|
104
108
|
static async extract(t, n) {
|
|
105
109
|
let r;
|
|
106
|
-
if (n?.(5, "
|
|
110
|
+
if (n?.(5, "正在读取压缩包文件流..."), typeof t == "string") {
|
|
107
111
|
let e = await fetch(t);
|
|
108
112
|
if (!e.ok) throw Error(`Failed to fetch zip file: ${e.statusText}`);
|
|
109
113
|
r = await e.arrayBuffer();
|
|
110
114
|
} else r = t instanceof Blob || t instanceof File ? await t.arrayBuffer() : t;
|
|
111
115
|
n?.(15, "正在解压 ZIP 文件包...");
|
|
112
|
-
let i = await
|
|
116
|
+
let i = await h.loadAsync(r), a = /* @__PURE__ */ new Map(), o = null, s = null, c = null, l = null, u = [
|
|
113
117
|
".png",
|
|
114
118
|
".jpg",
|
|
115
119
|
".jpeg",
|
|
116
120
|
".webp",
|
|
117
121
|
".bmp",
|
|
118
122
|
".tga",
|
|
119
|
-
".dds"
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
+
".dds",
|
|
124
|
+
".hdr",
|
|
125
|
+
".svg",
|
|
126
|
+
".ktx2"
|
|
127
|
+
], d = Object.keys(i.files), f = d.length || 1;
|
|
128
|
+
for (let e = 0; e < d.length; e++) {
|
|
129
|
+
let t = d[e], r = i.files[t];
|
|
123
130
|
if (r.dir || t.includes("__MACOSX") || t.split("/").pop()?.startsWith("._")) continue;
|
|
124
|
-
let
|
|
125
|
-
if (
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
131
|
+
let p = t.toLowerCase(), m = t.split("/").pop() || t, h = Math.round(20 + e / f * 35);
|
|
132
|
+
if (p.endsWith(".glb") && !o ? (o = r, n?.(h, `找到 GLB 二进制模型: ${m}`)) : p.endsWith(".gltf") && !s ? (s = r, n?.(h, `找到 GLTF 场景定义: ${m}`)) : p.endsWith(".obj") && !c ? (c = r, n?.(h, `找到 OBJ 网格模型: ${m}`)) : p.endsWith(".mtl") && !l && (l = r, n?.(h, `找到 MTL 材质定义: ${m}`)), p.endsWith(".bin")) {
|
|
133
|
+
n?.(h, `加载二进制缓冲区: ${m}`);
|
|
134
|
+
let e = await r.async("blob"), i = URL.createObjectURL(e);
|
|
135
|
+
a.set(t, i), a.set(m, i), a.set(m.toLowerCase(), i);
|
|
136
|
+
}
|
|
137
|
+
if (u.some((e) => p.endsWith(e))) {
|
|
138
|
+
n?.(h, `加载贴图资源: ${m}`);
|
|
139
|
+
let e = await r.async("blob"), i = URL.createObjectURL(e);
|
|
140
|
+
a.set(t, i), a.set(m, i), a.set(m.toLowerCase(), i);
|
|
130
141
|
}
|
|
131
142
|
}
|
|
132
|
-
|
|
133
|
-
let
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
143
|
+
n?.(60, "ZIP 资源索引提取完毕,准备解析三维模型网格...");
|
|
144
|
+
let p;
|
|
145
|
+
if (o) p = "glb";
|
|
146
|
+
else if (s) p = "gltf";
|
|
147
|
+
else if (c) p = "obj";
|
|
148
|
+
else throw a.forEach((e) => URL.revokeObjectURL(e)), Error("ZIP 压缩包中未检测到支持的 3D 模型文件(需要包含 .glb, .gltf 或 .obj 文件)");
|
|
149
|
+
let m, g, _ = null, v = null, y, b;
|
|
150
|
+
p === "glb" ? (y = await o.async("arraybuffer"), b = o.name) : p === "gltf" ? (y = await s.async("string"), b = s.name) : (m = await c.async("string"), g = c.name, l && (_ = await l.async("string"), v = l.name));
|
|
151
|
+
let x = new e.LoadingManager();
|
|
152
|
+
return x.setURLModifier((e) => {
|
|
153
|
+
let t = decodeURIComponent(e).replace(/^\.\//, ""), n = t.split("/").pop()?.split("\\").pop() || t;
|
|
154
|
+
if (a.has(e)) return a.get(e);
|
|
138
155
|
if (a.has(t)) return a.get(t);
|
|
139
156
|
if (a.has(n)) return a.get(n);
|
|
140
|
-
|
|
157
|
+
let r = n.toLowerCase();
|
|
158
|
+
for (let [e, t] of a.entries()) if (e.toLowerCase() === r || e.toLowerCase().endsWith("/" + r)) return t;
|
|
141
159
|
return e;
|
|
142
160
|
}), {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
161
|
+
format: p,
|
|
162
|
+
objContent: m,
|
|
163
|
+
objFileName: g,
|
|
164
|
+
mtlContent: _,
|
|
165
|
+
mtlFileName: v,
|
|
166
|
+
gltfContent: y,
|
|
167
|
+
gltfFileName: b,
|
|
147
168
|
blobUrls: a,
|
|
148
|
-
loadingManager:
|
|
169
|
+
loadingManager: x,
|
|
149
170
|
dispose: () => {
|
|
150
171
|
a.forEach((e) => {
|
|
151
172
|
try {
|
|
@@ -156,18 +177,63 @@ var f = class {
|
|
|
156
177
|
};
|
|
157
178
|
}
|
|
158
179
|
};
|
|
159
|
-
e.BufferGeometry.prototype.computeBoundsTree =
|
|
160
|
-
var
|
|
180
|
+
e.BufferGeometry.prototype.computeBoundsTree = p, e.BufferGeometry.prototype.disposeBoundsTree = m, e.Mesh.prototype.raycast = f;
|
|
181
|
+
var y = class {
|
|
161
182
|
currentZipContent = null;
|
|
183
|
+
customBlobUrls = [];
|
|
162
184
|
managedMaterials = [];
|
|
163
185
|
isTextureEnabled = !0;
|
|
164
186
|
displayStyle = "solid";
|
|
165
187
|
plainColor = 5016790;
|
|
166
188
|
currentClippingPlanes = [];
|
|
189
|
+
dracoDecoderPath = "https://www.gstatic.com/draco/versioned/decoders/1.5.7/";
|
|
190
|
+
dracoLoader = null;
|
|
191
|
+
ktx2TranscoderPath = "https://cdn.jsdelivr.net/npm/three@0.186.1/examples/jsm/libs/basis/";
|
|
192
|
+
ktx2Loader = null;
|
|
193
|
+
renderer = null;
|
|
194
|
+
constructor(e, t) {
|
|
195
|
+
typeof e == "string" ? (this.dracoDecoderPath = e, t && (this.renderer = t)) : typeof e == "object" && e && (e.dracoDecoderPath && (this.dracoDecoderPath = e.dracoDecoderPath), e.ktx2TranscoderPath && (this.ktx2TranscoderPath = e.ktx2TranscoderPath), this.renderer = e.renderer || t || null);
|
|
196
|
+
}
|
|
197
|
+
setRenderer(e) {
|
|
198
|
+
this.renderer = e, this.ktx2Loader && this.ktx2Loader.detectSupport(e);
|
|
199
|
+
}
|
|
200
|
+
setDracoDecoderPath(e) {
|
|
201
|
+
this.dracoDecoderPath = e, this.dracoLoader && this.dracoLoader.setDecoderPath(e);
|
|
202
|
+
}
|
|
203
|
+
setKTX2TranscoderPath(e) {
|
|
204
|
+
this.ktx2TranscoderPath = e, this.ktx2Loader && this.ktx2Loader.setTranscoderPath(e);
|
|
205
|
+
}
|
|
206
|
+
getDracoLoader() {
|
|
207
|
+
return this.dracoLoader || (this.dracoLoader = new l(), this.dracoLoader.setDecoderPath(this.dracoDecoderPath)), this.dracoLoader;
|
|
208
|
+
}
|
|
209
|
+
getKTX2Loader() {
|
|
210
|
+
if (!this.ktx2Loader) {
|
|
211
|
+
if (this.ktx2Loader = new u(), this.ktx2Loader.setTranscoderPath(this.ktx2TranscoderPath), this.renderer) this.ktx2Loader.detectSupport(this.renderer);
|
|
212
|
+
else if (typeof document < "u") try {
|
|
213
|
+
let t = document.createElement("canvas"), n = new e.WebGLRenderer({ canvas: t });
|
|
214
|
+
this.ktx2Loader.detectSupport(n), n.dispose();
|
|
215
|
+
} catch (e) {
|
|
216
|
+
console.warn("KTX2Loader: Failed to auto-detect WebGL compressed texture support", e);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return this.ktx2Loader;
|
|
220
|
+
}
|
|
221
|
+
createGLTFLoader(e) {
|
|
222
|
+
let t = new c(e);
|
|
223
|
+
return t.setDRACOLoader(this.getDracoLoader()), t.setKTX2Loader(this.getKTX2Loader()), t.setMeshoptDecoder(d), t;
|
|
224
|
+
}
|
|
167
225
|
async loadZip(e, t) {
|
|
168
226
|
this.cleanup();
|
|
169
|
-
let n = await
|
|
170
|
-
this.currentZipContent = n
|
|
227
|
+
let n = await v.extract(e, t);
|
|
228
|
+
if (this.currentZipContent = n, n.format === "glb" || n.format === "gltf") {
|
|
229
|
+
t?.(70, "正在解析 GLTF/GLB 网格结构与材质贴图...");
|
|
230
|
+
let e = this.createGLTFLoader(n.loadingManager), r = n.gltfContent, i = await new Promise((t, n) => {
|
|
231
|
+
e.parse(r, "", (e) => t(e), (e) => n(e));
|
|
232
|
+
});
|
|
233
|
+
t?.(88, "正在建立空间 BVH 加速结构与几何居中...");
|
|
234
|
+
let a = this.postProcessModel(i.scene, i.animations, n.format);
|
|
235
|
+
return t?.(100, "加载完成"), a;
|
|
236
|
+
}
|
|
171
237
|
let { objContent: r, mtlContent: i, loadingManager: a } = n;
|
|
172
238
|
t?.(65, "正在解析材质与贴图数据...");
|
|
173
239
|
let c = null;
|
|
@@ -176,48 +242,121 @@ var h = class {
|
|
|
176
242
|
c && l.setMaterials(c);
|
|
177
243
|
let u = typeof r == "string" ? r : new TextDecoder().decode(r), d = l.parse(u);
|
|
178
244
|
t?.(88, "正在建立空间 BVH 加速结构与几何居中...");
|
|
179
|
-
let f = this.postProcessModel(d);
|
|
245
|
+
let f = this.postProcessModel(d, [], "obj");
|
|
180
246
|
return t?.(100, "加载完成"), f;
|
|
181
247
|
}
|
|
182
|
-
async
|
|
183
|
-
this.cleanup()
|
|
184
|
-
let r =
|
|
185
|
-
|
|
186
|
-
let i = new o();
|
|
187
|
-
r && i.setMaterials(r);
|
|
188
|
-
let a = await i.loadAsync(e, (e) => {
|
|
248
|
+
async loadGLTF(e, t, n) {
|
|
249
|
+
this.cleanup();
|
|
250
|
+
let r = this.createGLTFLoader(t), i, a = typeof e == "string" && /\.glb(\?.*)?$/i.test(e);
|
|
251
|
+
typeof e == "string" ? (n?.(30, "正在请求 GLTF/GLB 模型数据..."), i = await r.loadAsync(e, (e) => {
|
|
189
252
|
if (e.lengthComputable && e.total > 0) {
|
|
190
|
-
let t = Math.round(
|
|
253
|
+
let t = Math.round(30 + e.loaded / e.total * 50);
|
|
191
254
|
n?.(t, `正在传输模型数据 (${Math.round(e.loaded / e.total * 100)}%)...`);
|
|
192
255
|
}
|
|
256
|
+
})) : (n?.(60, "正在解析 GLTF/GLB 二进制数据流..."), i = await new Promise((t, n) => {
|
|
257
|
+
r.parse(e, "", (e) => t(e), (e) => n(e));
|
|
258
|
+
})), n?.(88, "正在建立空间 BVH 加速结构与几何居中...");
|
|
259
|
+
let o = this.postProcessModel(i.scene, i.animations, a ? "glb" : "gltf");
|
|
260
|
+
return n?.(100, "加载完成"), o;
|
|
261
|
+
}
|
|
262
|
+
async loadGLB(e, t) {
|
|
263
|
+
if (e instanceof Blob || e instanceof File) {
|
|
264
|
+
let n = await e.arrayBuffer();
|
|
265
|
+
return this.loadGLTF(n, void 0, t);
|
|
266
|
+
}
|
|
267
|
+
return this.loadGLTF(e, void 0, t);
|
|
268
|
+
}
|
|
269
|
+
async loadOBJ(e, t, n, r) {
|
|
270
|
+
this.cleanup(), r?.(20, "正在加载材质定义...");
|
|
271
|
+
let i = null;
|
|
272
|
+
t && (i = await new s(n).loadAsync(t), i.preload()), r?.(50, "正在加载 OBJ 模型几何数据...");
|
|
273
|
+
let a = new o(n);
|
|
274
|
+
i && a.setMaterials(i);
|
|
275
|
+
let c = await a.loadAsync(e, (e) => {
|
|
276
|
+
if (e.lengthComputable && e.total > 0) {
|
|
277
|
+
let t = Math.round(50 + e.loaded / e.total * 35);
|
|
278
|
+
r?.(t, `正在传输模型数据 (${Math.round(e.loaded / e.total * 100)}%)...`);
|
|
279
|
+
}
|
|
193
280
|
});
|
|
194
|
-
|
|
195
|
-
let
|
|
196
|
-
return
|
|
281
|
+
r?.(88, "正在建立空间 BVH 加速结构与几何居中...");
|
|
282
|
+
let l = this.postProcessModel(c, [], "obj");
|
|
283
|
+
return r?.(100, "加载完成"), l;
|
|
284
|
+
}
|
|
285
|
+
async loadFiles(t, n) {
|
|
286
|
+
let r = Array.from(t);
|
|
287
|
+
if (r.length === 0) throw Error("未选择任何文件");
|
|
288
|
+
let i = r.find((e) => e.name.toLowerCase().endsWith(".zip"));
|
|
289
|
+
if (i) return this.loadZip(i, n);
|
|
290
|
+
let a = r.find((e) => e.name.toLowerCase().endsWith(".glb"));
|
|
291
|
+
if (a) return this.loadGLB(a, n);
|
|
292
|
+
let o = r.find((e) => e.name.toLowerCase().endsWith(".gltf"));
|
|
293
|
+
if (o) {
|
|
294
|
+
n?.(15, "正在建立 GLTF 关联资源映射表...");
|
|
295
|
+
let t = /* @__PURE__ */ new Map();
|
|
296
|
+
for (let e of r) {
|
|
297
|
+
let n = URL.createObjectURL(e);
|
|
298
|
+
this.customBlobUrls.push(n), t.set(e.name, n), t.set(e.name.toLowerCase(), n);
|
|
299
|
+
}
|
|
300
|
+
let i = new e.LoadingManager();
|
|
301
|
+
i.setURLModifier((e) => {
|
|
302
|
+
let n = decodeURIComponent(e).replace(/^\.\//, ""), r = n.split("/").pop()?.split("\\").pop() || n;
|
|
303
|
+
if (t.has(e)) return t.get(e);
|
|
304
|
+
if (t.has(n)) return t.get(n);
|
|
305
|
+
if (t.has(r)) return t.get(r);
|
|
306
|
+
let i = r.toLowerCase();
|
|
307
|
+
for (let [e, n] of t.entries()) if (e.toLowerCase() === i || e.toLowerCase().endsWith("/" + i)) return n;
|
|
308
|
+
return e;
|
|
309
|
+
});
|
|
310
|
+
let a = await o.text();
|
|
311
|
+
return this.loadGLTF(a, i, n);
|
|
312
|
+
}
|
|
313
|
+
let s = r.find((e) => e.name.toLowerCase().endsWith(".obj"));
|
|
314
|
+
if (s) {
|
|
315
|
+
let t = r.find((e) => e.name.toLowerCase().endsWith(".mtl")), i = /* @__PURE__ */ new Map();
|
|
316
|
+
for (let e of r) {
|
|
317
|
+
let t = URL.createObjectURL(e);
|
|
318
|
+
this.customBlobUrls.push(t), i.set(e.name, t), i.set(e.name.toLowerCase(), t);
|
|
319
|
+
}
|
|
320
|
+
let a = new e.LoadingManager();
|
|
321
|
+
a.setURLModifier((e) => {
|
|
322
|
+
let t = decodeURIComponent(e).replace(/^\.\//, ""), n = t.split("/").pop()?.split("\\").pop() || t;
|
|
323
|
+
if (i.has(e)) return i.get(e);
|
|
324
|
+
if (i.has(t)) return i.get(t);
|
|
325
|
+
if (i.has(n)) return i.get(n);
|
|
326
|
+
let r = n.toLowerCase();
|
|
327
|
+
for (let [e, t] of i.entries()) if (e.toLowerCase() === r || e.toLowerCase().endsWith("/" + r)) return t;
|
|
328
|
+
return e;
|
|
329
|
+
});
|
|
330
|
+
let o = i.get(s.name), c = t ? i.get(t.name) : void 0;
|
|
331
|
+
return this.loadOBJ(o, c, a, n);
|
|
332
|
+
}
|
|
333
|
+
throw Error("未识别到支持的 3D 模型文件(请提供 .glb, .gltf, .obj 或 .zip 格式)");
|
|
197
334
|
}
|
|
198
|
-
postProcessModel(t) {
|
|
199
|
-
let
|
|
335
|
+
postProcessModel(t, n, r = "obj") {
|
|
336
|
+
let i = 0, a = 0;
|
|
200
337
|
this.managedMaterials = [];
|
|
201
|
-
let
|
|
202
|
-
t && (t.anisotropy = 16, t.generateMipmaps = !0, t.minFilter = e.LinearMipmapLinearFilter, t.magFilter = e.LinearFilter, t.colorSpace = e.SRGBColorSpace, t.needsUpdate = !0);
|
|
203
|
-
},
|
|
338
|
+
let o = (t, n = !0) => {
|
|
339
|
+
t && (t.anisotropy = 16, t.generateMipmaps = !0, t.minFilter = e.LinearMipmapLinearFilter, t.magFilter = e.LinearFilter, n && !t.colorSpace && (t.colorSpace = e.SRGBColorSpace), t.needsUpdate = !0);
|
|
340
|
+
}, s = (t) => {
|
|
204
341
|
if (t.side = e.DoubleSide, t.needsUpdate = !0, "color" in t) {
|
|
205
342
|
let e = t;
|
|
206
|
-
|
|
343
|
+
o(e.map, !0), "emissiveMap" in e && o(e.emissiveMap, !0), "normalMap" in e && o(e.normalMap, !1), "bumpMap" in e && o(e.bumpMap, !1), "roughnessMap" in e && o(e.roughnessMap, !1), "metalnessMap" in e && o(e.metalnessMap, !1), "aoMap" in e && o(e.aoMap, !1), r === "obj" && !e.map && e.color && e.color.getHex() < 2236962 && e.color.setHex(11581636);
|
|
207
344
|
}
|
|
208
|
-
}
|
|
209
|
-
|
|
345
|
+
};
|
|
346
|
+
t.updateMatrixWorld(!0);
|
|
347
|
+
let c = new e.Box3().setFromObject(t), l = new e.Vector3(), u = new e.Vector3();
|
|
348
|
+
c.getCenter(l), c.getSize(u), t.traverse((t) => {
|
|
210
349
|
if (t.isMesh) {
|
|
211
|
-
let
|
|
212
|
-
|
|
350
|
+
let n = t;
|
|
351
|
+
n.castShadow = !0, n.receiveShadow = !0, n.material ? Array.isArray(n.material) ? n.material.forEach(s) : s(n.material) : n.material = new e.MeshStandardMaterial({
|
|
213
352
|
color: this.plainColor,
|
|
214
353
|
roughness: .45,
|
|
215
354
|
metalness: .12,
|
|
216
355
|
side: e.DoubleSide
|
|
217
356
|
});
|
|
218
|
-
let
|
|
219
|
-
if (
|
|
220
|
-
|
|
357
|
+
let r = n.geometry;
|
|
358
|
+
if (r) {
|
|
359
|
+
r.attributes.normal || r.computeVertexNormals(), r.computeBoundsTree && r.computeBoundsTree(), r.attributes.position && (i += r.attributes.position.count), r.index ? a += r.index.count / 3 : r.attributes.position && (a += r.attributes.position.count / 3);
|
|
221
360
|
let t = new e.MeshStandardMaterial({
|
|
222
361
|
color: this.plainColor,
|
|
223
362
|
roughness: .45,
|
|
@@ -225,21 +364,25 @@ var h = class {
|
|
|
225
364
|
side: e.DoubleSide,
|
|
226
365
|
clippingPlanes: this.currentClippingPlanes.length > 0 ? this.currentClippingPlanes : null,
|
|
227
366
|
clipShadows: !0
|
|
228
|
-
}),
|
|
229
|
-
mesh:
|
|
230
|
-
originalMaterial:
|
|
367
|
+
}), o = {
|
|
368
|
+
mesh: n,
|
|
369
|
+
originalMaterial: n.material,
|
|
231
370
|
plainMaterial: t
|
|
232
371
|
};
|
|
233
|
-
this.applyStyleToItem(
|
|
372
|
+
this.applyStyleToItem(o), this.managedMaterials.push(o);
|
|
234
373
|
}
|
|
235
374
|
}
|
|
236
|
-
})
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
375
|
+
});
|
|
376
|
+
let d = new e.Group();
|
|
377
|
+
return d.name = "gmv-model-root", t.position.set(-l.x, -l.y, -l.z), d.add(t), d.updateMatrixWorld(!0), {
|
|
378
|
+
model: d,
|
|
379
|
+
box: new e.Box3().setFromObject(d),
|
|
380
|
+
size: u,
|
|
381
|
+
center: l,
|
|
382
|
+
vertexCount: i,
|
|
383
|
+
faceCount: Math.round(a),
|
|
384
|
+
animations: n || [],
|
|
385
|
+
format: r
|
|
243
386
|
};
|
|
244
387
|
}
|
|
245
388
|
applyStyleToItem(e) {
|
|
@@ -303,14 +446,21 @@ var h = class {
|
|
|
303
446
|
}
|
|
304
447
|
}
|
|
305
448
|
cleanup() {
|
|
306
|
-
this.currentZipContent &&= (this.currentZipContent.dispose(), null)
|
|
449
|
+
this.currentZipContent &&= (this.currentZipContent.dispose(), null), this.customBlobUrls.length > 0 && (this.customBlobUrls.forEach((e) => {
|
|
450
|
+
try {
|
|
451
|
+
URL.revokeObjectURL(e);
|
|
452
|
+
} catch {}
|
|
453
|
+
}), this.customBlobUrls = []);
|
|
307
454
|
for (let e of this.managedMaterials) e.plainMaterial && e.plainMaterial.dispose(), e.mesh.geometry && e.mesh.geometry.disposeBoundsTree && e.mesh.geometry.disposeBoundsTree();
|
|
308
455
|
this.managedMaterials = [];
|
|
309
456
|
}
|
|
457
|
+
destroy() {
|
|
458
|
+
this.cleanup(), this.dracoLoader &&= (this.dracoLoader.dispose(), null), this.ktx2Loader &&= (this.ktx2Loader.dispose(), null);
|
|
459
|
+
}
|
|
310
460
|
};
|
|
311
461
|
//#endregion
|
|
312
462
|
//#region src/utils/math.ts
|
|
313
|
-
function
|
|
463
|
+
function b(t) {
|
|
314
464
|
let n = t.geometry;
|
|
315
465
|
if (!n) return 0;
|
|
316
466
|
let r = n.attributes.position;
|
|
@@ -322,15 +472,15 @@ function g(t) {
|
|
|
322
472
|
let e = n.index;
|
|
323
473
|
for (let t = 0; t < e.count; t += 3) {
|
|
324
474
|
let n = e.getX(t), l = e.getX(t + 1), u = e.getX(t + 2);
|
|
325
|
-
a.fromBufferAttribute(r, n).applyMatrix4(c), o.fromBufferAttribute(r, l).applyMatrix4(c), s.fromBufferAttribute(r, u).applyMatrix4(c), i +=
|
|
475
|
+
a.fromBufferAttribute(r, n).applyMatrix4(c), o.fromBufferAttribute(r, l).applyMatrix4(c), s.fromBufferAttribute(r, u).applyMatrix4(c), i += S(a, o, s);
|
|
326
476
|
}
|
|
327
|
-
} else for (let e = 0; e < r.count; e += 3) a.fromBufferAttribute(r, e).applyMatrix4(c), o.fromBufferAttribute(r, e + 1).applyMatrix4(c), s.fromBufferAttribute(r, e + 2).applyMatrix4(c), i +=
|
|
477
|
+
} else for (let e = 0; e < r.count; e += 3) a.fromBufferAttribute(r, e).applyMatrix4(c), o.fromBufferAttribute(r, e + 1).applyMatrix4(c), s.fromBufferAttribute(r, e + 2).applyMatrix4(c), i += S(a, o, s);
|
|
328
478
|
return Math.abs(i);
|
|
329
479
|
}
|
|
330
|
-
function
|
|
480
|
+
function x(t) {
|
|
331
481
|
let n = 0;
|
|
332
482
|
t.traverse((e) => {
|
|
333
|
-
e.isMesh && (n +=
|
|
483
|
+
e.isMesh && (n += b(e));
|
|
334
484
|
});
|
|
335
485
|
let r = new e.Box3().setFromObject(t), i = new e.Vector3();
|
|
336
486
|
r.getSize(i);
|
|
@@ -340,10 +490,10 @@ function _(t) {
|
|
|
340
490
|
bboxVolume: a
|
|
341
491
|
};
|
|
342
492
|
}
|
|
343
|
-
function
|
|
493
|
+
function S(e, t, n) {
|
|
344
494
|
return e.dot(t.clone().cross(n)) / 6;
|
|
345
495
|
}
|
|
346
|
-
function
|
|
496
|
+
function C(t) {
|
|
347
497
|
let n = t.length;
|
|
348
498
|
if (n < 3) return 0;
|
|
349
499
|
let r = new e.Vector3(0, 0, 0);
|
|
@@ -353,12 +503,12 @@ function y(t) {
|
|
|
353
503
|
}
|
|
354
504
|
return r.length() * .5;
|
|
355
505
|
}
|
|
356
|
-
function
|
|
506
|
+
function w(e, t = "m", n = 2) {
|
|
357
507
|
return Math.abs(e) < .001 ? `0.00 ${t}` : `${e.toFixed(n)} ${t}`;
|
|
358
508
|
}
|
|
359
509
|
//#endregion
|
|
360
510
|
//#region src/tools/BoundingBoxTool.ts
|
|
361
|
-
var
|
|
511
|
+
var T = class {
|
|
362
512
|
scene;
|
|
363
513
|
boxGroup;
|
|
364
514
|
wireframeBox = null;
|
|
@@ -388,25 +538,28 @@ var x = class {
|
|
|
388
538
|
}
|
|
389
539
|
attachToModel(t, n) {
|
|
390
540
|
this.detach(), this.currentModel = t, this.unit = n?.unit || "m", t.updateMatrixWorld(!0);
|
|
391
|
-
let i = new e.Box3();
|
|
541
|
+
let i = new e.Box3(), a = t.matrixWorld.clone().invert();
|
|
392
542
|
t.traverse((e) => {
|
|
393
543
|
if (e.isMesh) {
|
|
394
544
|
let t = e;
|
|
395
|
-
t.geometry && (t.geometry.boundingBox || t.geometry.computeBoundingBox(), t.geometry.boundingBox
|
|
545
|
+
if (t.geometry && (t.geometry.boundingBox || t.geometry.computeBoundingBox(), t.geometry.boundingBox)) {
|
|
546
|
+
let e = t.matrixWorld.clone().premultiply(a), n = t.geometry.boundingBox.clone().applyMatrix4(e);
|
|
547
|
+
i.union(n);
|
|
548
|
+
}
|
|
396
549
|
}
|
|
397
550
|
}), i.isEmpty() && i.setFromObject(t);
|
|
398
|
-
let
|
|
551
|
+
let o = i.min, s = i.max;
|
|
399
552
|
i.getSize(this.modelSize), this.localVertices = [
|
|
400
|
-
new e.Vector3(
|
|
401
|
-
new e.Vector3(
|
|
402
|
-
new e.Vector3(
|
|
403
|
-
new e.Vector3(
|
|
404
|
-
new e.Vector3(
|
|
405
|
-
new e.Vector3(
|
|
406
|
-
new e.Vector3(
|
|
407
|
-
new e.Vector3(
|
|
553
|
+
new e.Vector3(o.x, o.y, o.z),
|
|
554
|
+
new e.Vector3(s.x, o.y, o.z),
|
|
555
|
+
new e.Vector3(o.x, s.y, o.z),
|
|
556
|
+
new e.Vector3(s.x, s.y, o.z),
|
|
557
|
+
new e.Vector3(o.x, o.y, s.z),
|
|
558
|
+
new e.Vector3(s.x, o.y, s.z),
|
|
559
|
+
new e.Vector3(o.x, s.y, s.z),
|
|
560
|
+
new e.Vector3(s.x, s.y, s.z)
|
|
408
561
|
];
|
|
409
|
-
let
|
|
562
|
+
let c = [
|
|
410
563
|
0,
|
|
411
564
|
1,
|
|
412
565
|
2,
|
|
@@ -431,22 +584,22 @@ var x = class {
|
|
|
431
584
|
6,
|
|
432
585
|
3,
|
|
433
586
|
7
|
|
434
|
-
],
|
|
435
|
-
|
|
436
|
-
let
|
|
587
|
+
], l = new e.BufferGeometry(), u = new Float32Array(c.length * 3);
|
|
588
|
+
l.setAttribute("position", new e.BufferAttribute(u, 3));
|
|
589
|
+
let d = new e.LineBasicMaterial({
|
|
437
590
|
color: n?.color ? new e.Color(n.color) : 54015,
|
|
438
591
|
linewidth: 1,
|
|
439
592
|
transparent: !0,
|
|
440
593
|
opacity: .6,
|
|
441
594
|
depthTest: !0
|
|
442
595
|
});
|
|
443
|
-
this.wireframeBox = new e.LineSegments(
|
|
444
|
-
let d = document.createElement("div");
|
|
445
|
-
d.className = "gmv-dimension-badge dim-x", d.innerHTML = `<span>长 (X):</span> <strong>${b(this.modelSize.x, this.unit)}</strong>`, this.labelX = new r(d), this.boxGroup.add(this.labelX);
|
|
596
|
+
this.wireframeBox = new e.LineSegments(l, d), this.boxGroup.add(this.wireframeBox), this.lineX = this.createDynamicLine(15680580), this.lineY = this.createDynamicLine(1096065), this.lineZ = this.createDynamicLine(3900150);
|
|
446
597
|
let f = document.createElement("div");
|
|
447
|
-
f.className = "gmv-dimension-badge dim-
|
|
598
|
+
f.className = "gmv-dimension-badge dim-x", f.innerHTML = `<span>长 (X):</span> <strong>${w(this.modelSize.x, this.unit)}</strong>`, this.labelX = new r(f), this.boxGroup.add(this.labelX);
|
|
448
599
|
let p = document.createElement("div");
|
|
449
|
-
p.className = "gmv-dimension-badge dim-
|
|
600
|
+
p.className = "gmv-dimension-badge dim-y", p.innerHTML = `<span>高 (Y):</span> <strong>${w(this.modelSize.y, this.unit)}</strong>`, this.labelY = new r(p), this.boxGroup.add(this.labelY);
|
|
601
|
+
let m = document.createElement("div");
|
|
602
|
+
m.className = "gmv-dimension-badge dim-z", m.innerHTML = `<span>宽 (Z):</span> <strong>${w(this.modelSize.z, this.unit)}</strong>`, this.labelZ = new r(m), this.boxGroup.add(this.labelZ), this.setVisible(n?.visible ?? !1);
|
|
450
603
|
}
|
|
451
604
|
createDynamicLine(t) {
|
|
452
605
|
let n = new e.BufferGeometry().setFromPoints([new e.Vector3(), new e.Vector3()]), r = new e.LineBasicMaterial({
|
|
@@ -525,7 +678,7 @@ var x = class {
|
|
|
525
678
|
destroy() {
|
|
526
679
|
this.detach(), this.scene.remove(this.boxGroup);
|
|
527
680
|
}
|
|
528
|
-
},
|
|
681
|
+
}, E = class {
|
|
529
682
|
camera;
|
|
530
683
|
controls;
|
|
531
684
|
tweenGroup;
|
|
@@ -657,7 +810,7 @@ var x = class {
|
|
|
657
810
|
};
|
|
658
811
|
//#endregion
|
|
659
812
|
//#region src/utils/snapping.ts
|
|
660
|
-
function
|
|
813
|
+
function D(t, n, r, i = 15, a = 800, o = 600) {
|
|
661
814
|
if (!r || r.length === 0) return {
|
|
662
815
|
hit: !1,
|
|
663
816
|
point: null,
|
|
@@ -709,7 +862,7 @@ function C(t, n, r, i = 15, a = 800, o = 600) {
|
|
|
709
862
|
}
|
|
710
863
|
//#endregion
|
|
711
864
|
//#region src/tools/ClippingTool.ts
|
|
712
|
-
var
|
|
865
|
+
var O = class {
|
|
713
866
|
scene;
|
|
714
867
|
camera;
|
|
715
868
|
container;
|
|
@@ -1156,7 +1309,7 @@ var w = class {
|
|
|
1156
1309
|
return this.customPlane !== null;
|
|
1157
1310
|
}
|
|
1158
1311
|
handleCustomPointPick(t) {
|
|
1159
|
-
let n = this.container.getBoundingClientRect(), r =
|
|
1312
|
+
let n = this.container.getBoundingClientRect(), r = D(new e.Vector2((t.clientX - n.left) / n.width * 2 - 1, -((t.clientY - n.top) / n.height) * 2 + 1), this.camera, this.modelLoader.getMeshes(), 15, n.width, n.height);
|
|
1160
1313
|
r.hit && r.point && this.addCustomPoint(r.point);
|
|
1161
1314
|
}
|
|
1162
1315
|
addCustomPoint(t) {
|
|
@@ -1223,7 +1376,7 @@ var w = class {
|
|
|
1223
1376
|
destroy() {
|
|
1224
1377
|
this.cancelCustomClip(), this.resetAll(), this.clearPlaneWidgets(), this.scene.remove(this.planesGroup), this.scene.remove(this.customMarkersGroup), this.container.removeEventListener("pointerdown", this.onPointerDownBound, { capture: !0 }), this.container.removeEventListener("pointermove", this.onPointerMoveBound), this.container.removeEventListener("dblclick", this.onDoubleClickBound, { capture: !0 }), window.removeEventListener("pointermove", this.onPointerMoveDragBound, { capture: !0 }), window.removeEventListener("pointerup", this.onPointerUpDragBound, { capture: !0 });
|
|
1225
1378
|
}
|
|
1226
|
-
},
|
|
1379
|
+
}, k = class {
|
|
1227
1380
|
scene;
|
|
1228
1381
|
camera;
|
|
1229
1382
|
container;
|
|
@@ -1275,12 +1428,12 @@ var w = class {
|
|
|
1275
1428
|
}
|
|
1276
1429
|
handlePointerMove(t) {
|
|
1277
1430
|
if (this.currentMode === "none") return;
|
|
1278
|
-
let n = this.container.getBoundingClientRect(), r =
|
|
1431
|
+
let n = this.container.getBoundingClientRect(), r = D(new e.Vector2((t.clientX - n.left) / n.width * 2 - 1, -((t.clientY - n.top) / n.height) * 2 + 1), this.camera, this.modelLoader.getMeshes(), 15, n.width, n.height);
|
|
1279
1432
|
!r.hit || !r.point ? (this.container.style.cursor = "not-allowed", this.snapCursorMesh.visible = !1) : (this.container.style.cursor = "crosshair", this.snapCursorMesh.visible = !0, this.snapCursorMesh.position.copy(r.point), r.isVertexSnapped ? (this.snapCursorMesh.material.color.setHex(16007006), this.snapCursorMesh.userData.fixedScreenRadius = 7.5) : (this.snapCursorMesh.material.color.setHex(3718648), this.snapCursorMesh.userData.fixedScreenRadius = 5.5), this.updateSingleMeshScale(this.snapCursorMesh), this.activePoints.length > 0 && this.updateDynamicPreview(r.point));
|
|
1280
1433
|
}
|
|
1281
1434
|
handlePointerDown(t) {
|
|
1282
1435
|
if (this.currentMode === "none" || t.button !== 0) return;
|
|
1283
|
-
let n = this.container.getBoundingClientRect(), r =
|
|
1436
|
+
let n = this.container.getBoundingClientRect(), r = D(new e.Vector2((t.clientX - n.left) / n.width * 2 - 1, -((t.clientY - n.top) / n.height) * 2 + 1), this.camera, this.modelLoader.getMeshes(), 15, n.width, n.height);
|
|
1284
1437
|
if (!r.hit || !r.point) return;
|
|
1285
1438
|
let i = r.point.clone();
|
|
1286
1439
|
this.activePoints.push(i), this.addActiveMarker(i), this.emitter.emit("measure:change", [...this.activePoints]), this.currentMode === "distance" && this.activePoints.length === 2 ? this.finishDistanceMeasurement() : this.currentMode === "height" && this.activePoints.length === 2 ? this.finishHeightMeasurement() : this.currentMode === "angle" && this.activePoints.length === 3 && this.finishAngleMeasurement();
|
|
@@ -1315,14 +1468,14 @@ var w = class {
|
|
|
1315
1468
|
}), l = new e.Line(s, c);
|
|
1316
1469
|
o.add(l), this.addEndSphere(o, t, 3900150), this.addEndSphere(o, n, 3900150);
|
|
1317
1470
|
let u = document.createElement("div");
|
|
1318
|
-
u.className = "gmv-measure-badge distance", u.innerHTML = `<span>距离:</span> <strong>${
|
|
1471
|
+
u.className = "gmv-measure-badge distance", u.innerHTML = `<span>距离:</span> <strong>${w(i, this.unit)}</strong>`;
|
|
1319
1472
|
let d = new r(u);
|
|
1320
1473
|
d.position.copy(a), o.add(d), this.measurementGroup.add(o);
|
|
1321
1474
|
let f = {
|
|
1322
1475
|
id: `dist_${Date.now()}`,
|
|
1323
1476
|
type: "distance",
|
|
1324
1477
|
value: i,
|
|
1325
|
-
formattedValue:
|
|
1478
|
+
formattedValue: w(i, this.unit),
|
|
1326
1479
|
unit: this.unit,
|
|
1327
1480
|
points: [t, n]
|
|
1328
1481
|
};
|
|
@@ -1349,16 +1502,16 @@ var w = class {
|
|
|
1349
1502
|
s.add(_), this.addEndSphere(s, t, 1096065), this.addEndSphere(s, n, 15680580), this.addEndSphere(s, d, 16436245, 4);
|
|
1350
1503
|
let v = new e.Vector3().addVectors(d, n).multiplyScalar(.5), y = document.createElement("div");
|
|
1351
1504
|
y.className = "gmv-measure-badge height", y.innerHTML = `
|
|
1352
|
-
<div><span>高差 (ΔH):</span> <strong>${
|
|
1353
|
-
<div style="font-size:10px;opacity:0.85;">水平: ${
|
|
1505
|
+
<div><span>高差 (ΔH):</span> <strong>${w(i, this.unit)}</strong></div>
|
|
1506
|
+
<div style="font-size:10px;opacity:0.85;">水平: ${w(a, this.unit)} · 直线: ${w(o, this.unit)}</div>
|
|
1354
1507
|
`;
|
|
1355
|
-
let
|
|
1356
|
-
|
|
1357
|
-
let
|
|
1508
|
+
let b = new r(y);
|
|
1509
|
+
b.position.copy(v), s.add(b), this.measurementGroup.add(s);
|
|
1510
|
+
let x = {
|
|
1358
1511
|
id: `height_${Date.now()}`,
|
|
1359
1512
|
type: "height",
|
|
1360
1513
|
value: i,
|
|
1361
|
-
formattedValue:
|
|
1514
|
+
formattedValue: w(i, this.unit),
|
|
1362
1515
|
unit: this.unit,
|
|
1363
1516
|
points: [t, n],
|
|
1364
1517
|
extra: {
|
|
@@ -1366,11 +1519,11 @@ var w = class {
|
|
|
1366
1519
|
horizontalDistance: a
|
|
1367
1520
|
}
|
|
1368
1521
|
};
|
|
1369
|
-
this.results.push(
|
|
1522
|
+
this.results.push(x), this.emitter.emit("measure:complete", x), this.cancelActive(), this.setMode("none");
|
|
1370
1523
|
}
|
|
1371
1524
|
finishAreaMeasurement() {
|
|
1372
1525
|
if (this.activePoints.length < 3) return;
|
|
1373
|
-
let t = [...this.activePoints], n =
|
|
1526
|
+
let t = [...this.activePoints], n = C(t), i = new e.Group(), a = [...t, t[0]], o = new e.BufferGeometry().setFromPoints(a), s = new e.LineBasicMaterial({
|
|
1374
1527
|
color: 9133302,
|
|
1375
1528
|
linewidth: 2,
|
|
1376
1529
|
depthTest: !1
|
|
@@ -1379,14 +1532,14 @@ var w = class {
|
|
|
1379
1532
|
let l = new e.Vector3();
|
|
1380
1533
|
t.forEach((e) => l.add(e)), l.divideScalar(t.length);
|
|
1381
1534
|
let u = document.createElement("div");
|
|
1382
|
-
u.className = "gmv-measure-badge area", u.innerHTML = `<span>面积:</span> <strong>${
|
|
1535
|
+
u.className = "gmv-measure-badge area", u.innerHTML = `<span>面积:</span> <strong>${w(n, `${this.unit}²`)}</strong>`;
|
|
1383
1536
|
let d = new r(u);
|
|
1384
1537
|
d.position.copy(l), i.add(d), this.measurementGroup.add(i);
|
|
1385
1538
|
let f = {
|
|
1386
1539
|
id: `area_${Date.now()}`,
|
|
1387
1540
|
type: "area",
|
|
1388
1541
|
value: n,
|
|
1389
|
-
formattedValue:
|
|
1542
|
+
formattedValue: w(n, `${this.unit}²`),
|
|
1390
1543
|
unit: `${this.unit}²`,
|
|
1391
1544
|
points: t,
|
|
1392
1545
|
extra: { area: n }
|
|
@@ -1507,7 +1660,7 @@ var w = class {
|
|
|
1507
1660
|
destroy() {
|
|
1508
1661
|
this.removeListeners(), this.clearAll(), this.scene.remove(this.measurementGroup), this.scene.remove(this.activePreviewGroup), this.scene.remove(this.snapCursorMesh);
|
|
1509
1662
|
}
|
|
1510
|
-
},
|
|
1663
|
+
}, A = class {
|
|
1511
1664
|
renderer;
|
|
1512
1665
|
scene;
|
|
1513
1666
|
camera;
|
|
@@ -1593,7 +1746,7 @@ var w = class {
|
|
|
1593
1746
|
}), this.renderer.render(this.scene, this.camera);
|
|
1594
1747
|
}
|
|
1595
1748
|
}
|
|
1596
|
-
},
|
|
1749
|
+
}, j = class extends _ {
|
|
1597
1750
|
sceneManager;
|
|
1598
1751
|
modelLoader;
|
|
1599
1752
|
boundingBoxTool;
|
|
@@ -1605,8 +1758,22 @@ var w = class {
|
|
|
1605
1758
|
currentModelInfo = null;
|
|
1606
1759
|
unit = "m";
|
|
1607
1760
|
defaultShowBoundingBox = !1;
|
|
1761
|
+
animationMixer = null;
|
|
1762
|
+
animationClips = [];
|
|
1763
|
+
activeAction = null;
|
|
1764
|
+
currentAnimationName = null;
|
|
1765
|
+
animationClock = new e.Clock();
|
|
1766
|
+
isAnimationActive = !1;
|
|
1608
1767
|
constructor(e) {
|
|
1609
|
-
super(), this.unit = e.unit || "m", this.defaultShowBoundingBox = e.showBoundingBox ?? !1, this.sceneManager = new
|
|
1768
|
+
super(), this.unit = e.unit || "m", this.defaultShowBoundingBox = e.showBoundingBox ?? !1, this.sceneManager = new g(e), this.modelLoader = new y({
|
|
1769
|
+
dracoDecoderPath: e.dracoDecoderPath,
|
|
1770
|
+
ktx2TranscoderPath: e.ktx2TranscoderPath,
|
|
1771
|
+
renderer: this.sceneManager.renderer
|
|
1772
|
+
}), this.boundingBoxTool = new T(this.sceneManager.scene), this.cameraTool = new E(this.sceneManager.camera, this.sceneManager.controls, this.sceneManager.tweenGroup), this.clippingTool = new O(this.sceneManager.scene, this.sceneManager.camera, this.sceneManager.container, this.modelLoader, this.sceneManager.controls, this), this.measurementTool = new k(this.sceneManager.scene, this.sceneManager.camera, this.sceneManager.container, this.modelLoader, this, this.sceneManager.controls), this.measurementTool.setUnit(this.unit), this.screenshotTool = new A(this.sceneManager.renderer, this.sceneManager.scene, this.sceneManager.camera, () => this.currentModel), this.measurementTool.setUnit(this.unit), this.sceneManager.onBeforeRender = () => {
|
|
1773
|
+
if (this.animationMixer && this.isAnimationActive) {
|
|
1774
|
+
let e = this.animationClock.getDelta();
|
|
1775
|
+
this.animationMixer.update(e);
|
|
1776
|
+
}
|
|
1610
1777
|
this.boundingBoxTool.update(this.sceneManager.camera), this.cameraTool.updatePerFrame(), this.measurementTool.updatePerFrame(), this.clippingTool.updatePerFrame();
|
|
1611
1778
|
};
|
|
1612
1779
|
}
|
|
@@ -1625,7 +1792,7 @@ var w = class {
|
|
|
1625
1792
|
async loadOBJ(e, t) {
|
|
1626
1793
|
try {
|
|
1627
1794
|
this.emit("load:start", e), this.clearModel();
|
|
1628
|
-
let n = await this.modelLoader.loadOBJ(e, t, (e, t) => {
|
|
1795
|
+
let n = await this.modelLoader.loadOBJ(e, t, void 0, (e, t) => {
|
|
1629
1796
|
this.emit("load:progress", e, t);
|
|
1630
1797
|
});
|
|
1631
1798
|
return this.setupLoadedModel(n), this.emit("load:success", n), n;
|
|
@@ -1634,6 +1801,60 @@ var w = class {
|
|
|
1634
1801
|
throw this.emit("load:error", t), t;
|
|
1635
1802
|
}
|
|
1636
1803
|
}
|
|
1804
|
+
async loadGLTF(e) {
|
|
1805
|
+
try {
|
|
1806
|
+
this.emit("load:start", typeof e == "string" ? e : "GLTF Data"), this.clearModel();
|
|
1807
|
+
let t = await this.modelLoader.loadGLTF(e, void 0, (e, t) => {
|
|
1808
|
+
this.emit("load:progress", e, t);
|
|
1809
|
+
});
|
|
1810
|
+
return this.setupLoadedModel(t), this.emit("load:success", t), t;
|
|
1811
|
+
} catch (e) {
|
|
1812
|
+
let t = e instanceof Error ? e : Error(String(e));
|
|
1813
|
+
throw this.emit("load:error", t), t;
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
async loadGLB(e) {
|
|
1817
|
+
try {
|
|
1818
|
+
let t = typeof e == "string" ? e : e instanceof File ? e.name : "GLB Model";
|
|
1819
|
+
this.emit("load:start", t), this.clearModel();
|
|
1820
|
+
let n = await this.modelLoader.loadGLB(e, (e, t) => {
|
|
1821
|
+
this.emit("load:progress", e, t);
|
|
1822
|
+
});
|
|
1823
|
+
return this.setupLoadedModel(n), this.emit("load:success", n), n;
|
|
1824
|
+
} catch (e) {
|
|
1825
|
+
let t = e instanceof Error ? e : Error(String(e));
|
|
1826
|
+
throw this.emit("load:error", t), t;
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
async loadFiles(e) {
|
|
1830
|
+
try {
|
|
1831
|
+
let t = Array.from(e)[0]?.name || "Files";
|
|
1832
|
+
this.emit("load:start", t), this.clearModel();
|
|
1833
|
+
let n = await this.modelLoader.loadFiles(e, (e, t) => {
|
|
1834
|
+
this.emit("load:progress", e, t);
|
|
1835
|
+
});
|
|
1836
|
+
return this.setupLoadedModel(n), this.emit("load:success", n), n;
|
|
1837
|
+
} catch (e) {
|
|
1838
|
+
let t = e instanceof Error ? e : Error(String(e));
|
|
1839
|
+
throw this.emit("load:error", t), t;
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
async loadFromUrl(e) {
|
|
1843
|
+
let t = e.split("?")[0].toLowerCase();
|
|
1844
|
+
if (t.endsWith(".glb")) return this.loadGLB(e);
|
|
1845
|
+
if (t.endsWith(".gltf")) return this.loadGLTF(e);
|
|
1846
|
+
if (t.endsWith(".zip")) return this.loadZip(e);
|
|
1847
|
+
if (t.endsWith(".obj")) return this.loadOBJ(e);
|
|
1848
|
+
try {
|
|
1849
|
+
return await this.loadGLB(e);
|
|
1850
|
+
} catch {
|
|
1851
|
+
try {
|
|
1852
|
+
return await this.loadZip(e);
|
|
1853
|
+
} catch {
|
|
1854
|
+
return await this.loadOBJ(e);
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1637
1858
|
loadSampleGeometry(t = "mechanical") {
|
|
1638
1859
|
this.clearModel();
|
|
1639
1860
|
let n = new e.Group();
|
|
@@ -1678,14 +1899,14 @@ var w = class {
|
|
|
1678
1899
|
let r = this.modelLoader.postProcessModel(n);
|
|
1679
1900
|
return this.setupLoadedModel(r), this.emit("load:success", r), r;
|
|
1680
1901
|
}
|
|
1681
|
-
setupLoadedModel(
|
|
1682
|
-
this.currentModel =
|
|
1902
|
+
setupLoadedModel(t) {
|
|
1903
|
+
this.currentModel = t.model, this.currentModel.name = "gmv-current-model", this.currentModelInfo = t, this.sceneManager.scene.add(this.currentModel), t.animations && t.animations.length > 0 ? (this.animationClips = t.animations, this.animationMixer = new e.AnimationMixer(this.currentModel), this.playAnimation(0)) : (this.animationClips = [], this.animationMixer = null, this.activeAction = null, this.currentAnimationName = null, this.isAnimationActive = !1), this.boundingBoxTool.attachToModel(this.currentModel, {
|
|
1683
1904
|
visible: this.defaultShowBoundingBox,
|
|
1684
1905
|
unit: this.unit
|
|
1685
|
-
}), this.clippingTool.setModelBounds(
|
|
1906
|
+
}), this.clippingTool.setModelBounds(t.box), this.cameraTool.setView("front", this.currentModel, 0);
|
|
1686
1907
|
}
|
|
1687
1908
|
clearModel() {
|
|
1688
|
-
this.measurementTool.clearAll(), this.clippingTool.resetAll(), this.boundingBoxTool.detach(), this.currentModel &&= (this.sceneManager.scene.remove(this.currentModel), null), this.currentModelInfo = null, this.modelLoader.cleanup();
|
|
1909
|
+
this.animationMixer &&= (this.animationMixer.stopAllAction(), this.currentModel && this.animationMixer.uncacheRoot(this.currentModel), null), this.animationClips = [], this.activeAction = null, this.currentAnimationName = null, this.isAnimationActive = !1, this.measurementTool.clearAll(), this.clippingTool.resetAll(), this.boundingBoxTool.detach(), this.currentModel &&= (this.sceneManager.scene.remove(this.currentModel), null), this.currentModelInfo = null, this.modelLoader.cleanup();
|
|
1689
1910
|
}
|
|
1690
1911
|
setBackground(e, t) {
|
|
1691
1912
|
this.sceneManager.setBackground(e, t);
|
|
@@ -1865,11 +2086,39 @@ var w = class {
|
|
|
1865
2086
|
off(e, t) {
|
|
1866
2087
|
return super.off(e, t);
|
|
1867
2088
|
}
|
|
2089
|
+
getAnimations() {
|
|
2090
|
+
return this.animationClips.map((e, t) => e.name || `Animation ${t + 1}`);
|
|
2091
|
+
}
|
|
2092
|
+
getCurrentAnimation() {
|
|
2093
|
+
return this.currentAnimationName;
|
|
2094
|
+
}
|
|
2095
|
+
playAnimation(e = 0) {
|
|
2096
|
+
if (!this.animationMixer || this.animationClips.length === 0) return;
|
|
2097
|
+
let t;
|
|
2098
|
+
if (t = typeof e == "number" ? this.animationClips[e] : this.animationClips.find((t, n) => t.name === e || `Animation ${n + 1}` === e), t ||= this.animationClips[0], !t) return;
|
|
2099
|
+
let n = this.animationMixer.clipAction(t);
|
|
2100
|
+
this.activeAction && this.activeAction !== n ? (this.activeAction.fadeOut(.3), n.reset().fadeIn(.3).play()) : n.play(), this.activeAction = n, this.currentAnimationName = t.name || "Animation 1", this.isAnimationActive = !0, this.animationClock.getDelta(), this.emit("animation:play", this.currentAnimationName);
|
|
2101
|
+
}
|
|
2102
|
+
pauseAnimation() {
|
|
2103
|
+
this.isAnimationActive = !1, this.emit("animation:pause");
|
|
2104
|
+
}
|
|
2105
|
+
resumeAnimation() {
|
|
2106
|
+
this.animationMixer && this.activeAction && (this.isAnimationActive = !0, this.animationClock.getDelta(), this.emit("animation:play", this.currentAnimationName || ""));
|
|
2107
|
+
}
|
|
2108
|
+
stopAnimation() {
|
|
2109
|
+
this.isAnimationActive = !1, this.activeAction && this.activeAction.stop(), this.emit("animation:stop");
|
|
2110
|
+
}
|
|
2111
|
+
isAnimationPlaying() {
|
|
2112
|
+
return this.isAnimationActive;
|
|
2113
|
+
}
|
|
2114
|
+
setAnimationSpeed(e) {
|
|
2115
|
+
this.animationMixer && (this.animationMixer.timeScale = Math.max(0, e), this.emit("animation:speed", e));
|
|
2116
|
+
}
|
|
1868
2117
|
destroy() {
|
|
1869
|
-
this.clearModel(), this.measurementTool.destroy(), this.clippingTool.destroy(), this.sceneManager.destroy(), this.removeAllListeners();
|
|
2118
|
+
this.clearModel(), this.modelLoader.destroy(), this.measurementTool.destroy(), this.clippingTool.destroy(), this.sceneManager.destroy(), this.removeAllListeners();
|
|
1870
2119
|
}
|
|
1871
2120
|
};
|
|
1872
2121
|
//#endregion
|
|
1873
|
-
export {
|
|
2122
|
+
export { T as BoundingBoxTool, E as CameraTool, O as ClippingTool, _ as EventEmitter, k as MeasurementTool, y as ModelLoader, g as SceneManager, A as ScreenshotTool, j as Viewer, v as ZipExtractor, C as compute3DPolygonArea, x as computeGroupVolume, b as computeMeshVolume, D as findSnapPoint, w as formatUnit };
|
|
1874
2123
|
|
|
1875
2124
|
//# sourceMappingURL=index.js.map
|