@ridp/threejs 1.4.0 → 1.4.2

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.
Files changed (55) hide show
  1. package/dist/hooks.cjs +1 -1
  2. package/dist/hooks.js +12 -9
  3. package/dist/packages/threejs/package.json.cjs +1 -0
  4. package/dist/packages/threejs/package.json.js +4 -0
  5. package/dist/packages/threejs/src/hooks/useBatchGLTFLoader.cjs +1 -0
  6. package/dist/packages/threejs/src/hooks/useBatchGLTFLoader.js +83 -0
  7. package/dist/packages/threejs/src/hooks/useGLTFLoader.cjs +1 -0
  8. package/dist/packages/threejs/src/hooks/useGLTFLoader.js +292 -0
  9. package/dist/packages/threejs/src/hooks/useObb.cjs +1 -0
  10. package/dist/packages/threejs/src/hooks/useObb.js +41 -0
  11. package/dist/packages/threejs/src/hooks/useRaycaster.cjs +1 -0
  12. package/dist/packages/threejs/src/hooks/useRaycaster.js +35 -0
  13. package/dist/packages/threejs/src/hooks/useThreeJs.cjs +5 -0
  14. package/dist/packages/threejs/src/hooks/useThreeJs.js +153 -0
  15. package/dist/packages/threejs/src/instance/IDBCache.cjs +1 -0
  16. package/dist/packages/threejs/src/instance/IDBCache.js +142 -0
  17. package/dist/packages/threejs/src/instance/threeIns.cjs +3 -0
  18. package/dist/packages/threejs/src/instance/threeIns.js +369 -0
  19. package/dist/packages/threejs/src/utils/CacheMonitor.cjs +1 -0
  20. package/dist/packages/threejs/src/utils/CacheMonitor.js +125 -0
  21. package/dist/packages/threejs/src/utils/ImageLoader.cjs +1 -0
  22. package/dist/packages/threejs/src/utils/ImageLoader.js +33 -0
  23. package/dist/packages/threejs/src/utils/PredictiveLoader.cjs +1 -0
  24. package/dist/packages/threejs/src/utils/PredictiveLoader.js +155 -0
  25. package/dist/packages/threejs/src/utils/RetryHelper.cjs +1 -0
  26. package/dist/packages/threejs/src/utils/RetryHelper.js +108 -0
  27. package/dist/packages/threejs/src/utils/common.cjs +1 -0
  28. package/dist/packages/threejs/src/utils/common.js +15 -0
  29. package/dist/packages/threejs/src/utils/css3dHelper.cjs +15 -0
  30. package/dist/packages/threejs/src/utils/css3dHelper.js +42 -0
  31. package/dist/packages/threejs/src/utils/disposeObject.cjs +1 -0
  32. package/dist/packages/threejs/src/utils/disposeObject.js +13 -0
  33. package/dist/packages/threejs/src/utils/helper.cjs +1 -0
  34. package/dist/packages/threejs/src/utils/helper.js +47 -0
  35. package/dist/packages/threejs/src/utils/modelSerialize.cjs +1 -0
  36. package/dist/packages/threejs/src/utils/modelSerialize.js +225 -0
  37. package/dist/packages/threejs/src/utils/sceneRebuilder.cjs +1 -0
  38. package/dist/packages/threejs/src/utils/sceneRebuilder.js +138 -0
  39. package/dist/packages/threejs/src/workers/gltfParser.worker.cjs +1 -0
  40. package/dist/packages/threejs/src/workers/gltfParser.worker.js +11 -0
  41. package/dist/packages/threejs/src/workers/gltfParserOptimized.worker.cjs +1 -0
  42. package/dist/packages/threejs/src/workers/gltfParserOptimized.worker.js +11 -0
  43. package/dist/threejs.cjs +1 -3
  44. package/dist/threejs.js +58 -404
  45. package/dist/utils.cjs +1 -1
  46. package/dist/utils.js +40 -32
  47. package/package.json +1 -1
  48. package/dist/ImageLoader-DXx88iwh.js +0 -1444
  49. package/dist/ImageLoader-DzG6sgbB.cjs +0 -24
  50. package/dist/PredictiveLoader--_3bEnce.js +0 -3738
  51. package/dist/PredictiveLoader-CpRi-ULa.cjs +0 -2
  52. package/dist/useBatchGLTFLoader-CDNvTMtt.cjs +0 -5
  53. package/dist/useBatchGLTFLoader-Dg-xau9i.js +0 -493
  54. /package/dist/{modelOptimizer-A0Cs6f9e.cjs → packages/threejs/src/utils/modelOptimizer.cjs} +0 -0
  55. /package/dist/{modelOptimizer-BRPnM2RH.js → packages/threejs/src/utils/modelOptimizer.js} +0 -0
@@ -0,0 +1,369 @@
1
+ var A = Object.defineProperty;
2
+ var H = (p, e, t) => e in p ? A(p, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : p[e] = t;
3
+ var i = (p, e, t) => H(p, typeof e != "symbol" ? e + "" : e, t);
4
+ import { MathUtils as g, Scene as V, PerspectiveCamera as P, WebGLRenderer as q, Box3 as X, Vector3 as d, Box3Helper as Y } from "three";
5
+ import { CSS3DRenderer as Z } from "../../../../node_modules/.pnpm/three@0.178.0/node_modules/three/examples/jsm/renderers/CSS3DRenderer.js";
6
+ import j from "../../../../node_modules/.pnpm/three@0.178.0/node_modules/three/examples/jsm/libs/stats.module.js";
7
+ import { createOrbitControl as B } from "../utils/helper.js";
8
+ import { disposeThreeObject as _ } from "../utils/disposeObject.js";
9
+ import "../utils/PredictiveLoader.js";
10
+ import { version as N } from "../../package.json.js";
11
+ const W = 50, k = 20, G = 20, C = {
12
+ TOP: "top",
13
+ // 俯视(从上往下)
14
+ RIGHT: "right",
15
+ // 侧视(从右往左)
16
+ LEFT: "left",
17
+ // 左侧视
18
+ ISO: "iso"
19
+ // 正斜视(等轴测视角)
20
+ }, U = {
21
+ enableDamping: !0,
22
+ dampingFactor: 0.25,
23
+ screenSpacePanning: !1,
24
+ minDistance: 0.1,
25
+ maxDistance: 1e3,
26
+ maxPolarAngle: g.degToRad(60)
27
+ };
28
+ class $ {
29
+ /**
30
+ * 构造函数
31
+ * @param {string} selector - DOM 容器选择器
32
+ * @param {Object} option - 配置选项
33
+ * @param {boolean} [option.css3d=false] - 是否启用 CSS3D 渲染器
34
+ * @param {boolean} [option.stats=false] - 是否显示性能统计
35
+ * @param {string} [option.renderType='change'] - 渲染类型: 'loop' 或 'change'
36
+ * @param {boolean} [option.initListener=true] - 是否初始化事件监听器
37
+ * @param {number} [option.initialFov=50] - 初始相机 FOV 值
38
+ * @param {Object} [option.control] - 控制器配置
39
+ * @param {boolean} [option.control.init=true] - 是否初始化控制器
40
+ * @param {Object} [option.control.options={}] - 控制器选项
41
+ */
42
+ constructor(e, t) {
43
+ i(this, "isReady", !1);
44
+ i(this, "scene", null);
45
+ i(this, "camera", null);
46
+ i(this, "renderer", null);
47
+ i(this, "control", null);
48
+ i(this, "css3dRenderer", null);
49
+ i(this, "el", null);
50
+ i(this, "renderRequested", !1);
51
+ i(this, "selector", null);
52
+ i(this, "eventsListener", {});
53
+ i(this, "stats", null);
54
+ i(this, "isDispose", !1);
55
+ i(this, "version", "0.0.0");
56
+ i(this, "boxHelper", null);
57
+ i(this, "initOpt", {
58
+ css3d: !1,
59
+ stats: !1,
60
+ renderType: "change",
61
+ initListener: !0,
62
+ // 使用布尔值代替字符串
63
+ initialFov: 50,
64
+ // 初始 FOV 值,用于避免全屏切换时的累积误差
65
+ control: {
66
+ init: !0,
67
+ options: {}
68
+ }
69
+ });
70
+ /**
71
+ * 初始化场景
72
+ * @param {string} selector - DOM 容器选择器
73
+ */
74
+ i(this, "setup", (e) => {
75
+ if (this.isDispose = !1, this.selector = e, this.el = document.querySelector(e), !this.el) {
76
+ console.error(`ThreeIns: 找不到元素 ${e}`);
77
+ return;
78
+ }
79
+ const [t, l] = this.getTargetSize();
80
+ if (this.updateCameraFOV(t, l), this.camera.position.set(0, 0, 0), this.camera.lookAt(0, 0, 0), this.camera.updateProjectionMatrix(), this.renderer.setPixelRatio(window.devicePixelRatio), this.renderer.setSize(t, l), this.el.appendChild(this.renderer.domElement), this.initOpt.control && this.initOpt.control.init) {
81
+ this.control = B(this.camera, this.renderer.domElement);
82
+ const s = Object.assign(
83
+ U,
84
+ this.initOpt.control.options || {}
85
+ );
86
+ Object.keys(s).forEach((x) => {
87
+ this.control[x] = s[x];
88
+ });
89
+ }
90
+ setTimeout(() => {
91
+ this.isReady = !0;
92
+ }, k), this.initOpt.stats && this.initStats(), this.initOpt.css3d && this.initCss3dRenderer(), this.initOpt.renderType === "loop" ? this.animate() : this.initOpt.renderType === "change" && this.control && this.control.addEventListener(
93
+ "change",
94
+ this.requestRenderIfNotRequested
95
+ ), this.initListener();
96
+ });
97
+ /**
98
+ * WebGL 上下文丢失处理
99
+ * @param {Event} e - 事件对象
100
+ */
101
+ i(this, "onContextLost", (e) => {
102
+ e.preventDefault(), this.animationFrameId && cancelAnimationFrame(this.animationFrameId);
103
+ });
104
+ /**
105
+ * WebGL 上下文恢复处理
106
+ * @param {Event} e - 事件对象
107
+ */
108
+ i(this, "onContextRestored", (e) => {
109
+ e.preventDefault(), this.dispose(), setTimeout(() => {
110
+ this.setup(this.selector);
111
+ }, G);
112
+ });
113
+ /**
114
+ * 初始化事件监听器
115
+ */
116
+ i(this, "initListener", () => {
117
+ this.initOpt.initListener && window && window.addEventListener("resize", this.onResize, !1), this.renderer.domElement.addEventListener(
118
+ "webglcontextlost",
119
+ this.onContextLost,
120
+ !1
121
+ ), this.renderer.domElement.addEventListener(
122
+ "webglcontextrestored",
123
+ this.onContextRestored,
124
+ !1
125
+ );
126
+ });
127
+ /**
128
+ * 移除事件监听器
129
+ */
130
+ i(this, "removeListener", () => {
131
+ window && window.removeEventListener("resize", this.onResize, !1), this.renderer && this.renderer.domElement && (this.renderer.domElement.removeEventListener(
132
+ "webglcontextlost",
133
+ this.onContextLost,
134
+ !1
135
+ ), this.renderer.domElement.removeEventListener(
136
+ "webglcontextrestored",
137
+ this.onContextRestored,
138
+ !1
139
+ ));
140
+ });
141
+ /**
142
+ * 渲染循环(loop 模式)
143
+ */
144
+ i(this, "animate", () => {
145
+ this.isDispose || (this.initOpt.renderType === "loop" && this.onRender(), this.animationFrameId = requestAnimationFrame(this.animate));
146
+ });
147
+ /**
148
+ * 执行渲染
149
+ */
150
+ i(this, "onRender", () => {
151
+ this.isDispose || (this.renderRequested = !1, this.stats && this.stats.update(), this.control && this.control.update(), this.renderer.render(this.scene, this.camera), this.css3dRenderer && this.css3dRenderer.render(this.scene, this.camera), this.eventsListener.onRender && this.eventsListener.onRender.length && this.eventsListener.onRender.forEach((e) => e()));
152
+ });
153
+ /**
154
+ * 请求渲染(如果尚未请求)
155
+ */
156
+ i(this, "requestRenderIfNotRequested", () => {
157
+ this.renderRequested || (this.renderRequested = !0, requestAnimationFrame(() => {
158
+ this.onRender();
159
+ }));
160
+ });
161
+ /**
162
+ * 处理窗口大小变化(带防抖)
163
+ */
164
+ i(this, "onResize", () => {
165
+ this.resizeTimer && clearTimeout(this.resizeTimer), this.resizeTimer = setTimeout(() => {
166
+ const [e, t] = this.getTargetSize();
167
+ this.updateCameraFOV(e, t), this.camera.lookAt(this.scene.position), this.renderer.setSize(e, t), this.css3dRenderer && this.css3dRenderer.setSize(e, t), this.onRender();
168
+ }, W);
169
+ });
170
+ /**
171
+ * @deprecated 此方法已弃用,请使用 setView() 方法代替
172
+ *
173
+ * frameArea 仅为兼容旧版本保留,功能已被 setView() 完全覆盖
174
+ *
175
+ * 旧用法:
176
+ * threeIns.frameArea(model, 1.0)
177
+ *
178
+ * 推荐用法:
179
+ * threeIns.setView(model, ViewType.ISO, { scale: 1.0 })
180
+ *
181
+ * @param {Object3D} model - 要调整视角的 3D 模型对象
182
+ * @param {number} [scale=0.8] - 缩放比例,1=占满画布,0.5=50%,2.0=200%
183
+ * @returns {Object} 返回 setView 的结果
184
+ */
185
+ i(this, "frameArea", (e, t) => (console.warn(
186
+ `[ThreeIns] frameArea() 已弃用,建议使用 setView() 方法。
187
+ 旧用法: threeIns.frameArea(model, scale)
188
+ 新用法: threeIns.setView(model, ViewType.ISO, { scale })`
189
+ ), this.setView(e, C.ISO, { scale: t, animate: !1, showBox: !1 })));
190
+ /**
191
+ * 切换到指定视角
192
+ * 根据视角类型自动调整相机位置和朝向,支持缩放比例控制
193
+ *
194
+ * @param {Object3D} model - 3D 物体对象
195
+ * @param {string} viewType - 视角类型,使用 ViewType 枚举
196
+ * - 'top': 俯视(从上往下看 Y 轴正方向)
197
+ * - 'right': 侧视(从右往左看 X 轴正方向)
198
+ * - 'left': 左侧视(从左往右看 X 轴负方向)
199
+ * - 'iso': 正斜视(等轴测视角,45°角)
200
+ * @param {Object} [options] - 可选配置
201
+ * @param {number} [options.scale=1] - 缩放比例,控制模型在画布中的占比
202
+ * @param {Vector3} [options.offset] - 偏移量,调整观察中心点
203
+ * @param {boolean} [options.showBox=false] - 是否显示包围盒辅助线
204
+ * @param {number} [options.boxColor=0xffff00] - 包围盒颜色
205
+ * @param {boolean} [options.animate=true] - 是否使用动画过渡
206
+ * @param {number} [options.duration=1000] - 动画持续时间(毫秒)
207
+ * @returns {Object} 返回相机位置和模型信息
208
+ * @returns {Vector3} return.position - 相机位置
209
+ * @returns {Vector3} return.target - 相机观察目标点
210
+ * @returns {number} return.distance - 相机到模型的距离
211
+ *
212
+ * @example
213
+ * // 导入 ViewType 枚举
214
+ * import { ThreeIns, ViewType } from 'threejs';
215
+ *
216
+ * // 切换到俯视,模型占满画布
217
+ * threeIns.setView(model, ViewType.TOP);
218
+ *
219
+ * // 切换到等轴测,模型占画布的 80%
220
+ * threeIns.setView(model, ViewType.ISO, { scale: 0.8 });
221
+ *
222
+ * // 切换到斜视,显示包围盒,无动画
223
+ * threeIns.setView(model, ViewType.ISO, {
224
+ * showBox: true,
225
+ * animate: false
226
+ * });
227
+ *
228
+ * // 切换到侧视,自定义观察点
229
+ * threeIns.setView(model, ViewType.RIGHT, {
230
+ * offset: new THREE.Vector3(0, 10, 0),
231
+ * scale: 0.8
232
+ * });
233
+ *
234
+ * // 或者使用类静态属性(向后兼容)
235
+ * threeIns.setView(model, ThreeIns.ViewType.TOP);
236
+ */
237
+ i(this, "setView", (e, t, l = {}) => {
238
+ let s = l.scale || 0.8, x = l.offset || null, R = l.showBox || !1, y = l.boxColor || 16776960, z = l.animate !== void 0 ? l.animate : !0, M = l.duration || 1e3;
239
+ const F = new X().setFromObject(e);
240
+ let h = F.getCenter(new d());
241
+ x && h.add(x);
242
+ const T = {
243
+ top: new d(0, 1, 0),
244
+ // 从上往下:Y 轴正方向
245
+ right: new d(2, 1, 1).normalize(),
246
+ // 从右往左:X 轴正方向
247
+ left: new d(-2, 1, 1).normalize(),
248
+ // 从左往右:X 轴负方向
249
+ iso: new d(0, 1, 1).normalize()
250
+ // 等轴测:从对角线上方俯视
251
+ }, E = T[t] || T.iso, o = F.getSize(new d()), L = this.camera.aspect, n = g.degToRad(this.camera.fov * 0.5), S = g.degToRad(80), c = Math.min(Math.atan(Math.tan(n) * L), S);
252
+ let m;
253
+ if (t === "top") {
254
+ const r = o.x * 0.5 / (Math.tan(c) * s), a = o.z * 0.5 / (Math.tan(n) * s);
255
+ m = Math.max(r, a);
256
+ } else if (t === "right" || t === "left") {
257
+ const r = o.y * 0.5 / (Math.tan(n) * s), a = o.z * 0.5 / (Math.tan(n) * s);
258
+ m = Math.max(r, a);
259
+ } else {
260
+ const r = o.x * 0.5 / (Math.tan(c) * s), a = o.y * 0.5 / (Math.tan(n) * s), u = o.z * 0.5 / (Math.tan(n) * s);
261
+ m = Math.max(r, a, u);
262
+ }
263
+ const f = E.clone().multiplyScalar(m).add(h);
264
+ if (R && (console.log("📍 相机位置验证:"), console.log(" - 方向向量:", E), console.log(" - 距离:", m.toFixed(2)), console.log(" - 包围盒中心:", h), console.log(" - 计算公式: direction * distance + boxCenter"), console.log(" - 目标位置:", f), console.log(" - 实际相机与中心的距离:", f.clone().sub(h).length().toFixed(2))), R ? (this.boxHelper && (this.scene.remove(this.boxHelper), this.boxHelper = null), this.boxHelper = new Y(F, y), this.scene.add(this.boxHelper)) : this.boxHelper && (this.scene.remove(this.boxHelper), this.boxHelper = null), z) {
265
+ const r = this.camera.position.clone(), a = this.control ? this.control.target.clone() : new d(0, 0, 0), u = h, D = Date.now(), v = () => {
266
+ const I = Date.now() - D, b = Math.min(I / M, 1), O = 1 - Math.pow(1 - b, 3);
267
+ if (this.camera.position.lerpVectors(r, f, O), this.control) {
268
+ const w = new d();
269
+ w.lerpVectors(a, u, O), this.control.target.copy(w), this.camera.lookAt(w);
270
+ } else
271
+ this.camera.lookAt(h);
272
+ this.camera.updateProjectionMatrix(), b < 1 ? requestAnimationFrame(v) : (this.camera.position.copy(f), this.camera.lookAt(h), this.camera.updateProjectionMatrix(), this.control && (this.control.target.copy(h), this.control.update()), this.onRender());
273
+ };
274
+ v();
275
+ } else
276
+ this.camera.position.copy(f), this.camera.lookAt(h), this.camera.updateProjectionMatrix(), this.control && (this.control.target.copy(h), this.control.update()), this.onRender();
277
+ if (R) {
278
+ if (console.log("🎥 视角切换信息:"), console.log(" - 视角类型:", t), console.log(" - 相机位置:", f), console.log(" - 观察目标:", h), console.log(" - 方向向量:", E), console.log(" - 包围盒尺寸:", o), console.log(" - 包围盒中心:", F.getCenter(new d())), console.log(" - 水平 FOV:", g.radToDeg(c * 2).toFixed(2) + "°"), console.log(" - 垂直 FOV:", g.radToDeg(n * 2).toFixed(2) + "°"), console.log(" - 宽高比:", L.toFixed(4)), console.log(" - 模型宽度:", o.x.toFixed(2)), console.log(" - 模型高度:", o.y.toFixed(2)), console.log(" - 模型深度:", o.z.toFixed(2)), console.log(" - 传入的 scale 参数:", s), t === "top") {
279
+ const r = o.x * 0.5 / (Math.tan(c) * s), a = o.z * 0.5 / (Math.tan(n) * s);
280
+ console.log(" - 模型 X 尺寸 (宽度):", o.x.toFixed(2)), console.log(" - 模型 Z 尺寸 (深度):", o.z.toFixed(2)), console.log(" - tan(halfFovX):", Math.tan(c).toFixed(4)), console.log(" - tan(halfFovY):", Math.tan(n).toFixed(4)), console.log(" - X方向距离计算: (", (o.x * 0.5).toFixed(2), ") / (", Math.tan(c).toFixed(4), " *", s, ") =", r.toFixed(2)), console.log(" - Z方向距离计算: (", (o.z * 0.5).toFixed(2), ") / (", Math.tan(n).toFixed(4), " *", s, ") =", a.toFixed(2)), console.log(" - X方向距离 (scale=" + s + "):", r.toFixed(2)), console.log(" - Z方向距离 (scale=" + s + "):", a.toFixed(2));
281
+ } else if (t === "right" || t === "left") {
282
+ const r = o.y * 0.5 / (Math.tan(n) * s), a = o.z * 0.5 / (Math.tan(n) * s);
283
+ console.log(" - Y方向距离 (scale=" + s + "):", r.toFixed(2)), console.log(" - Z方向距离 (scale=" + s + "):", a.toFixed(2));
284
+ } else {
285
+ const r = o.x * 0.5 / (Math.tan(c) * s), a = o.y * 0.5 / (Math.tan(n) * s), u = o.z * 0.5 / (Math.tan(n) * s);
286
+ console.log(" - 模型 X 尺寸 (宽度):", o.x.toFixed(2)), console.log(" - 模型 Y 尺寸 (高度):", o.y.toFixed(2)), console.log(" - 模型 Z 尺寸 (深度):", o.z.toFixed(2)), console.log(" - tan(halfFovX):", Math.tan(c).toFixed(4)), console.log(" - tan(halfFovY):", Math.tan(n).toFixed(4)), console.log(" - X方向距离计算: (", (o.x * 0.5).toFixed(2), ") / (", Math.tan(c).toFixed(4), " *", s, ") =", r.toFixed(2)), console.log(" - Y方向距离计算: (", (o.y * 0.5).toFixed(2), ") / (", Math.tan(n).toFixed(4), " *", s, ") =", a.toFixed(2)), console.log(" - Z方向距离计算: (", (o.z * 0.5).toFixed(2), ") / (", Math.tan(n).toFixed(4), " *", s, ") =", u.toFixed(2)), console.log(" - X方向距离 (scale=" + s + "):", r.toFixed(2)), console.log(" - Y方向距离 (scale=" + s + "):", a.toFixed(2)), console.log(" - Z方向距离 (scale=" + s + "):", u.toFixed(2)), console.log(" - 最大距离 (Max):", Math.max(r, a, u).toFixed(2));
287
+ }
288
+ console.log(" - 最终距离:", m.toFixed(2)), console.log(" - 缩放比例:", s), console.log(" - 动画:", z ? "是 (" + M + "ms)" : "否");
289
+ }
290
+ return {
291
+ position: f,
292
+ target: h,
293
+ distance: m,
294
+ viewType: t
295
+ };
296
+ });
297
+ /**
298
+ * 注册事件监听器
299
+ * @param {string} event - 事件名称
300
+ * @param {Function} callback - 回调函数
301
+ * @returns {Function} 返回取消监听的函数
302
+ */
303
+ i(this, "on", (e, t) => !e || !t || typeof t != "function" ? (console.warn("ThreeIns.on: 无效的参数"), () => {
304
+ }) : (this.eventsListener[e] || (this.eventsListener[e] = []), this.eventsListener[e].push(t), () => this.off(e, t)));
305
+ this.isReady = !1, this.scene = new V({}), this.camera = new P(50, 1, 0.1, 2e3), this.renderer = new q({
306
+ antialias: !0,
307
+ alpha: !0,
308
+ precision: "mediump",
309
+ logarithmicDepthBuffer: !0
310
+ }), this.version = N, this.onContextLost = this.onContextLost.bind(this), this.onContextRestored = this.onContextRestored.bind(this), this.onResize = this.onResize.bind(this), this.animate = this.animate.bind(this), this.resizeTimer = null, this.animationFrameId = null, t && (this.initOpt = Object.assign(this.initOpt, t)), e && this.setup(e);
311
+ }
312
+ /**
313
+ * 更新相机 FOV 以适应容器尺寸
314
+ * @private
315
+ * @param {number} domW - 容器宽度
316
+ * @param {number} domH - 容器高度
317
+ */
318
+ updateCameraFOV(e, t) {
319
+ const l = this.initOpt.initialFov || 50, s = Math.tan(Math.PI / 180 * l / 2);
320
+ this.camera.aspect = e / t, this.camera.fov = 360 / Math.PI * Math.atan(s * (t / e)), this.camera.updateProjectionMatrix();
321
+ }
322
+ /**
323
+ * 初始化性能统计
324
+ */
325
+ initStats() {
326
+ this.stats = new j(), this.stats.dom.style.cssText = "position:absolute;top:0;left:0;cursor:pointer;opacity:0.9;z-index:10000", this.el.appendChild(this.stats.dom);
327
+ }
328
+ /**
329
+ * 初始化 CSS3D 渲染器
330
+ */
331
+ initCss3dRenderer() {
332
+ this.css3dRenderer = new Z();
333
+ const [e, t] = this.getTargetSize();
334
+ this.css3dRenderer.setSize(e, t), this.css3dRenderer.domElement.style.position = "absolute", this.css3dRenderer.domElement.style.pointerEvents = "none", this.css3dRenderer.domElement.style.top = 0, this.css3dRenderer.domElement.style.left = 0, this.el.appendChild(this.css3dRenderer.domElement);
335
+ }
336
+ /**
337
+ * 获取目标容器尺寸
338
+ * 使用智能缓存策略:全屏时使用窗口尺寸,非全屏时使用元素尺寸
339
+ * @returns {[number, number]} [width, height]
340
+ */
341
+ getTargetSize() {
342
+ return document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement ? [window.innerWidth, window.innerHeight] : this.el ? !document.body.contains(this.el) && (console.warn(`ThreeIns: 缓存的元素已失效,重新查询 ${this.selector}`), this.el = document.querySelector(this.selector), !this.el) ? [0, 0] : [this.el.clientWidth, this.el.clientHeight] : [0, 0];
343
+ }
344
+ /**
345
+ * 移除事件监听器
346
+ * @param {string} event - 事件名称
347
+ * @param {Function} [callback] - 可选的回调函数,如果不提供则移除该事件的所有监听器
348
+ */
349
+ off(e, t) {
350
+ if (!e) {
351
+ this.eventsListener = {};
352
+ return;
353
+ }
354
+ this.eventsListener[e] && (t ? this.eventsListener[e] = this.eventsListener[e].filter((l) => l !== t) : this.eventsListener[e] = []);
355
+ }
356
+ /**
357
+ * 清理所有资源
358
+ */
359
+ dispose() {
360
+ this.isDispose || (this.isDispose = !0, this.animationFrameId && (cancelAnimationFrame(this.animationFrameId), this.animationFrameId = null), this.resizeTimer && (clearTimeout(this.resizeTimer), this.resizeTimer = null), this.removeListener(), this.eventsListener = {}, this.stats && this.stats.dom && (this.stats.dom.remove(), this.stats = null), this.css3dRenderer && (this.css3dRenderer.domElement.remove(), this.css3dRenderer = null), this.boxHelper && (this.scene.remove(this.boxHelper), this.boxHelper = null), this.scene && (_(this.scene), this.scene = null), this.renderer && (this.renderer.dispose(), this.renderer.domElement && this.renderer.domElement.remove(), this.renderer = null), this.control && (this.control.dispose(), this.control = null), this.camera = null, this.el = null, this.selector = null, console.log("ThreeIns: 资源已清理完成"));
361
+ }
362
+ }
363
+ // 存储包围盒辅助器
364
+ // 视角类型枚举(作为类静态属性引用,保持向后兼容)
365
+ i($, "ViewType", C);
366
+ export {
367
+ $ as ThreeIns,
368
+ C as ViewType
369
+ };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class e{constructor(){this.stats={hits:0,misses:0,totalLoadTime:0,cacheSaveTime:0,errors:0},this.loadHistory=[]}recordHit(t){this.stats.hits++,this.stats.totalLoadTime+=t,this._recordHistory("hit",t)}recordMiss(t){this.stats.misses++,this.stats.totalLoadTime+=t,this._recordHistory("miss",t)}recordCacheSave(t){this.stats.cacheSaveTime+=t}recordError(t,s){this.stats.errors++,this._recordHistory("error",0,{path:t,error:s.message})}getHitRate(){const t=this.stats.hits+this.stats.misses;return t>0?(this.stats.hits/t*100).toFixed(2)+"%":"0%"}getAvgLoadTime(){const t=this.stats.hits+this.stats.misses;return t>0?(this.stats.totalLoadTime/t).toFixed(2)+"ms":"0ms"}getStats(){const t=this.stats.hits+this.stats.misses;return{命中率:this.getHitRate(),平均加载时间:this.getAvgLoadTime(),缓存命中数:this.stats.hits,缓存未命中数:this.stats.misses,总加载次数:t,总加载时间:this.stats.totalLoadTime.toFixed(2)+"ms",缓存保存时间:this.stats.cacheSaveTime.toFixed(2)+"ms",错误次数:this.stats.errors}}getHistory(t=10){return this.loadHistory.slice(-t)}reset(){this.stats={hits:0,misses:0,totalLoadTime:0,cacheSaveTime:0,errors:0},this.loadHistory=[]}_recordHistory(t,s,i={}){this.loadHistory.push({type:t,duration:s,timestamp:Date.now(),...i}),this.loadHistory.length>100&&this.loadHistory.shift()}logReport(){console.group("📊 缓存性能报告");const t=this.getStats();Object.entries(t).forEach(([s,i])=>{console.log(`${s}: ${i}`)}),console.groupEnd()}}const o=new e;exports.CacheMonitor=e;exports.cacheMonitor=o;
@@ -0,0 +1,125 @@
1
+ class e {
2
+ constructor() {
3
+ this.stats = {
4
+ hits: 0,
5
+ // 缓存命中次数
6
+ misses: 0,
7
+ // 缓存未命中次数
8
+ totalLoadTime: 0,
9
+ // 总加载时间(ms)
10
+ cacheSaveTime: 0,
11
+ // 缓存保存时间(ms)
12
+ errors: 0
13
+ // 错误次数
14
+ }, this.loadHistory = [];
15
+ }
16
+ /**
17
+ * 记录缓存命中
18
+ * @param {number} loadTime - 加载耗时(ms)
19
+ */
20
+ recordHit(t) {
21
+ this.stats.hits++, this.stats.totalLoadTime += t, this._recordHistory("hit", t);
22
+ }
23
+ /**
24
+ * 记录缓存未命中
25
+ * @param {number} loadTime - 加载耗时(ms)
26
+ */
27
+ recordMiss(t) {
28
+ this.stats.misses++, this.stats.totalLoadTime += t, this._recordHistory("miss", t);
29
+ }
30
+ /**
31
+ * 记录缓存保存时间
32
+ * @param {number} saveTime - 保存耗时(ms)
33
+ */
34
+ recordCacheSave(t) {
35
+ this.stats.cacheSaveTime += t;
36
+ }
37
+ /**
38
+ * 记录错误
39
+ * @param {string} path - 模型路径
40
+ * @param {Error} error - 错误对象
41
+ */
42
+ recordError(t, s) {
43
+ this.stats.errors++, this._recordHistory("error", 0, { path: t, error: s.message });
44
+ }
45
+ /**
46
+ * 计算缓存命中率
47
+ * @returns {string} 命中率百分比字符串
48
+ */
49
+ getHitRate() {
50
+ const t = this.stats.hits + this.stats.misses;
51
+ return t > 0 ? (this.stats.hits / t * 100).toFixed(2) + "%" : "0%";
52
+ }
53
+ /**
54
+ * 计算平均加载时间
55
+ * @returns {string} 平均加载时间(含单位)
56
+ */
57
+ getAvgLoadTime() {
58
+ const t = this.stats.hits + this.stats.misses;
59
+ return t > 0 ? (this.stats.totalLoadTime / t).toFixed(2) + "ms" : "0ms";
60
+ }
61
+ /**
62
+ * 获取完整的统计数据
63
+ * @returns {Object} 统计数据对象
64
+ */
65
+ getStats() {
66
+ const t = this.stats.hits + this.stats.misses;
67
+ return {
68
+ 命中率: this.getHitRate(),
69
+ 平均加载时间: this.getAvgLoadTime(),
70
+ 缓存命中数: this.stats.hits,
71
+ 缓存未命中数: this.stats.misses,
72
+ 总加载次数: t,
73
+ 总加载时间: this.stats.totalLoadTime.toFixed(2) + "ms",
74
+ 缓存保存时间: this.stats.cacheSaveTime.toFixed(2) + "ms",
75
+ 错误次数: this.stats.errors
76
+ };
77
+ }
78
+ /**
79
+ * 获取最近N条加载历史
80
+ * @param {number} count - 获取条数,默认 10
81
+ * @returns {Array} 历史记录数组
82
+ */
83
+ getHistory(t = 10) {
84
+ return this.loadHistory.slice(-t);
85
+ }
86
+ /**
87
+ * 清空统计数据
88
+ */
89
+ reset() {
90
+ this.stats = {
91
+ hits: 0,
92
+ misses: 0,
93
+ totalLoadTime: 0,
94
+ cacheSaveTime: 0,
95
+ errors: 0
96
+ }, this.loadHistory = [];
97
+ }
98
+ /**
99
+ * 内部方法: 记录历史
100
+ * @private
101
+ */
102
+ _recordHistory(t, s, i = {}) {
103
+ this.loadHistory.push({
104
+ type: t,
105
+ duration: s,
106
+ timestamp: Date.now(),
107
+ ...i
108
+ }), this.loadHistory.length > 100 && this.loadHistory.shift();
109
+ }
110
+ /**
111
+ * 打印统计报告到控制台
112
+ */
113
+ logReport() {
114
+ console.group("📊 缓存性能报告");
115
+ const t = this.getStats();
116
+ Object.entries(t).forEach(([s, i]) => {
117
+ console.log(`${s}: ${i}`);
118
+ }), console.groupEnd();
119
+ }
120
+ }
121
+ const r = new e();
122
+ export {
123
+ e as CacheMonitor,
124
+ r as cacheMonitor
125
+ };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("three"),d=require("../../../../node_modules/.pnpm/three@0.178.0/node_modules/three/examples/jsm/loaders/EXRLoader.cjs"),u=require("../../../../node_modules/.pnpm/three@0.178.0/node_modules/three/examples/jsm/loaders/RGBELoader.cjs"),i={};async function l(r,n){if(!n)return;if(i[n]){const e=i[n];r.environment=e;return}let o=t(n);return new Promise((e,a)=>{o.load(n,e,void 0,a)}).then(e=>{e.mapping=c.EquirectangularReflectionMapping,r.environment=e,i[n]=e}).catch(e=>{console.log(" =====> e:",e)})}async function s(r){let n=t(r);return new Promise((o,e)=>{n.load(r,o,void 0,e)})}function t(r){return r.split(".").pop()==="exr"?new d.EXRLoader:new u.RGBELoader}exports.ImageLoader=s;exports.initEnvImage=l;
@@ -0,0 +1,33 @@
1
+ import { EquirectangularReflectionMapping as c } from "three";
2
+ import { EXRLoader as d } from "../../../../node_modules/.pnpm/three@0.178.0/node_modules/three/examples/jsm/loaders/EXRLoader.js";
3
+ import { RGBELoader as m } from "../../../../node_modules/.pnpm/three@0.178.0/node_modules/three/examples/jsm/loaders/RGBELoader.js";
4
+ const i = {};
5
+ async function s(o, n) {
6
+ if (!n) return;
7
+ if (i[n]) {
8
+ const e = i[n];
9
+ o.environment = e;
10
+ return;
11
+ }
12
+ let r = t(n);
13
+ return new Promise((e, a) => {
14
+ r.load(n, e, void 0, a);
15
+ }).then((e) => {
16
+ e.mapping = c, o.environment = e, i[n] = e;
17
+ }).catch((e) => {
18
+ console.log(" =====> e:", e);
19
+ });
20
+ }
21
+ async function g(o) {
22
+ let n = t(o);
23
+ return new Promise((r, e) => {
24
+ n.load(o, r, void 0, e);
25
+ });
26
+ }
27
+ function t(o) {
28
+ return o.split(".").pop() === "exr" ? new d() : new m();
29
+ }
30
+ export {
31
+ g as ImageLoader,
32
+ s as initEnvImage
33
+ };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const d=require("../hooks/useGLTFLoader.cjs");class c{constructor(e={}){this.options={maxPreloadCount:e.maxPreloadCount||5,preloadDelay:e.preloadDelay||1e3,enableLearning:e.enableLearning!==!1},this.loadHistory=new Map,this.loadSequence=[],this.associations=new Map,this.preloadQueue=new Set,this.isPreloading=!1,this.loader=null,this.getLoader=()=>(this.loader||(this.loader=d.useGLTFLoader()),this.loader)}recordLoad(e,s){const t=Date.now(),o=this.loadHistory.get(e)||{count:0,lastLoadTime:0,versions:new Set};o.count++,o.lastLoadTime=t,o.versions.add(s),this.loadHistory.set(e,o),this.loadSequence.push({path:e,timestamp:t}),this.loadSequence.length>100&&this.loadSequence.shift(),this.options.enableLearning&&this.loadSequence.length>=2&&this._learnAssociations(e),this._triggerPredictivePreload(e,s)}_learnAssociations(e){const t=this.loadSequence.length-1;for(let o=Math.max(0,t-10);o<t;o++){const{path:a}=this.loadSequence[o];if(this.loadSequence[t].timestamp-this.loadSequence[o].timestamp<5*60*1e3&&a!==e){this.associations.has(a)||this.associations.set(a,new Map);const i=this.associations.get(a),n=i.get(e)||0;i.set(e,n+1)}}}_triggerPredictivePreload(e,s){setTimeout(()=>{const t=this.predictNext(e);this.preload(t,s)},this.options.preloadDelay)}predictNext(e){const s=new Map,t=this.associations.get(e);t&&t.forEach((i,n)=>{s.set(n,(s.get(n)||0)+i*2)});const o=Array.from(this.loadHistory.values()).reduce((i,n)=>i+n.count,0)/(this.loadHistory.size||1);this.loadHistory.forEach((i,n)=>{if(n!==e){const l=i.count/o;s.set(n,(s.get(n)||0)+l)}});const a=this.loadSequence.slice(-10);return new Set(a.map(i=>i.path)).forEach(i=>{i!==e&&s.set(i,(s.get(i)||0)+.5)}),Array.from(s.entries()).sort((i,n)=>n[1]-i[1]).slice(0,this.options.maxPreloadCount).map(([i])=>i)}async preload(e,s="latest"){if(this.isPreloading)return;this.isPreloading=!0;const{asyncFetch:t}=this.getLoader(),o=e.filter(a=>!this.preloadQueue.has(a)).slice(0,this.options.maxPreloadCount).map(async a=>{this.preloadQueue.add(a);try{console.log(`[ 智能预加载 ] 开始预加载: ${a}`),await t(a,s),console.log(`[ 智能预加载 ] 完成: ${a}`)}catch(r){console.warn(`[ 智能预加载 ] 失败: ${a}`,r)}finally{this.preloadQueue.delete(a)}});await Promise.all(o),this.isPreloading=!1}addAssociation(e,s){this.associations.has(e)||this.associations.set(e,new Map);const t=this.associations.get(e);s.forEach(o=>{const a=t.get(o)||0;t.set(o,a+10)})}getStats(){const e=Array.from(this.loadHistory.entries()).sort((s,t)=>t[1].count-s[1].count).slice(0,10).map(([s,t])=>({path:s,loadCount:t.count,lastLoadTime:new Date(t.lastLoadTime).toLocaleString()}));return{totalModelsLoaded:this.loadHistory.size,totalAssociations:this.associations.size,topModels:e,preloadQueueSize:this.preloadQueue.size}}clearHistory(){this.loadHistory.clear(),this.loadSequence=[],this.associations.clear()}exportAssociations(){const e={};return this.associations.forEach((s,t)=>{e[t]=Array.from(s.entries())}),e}importAssociations(e){Object.entries(e).forEach(([s,t])=>{const o=new Map(t);this.associations.set(s,o)})}}const h=new c;exports.PredictiveLoader=c;exports.predictiveLoader=h;