@ridp/threejs 1.4.3 → 1.4.4

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 (57) hide show
  1. package/dist/ImageLoader-CMAmH-92.js +1444 -0
  2. package/dist/ImageLoader-y6-Adf1b.cjs +24 -0
  3. package/dist/PredictiveLoader-BXCwkdSX.cjs +2 -0
  4. package/dist/PredictiveLoader-eiPgVdsJ.js +3832 -0
  5. package/dist/assets/{gltfParser.worker-Bqz8BBJx.js → gltfParser.worker-D2lwod50.js} +2 -2
  6. package/dist/assets/{gltfParserOptimized.worker-DfipxPjm.js → gltfParserOptimized.worker-FT73rIOj.js} +2 -2
  7. package/dist/hooks.cjs +1 -1
  8. package/dist/hooks.js +9 -12
  9. package/dist/{packages/threejs/src/utils/modelOptimizer.js → modelOptimizer-D6fRg-DF.js} +1 -1
  10. package/dist/threejs.cjs +3 -1
  11. package/dist/threejs.js +428 -58
  12. package/dist/useBatchGLTFLoader-D3gPYO-K.cjs +5 -0
  13. package/dist/useBatchGLTFLoader-DP_NdYhC.js +493 -0
  14. package/dist/utils.cjs +1 -1
  15. package/dist/utils.js +32 -40
  16. package/package.json +1 -1
  17. package/dist/packages/threejs/package.json.cjs +0 -1
  18. package/dist/packages/threejs/package.json.js +0 -4
  19. package/dist/packages/threejs/src/hooks/useBatchGLTFLoader.cjs +0 -1
  20. package/dist/packages/threejs/src/hooks/useBatchGLTFLoader.js +0 -83
  21. package/dist/packages/threejs/src/hooks/useGLTFLoader.cjs +0 -1
  22. package/dist/packages/threejs/src/hooks/useGLTFLoader.js +0 -292
  23. package/dist/packages/threejs/src/hooks/useObb.cjs +0 -1
  24. package/dist/packages/threejs/src/hooks/useObb.js +0 -41
  25. package/dist/packages/threejs/src/hooks/useRaycaster.cjs +0 -1
  26. package/dist/packages/threejs/src/hooks/useRaycaster.js +0 -35
  27. package/dist/packages/threejs/src/hooks/useThreeJs.cjs +0 -5
  28. package/dist/packages/threejs/src/hooks/useThreeJs.js +0 -153
  29. package/dist/packages/threejs/src/instance/IDBCache.cjs +0 -1
  30. package/dist/packages/threejs/src/instance/IDBCache.js +0 -142
  31. package/dist/packages/threejs/src/instance/threeIns.cjs +0 -3
  32. package/dist/packages/threejs/src/instance/threeIns.js +0 -393
  33. package/dist/packages/threejs/src/utils/CacheMonitor.cjs +0 -1
  34. package/dist/packages/threejs/src/utils/CacheMonitor.js +0 -125
  35. package/dist/packages/threejs/src/utils/ImageLoader.cjs +0 -1
  36. package/dist/packages/threejs/src/utils/ImageLoader.js +0 -33
  37. package/dist/packages/threejs/src/utils/PredictiveLoader.cjs +0 -1
  38. package/dist/packages/threejs/src/utils/PredictiveLoader.js +0 -155
  39. package/dist/packages/threejs/src/utils/RetryHelper.cjs +0 -1
  40. package/dist/packages/threejs/src/utils/RetryHelper.js +0 -108
  41. package/dist/packages/threejs/src/utils/common.cjs +0 -1
  42. package/dist/packages/threejs/src/utils/common.js +0 -15
  43. package/dist/packages/threejs/src/utils/css3dHelper.cjs +0 -15
  44. package/dist/packages/threejs/src/utils/css3dHelper.js +0 -42
  45. package/dist/packages/threejs/src/utils/disposeObject.cjs +0 -1
  46. package/dist/packages/threejs/src/utils/disposeObject.js +0 -13
  47. package/dist/packages/threejs/src/utils/helper.cjs +0 -1
  48. package/dist/packages/threejs/src/utils/helper.js +0 -47
  49. package/dist/packages/threejs/src/utils/modelSerialize.cjs +0 -1
  50. package/dist/packages/threejs/src/utils/modelSerialize.js +0 -225
  51. package/dist/packages/threejs/src/utils/sceneRebuilder.cjs +0 -1
  52. package/dist/packages/threejs/src/utils/sceneRebuilder.js +0 -138
  53. package/dist/packages/threejs/src/workers/gltfParser.worker.cjs +0 -1
  54. package/dist/packages/threejs/src/workers/gltfParser.worker.js +0 -11
  55. package/dist/packages/threejs/src/workers/gltfParserOptimized.worker.cjs +0 -1
  56. package/dist/packages/threejs/src/workers/gltfParserOptimized.worker.js +0 -11
  57. /package/dist/{packages/threejs/src/utils/modelOptimizer.cjs → modelOptimizer-A0Cs6f9e.cjs} +0 -0
package/dist/hooks.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("./packages/threejs/src/hooks/useThreeJs.cjs"),r=require("./packages/threejs/src/hooks/useRaycaster.cjs"),e=require("./packages/threejs/src/hooks/useObb.cjs"),t=require("./packages/threejs/src/hooks/useGLTFLoader.cjs"),u=require("./packages/threejs/src/hooks/useBatchGLTFLoader.cjs");exports.useThreeJs=s.useThreeJs;exports.useRaycaster=r.useRaycaster;exports.intersectColor=e.intersectColor;exports.obbObjects=e.obbObjects;exports.useObb=e.useObb;exports.useGLTFLoader=t.useGLTFLoader;exports.useBatchGLTFLoader=u.useBatchGLTFLoader;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./useBatchGLTFLoader-D3gPYO-K.cjs"),r=require("./PredictiveLoader-BXCwkdSX.cjs");exports.intersectColor=e.intersectColor;exports.obbObjects=e.obbObjects;exports.useBatchGLTFLoader=e.useBatchGLTFLoader;exports.useObb=e.useObb;exports.useRaycaster=e.useRaycaster;exports.useThreeJs=e.useThreeJs;exports.useGLTFLoader=r.useGLTFLoader;
package/dist/hooks.js CHANGED
@@ -1,14 +1,11 @@
1
- import { useThreeJs as o } from "./packages/threejs/src/hooks/useThreeJs.js";
2
- import { useRaycaster as s } from "./packages/threejs/src/hooks/useRaycaster.js";
3
- import { intersectColor as b, obbObjects as f, useObb as m } from "./packages/threejs/src/hooks/useObb.js";
4
- import { useGLTFLoader as u } from "./packages/threejs/src/hooks/useGLTFLoader.js";
5
- import { useBatchGLTFLoader as c } from "./packages/threejs/src/hooks/useBatchGLTFLoader.js";
1
+ import { i as a, o, c as r, b as t, a as u, u as b } from "./useBatchGLTFLoader-DP_NdYhC.js";
2
+ import { u as L } from "./PredictiveLoader-eiPgVdsJ.js";
6
3
  export {
7
- b as intersectColor,
8
- f as obbObjects,
9
- c as useBatchGLTFLoader,
10
- u as useGLTFLoader,
11
- m as useObb,
12
- s as useRaycaster,
13
- o as useThreeJs
4
+ a as intersectColor,
5
+ o as obbObjects,
6
+ r as useBatchGLTFLoader,
7
+ L as useGLTFLoader,
8
+ t as useObb,
9
+ u as useRaycaster,
10
+ b as useThreeJs
14
11
  };
@@ -25,7 +25,7 @@ class f {
25
25
  }
26
26
  /**
27
27
  * 使用修饰器修改几何体(简化实现)
28
- * 注意: 完整实现需要 three/examples/jsm/modifiers/SimplifyModifier.js
28
+ * 注意: 完整实现需要 three/addons/modifiers/SimplifyModifier.js
29
29
  * 这里提供一个基础实现
30
30
  */
31
31
  modifierModify(o, r) {
package/dist/threejs.cjs CHANGED
@@ -1 +1,3 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=require("./packages/threejs/src/hooks/useThreeJs.cjs"),p=require("./packages/threejs/src/hooks/useRaycaster.cjs"),t=require("./packages/threejs/src/hooks/useObb.cjs"),b=require("./packages/threejs/src/hooks/useGLTFLoader.cjs"),T=require("./packages/threejs/src/hooks/useBatchGLTFLoader.cjs"),e=require("./packages/threejs/src/utils/helper.cjs"),a=require("./packages/threejs/src/utils/css3dHelper.cjs"),m=require("./packages/threejs/src/utils/disposeObject.cjs"),L=require("./packages/threejs/src/utils/common.cjs"),c=require("./packages/threejs/src/utils/ImageLoader.cjs"),r=require("./packages/threejs/src/utils/modelSerialize.cjs"),i=require("./packages/threejs/src/utils/CacheMonitor.cjs"),o=require("./packages/threejs/src/utils/RetryHelper.cjs"),s=require("./packages/threejs/src/utils/PredictiveLoader.cjs"),n=require("./packages/threejs/src/utils/sceneRebuilder.cjs"),d=require("./packages/threejs/src/utils/modelOptimizer.cjs"),h=require("./packages/threejs/src/instance/IDBCache.cjs"),l=require("./packages/threejs/src/instance/threeIns.cjs");exports.useThreeJs=u.useThreeJs;exports.useRaycaster=p.useRaycaster;exports.intersectColor=t.intersectColor;exports.obbObjects=t.obbObjects;exports.useObb=t.useObb;exports.useGLTFLoader=b.useGLTFLoader;exports.useBatchGLTFLoader=T.useBatchGLTFLoader;exports.createArrowHelper=e.createArrowHelper;exports.createAxesHelper=e.createAxesHelper;exports.createBox3Helper=e.createBox3Helper;exports.createCameraHelper=e.createCameraHelper;exports.createGridHelper=e.createGridHelper;exports.createMapControls=e.createMapControls;exports.createOrbitControl=e.createOrbitControl;exports.createRaycaster=e.createRaycaster;exports.createStats=e.createStats;exports.createInfoPlane=a.createInfoPlane;exports.createTagPlane=a.createTagPlane;exports.disposeThreeObject=m.disposeThreeObject;exports.getCommonParent=L.getCommonParent;exports.ImageLoader=c.ImageLoader;exports.initEnvImage=c.initEnvImage;exports.dataToObject3D=r.dataToObject3D;exports.dataToObject3DSync=r.dataToObject3DSync;exports.object3DToData=r.object3DToData;exports.object3DToDataSync=r.object3DToDataSync;exports.CacheMonitor=i.CacheMonitor;exports.cacheMonitor=i.cacheMonitor;exports.ErrorType=o.ErrorType;exports.ModelLoadError=o.ModelLoadError;exports.RetryHelper=o.RetryHelper;exports.PredictiveLoader=s.PredictiveLoader;exports.predictiveLoader=s.predictiveLoader;exports.ProgressiveSceneBuilder=n.ProgressiveSceneBuilder;exports.rebuildScene=n.rebuildScene;exports.ModelOptimizer=d.ModelOptimizer;exports.modelOptimizer=d.modelOptimizer;exports.IDBCache=h.IDBCache;exports.ThreeIns=l.ThreeIns;exports.ViewType=l.ViewType;
1
+ "use strict";var q=Object.defineProperty;var B=(x,e,t)=>e in x?q(x,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):x[e]=t;var i=(x,e,t)=>B(x,typeof e!="symbol"?e+"":e,t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const g=require("./useBatchGLTFLoader-D3gPYO-K.cjs"),n=require("./PredictiveLoader-BXCwkdSX.cjs"),b=require("./ImageLoader-y6-Adf1b.cjs"),V=require("./modelOptimizer-A0Cs6f9e.cjs"),a=require("three"),X="1.4.3",Y=50,Z=20,G=20,O={TOP:"top",RIGHT:"right",LEFT:"left",ISO:"iso"},U={enableDamping:!0,dampingFactor:.25,screenSpacePanning:!1,minDistance:.1,maxDistance:1e3,maxPolarAngle:a.MathUtils.degToRad(60)};class I{constructor(e,t){i(this,"isReady",!1);i(this,"scene",null);i(this,"camera",null);i(this,"renderer",null);i(this,"control",null);i(this,"css3dRenderer",null);i(this,"el",null);i(this,"renderRequested",!1);i(this,"selector",null);i(this,"eventsListener",{});i(this,"stats",null);i(this,"isDispose",!1);i(this,"version","0.0.0");i(this,"boxHelper",null);i(this,"initOpt",{css3d:!1,stats:!1,renderType:"change",initListener:!0,initialFov:50,control:{init:!0,options:{}}});i(this,"setup",e=>{if(this.isDispose=!1,this.selector=e,this.el=document.querySelector(e),!this.el){console.error(`ThreeIns: 找不到元素 ${e}`);return}const[t,h]=this.getTargetSize();if(this.updateCameraFOV(t,h),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,h),this.el.appendChild(this.renderer.domElement),this.initOpt.control&&this.initOpt.control.init){this.control=n.createOrbitControl(this.camera,this.renderer.domElement);const s=Object.assign(U,this.initOpt.control.options||{});Object.keys(s).forEach(F=>{this.control[F]=s[F]})}setTimeout(()=>{this.isReady=!0},Z),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("change",this.requestRenderIfNotRequested),this.initListener()});i(this,"onContextLost",e=>{e.preventDefault(),this.animationFrameId&&cancelAnimationFrame(this.animationFrameId)});i(this,"onContextRestored",e=>{e.preventDefault(),this.dispose(),setTimeout(()=>{this.setup(this.selector)},G)});i(this,"initListener",()=>{this.initOpt.initListener&&window&&window.addEventListener("resize",this.onResize,!1),this.renderer.domElement.addEventListener("webglcontextlost",this.onContextLost,!1),this.renderer.domElement.addEventListener("webglcontextrestored",this.onContextRestored,!1)});i(this,"removeListener",()=>{window&&window.removeEventListener("resize",this.onResize,!1),this.renderer&&this.renderer.domElement&&(this.renderer.domElement.removeEventListener("webglcontextlost",this.onContextLost,!1),this.renderer.domElement.removeEventListener("webglcontextrestored",this.onContextRestored,!1))});i(this,"animate",()=>{this.isDispose||(this.initOpt.renderType==="loop"&&this.onRender(),this.animationFrameId=requestAnimationFrame(this.animate))});i(this,"onRender",()=>{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()))});i(this,"requestRenderIfNotRequested",()=>{this.renderRequested||(this.renderRequested=!0,requestAnimationFrame(()=>{this.onRender()}))});i(this,"onResize",()=>{this.resizeTimer&&clearTimeout(this.resizeTimer),this.resizeTimer=setTimeout(()=>{const[e,t]=this.getTargetSize();this.updateCameraFOV(e,t),this.camera.lookAt(this.scene.position),this.renderer.setSize(e,t),this.css3dRenderer&&this.css3dRenderer.setSize(e,t),this.onRender()},Y)});i(this,"frameArea",(e,t)=>(console.warn(`[ThreeIns] frameArea() 已弃用,建议使用 setView() 方法。
2
+ 旧用法: threeIns.frameArea(model, scale)
3
+ 新用法: threeIns.setView(model, ViewType.ISO, { scale })`),this.setView(e,O.ISO,{scale:t,animate:!1,showBox:!1})));i(this,"setView",(e,t,h={})=>{let s=h.scale||.8,F=h.offset||null,T=h.position||"center",M=h.showBox||!1,H=h.boxColor||16776960,E=h.animate!==void 0?h.animate:!0,w=h.duration||1e3;const R=new a.Box3().setFromObject(e);let d=R.getCenter(new a.Vector3);if(typeof T=="string"){const o=R.getSize(new a.Vector3),l={center:new a.Vector3(0,0,0),"top-left":new a.Vector3(-o.x*.3,o.y*.3,o.z*.3),"top-right":new a.Vector3(o.x*.3,o.y*.3,o.z*.3),"bottom-left":new a.Vector3(-o.x*.3,-o.y*.3,o.z*.3),"bottom-right":new a.Vector3(o.x*.3,-o.y*.3,o.z*.3)},m=l[T]||l.center;t==="top"?d.add(new a.Vector3(m.x,0,m.z)):t==="right"||t==="left"?d.add(new a.Vector3(0,m.y,m.z)):d.add(m)}else T instanceof a.Vector3&&d.add(T);F&&d.add(F);const y={top:new a.Vector3(0,1,0),right:new a.Vector3(2,1,1).normalize(),left:new a.Vector3(-2,1,1).normalize(),iso:new a.Vector3(0,1,1).normalize()},z=y[t]||y.iso,r=R.getSize(new a.Vector3),C=this.camera.aspect,c=a.MathUtils.degToRad(this.camera.fov*.5),P=a.MathUtils.degToRad(80),u=Math.min(Math.atan(Math.tan(c)*C),P);let p;if(t==="top"){const o=r.x*.5/(Math.tan(u)*s),l=r.z*.5/(Math.tan(c)*s);p=Math.max(o,l)}else if(t==="right"||t==="left"){const o=r.y*.5/(Math.tan(c)*s),l=r.z*.5/(Math.tan(c)*s);p=Math.max(o,l)}else{const o=r.x*.5/(Math.tan(u)*s),l=r.y*.5/(Math.tan(c)*s),m=r.z*.5/(Math.tan(c)*s);p=Math.max(o,l,m)}const f=z.clone().multiplyScalar(p).add(d);if(M&&(console.log("📍 相机位置验证:"),console.log(" - 方向向量:",z),console.log(" - 距离:",p.toFixed(2)),console.log(" - 包围盒中心:",d),console.log(" - 计算公式: direction * distance + boxCenter"),console.log(" - 目标位置:",f),console.log(" - 实际相机与中心的距离:",f.clone().sub(d).length().toFixed(2))),M?(this.boxHelper&&(this.scene.remove(this.boxHelper),this.boxHelper=null),this.boxHelper=new a.Box3Helper(R,H),this.scene.add(this.boxHelper)):this.boxHelper&&(this.scene.remove(this.boxHelper),this.boxHelper=null),E){const o=this.camera.position.clone(),l=this.control?this.control.target.clone():new a.Vector3(0,0,0),m=d,A=Date.now(),v=()=>{const j=Date.now()-A,S=Math.min(j/w,1),D=1-Math.pow(1-S,3);if(this.camera.position.lerpVectors(o,f,D),this.control){const L=new a.Vector3;L.lerpVectors(l,m,D),this.control.target.copy(L),this.camera.lookAt(L)}else this.camera.lookAt(d);this.camera.updateProjectionMatrix(),S<1?requestAnimationFrame(v):(this.camera.position.copy(f),this.camera.lookAt(d),this.camera.updateProjectionMatrix(),this.control&&(this.control.target.copy(d),this.control.update()),this.onRender())};v()}else this.camera.position.copy(f),this.camera.lookAt(d),this.camera.updateProjectionMatrix(),this.control&&(this.control.target.copy(d),this.control.update()),this.onRender();if(M){if(console.log("🎥 视角切换信息:"),console.log(" - 视角类型:",t),console.log(" - 相机位置:",f),console.log(" - 观察目标:",d),console.log(" - 方向向量:",z),console.log(" - 包围盒尺寸:",r),console.log(" - 包围盒中心:",R.getCenter(new a.Vector3)),console.log(" - 水平 FOV:",a.MathUtils.radToDeg(u*2).toFixed(2)+"°"),console.log(" - 垂直 FOV:",a.MathUtils.radToDeg(c*2).toFixed(2)+"°"),console.log(" - 宽高比:",C.toFixed(4)),console.log(" - 模型宽度:",r.x.toFixed(2)),console.log(" - 模型高度:",r.y.toFixed(2)),console.log(" - 模型深度:",r.z.toFixed(2)),console.log(" - 传入的 scale 参数:",s),t==="top"){const o=r.x*.5/(Math.tan(u)*s),l=r.z*.5/(Math.tan(c)*s);console.log(" - 模型 X 尺寸 (宽度):",r.x.toFixed(2)),console.log(" - 模型 Z 尺寸 (深度):",r.z.toFixed(2)),console.log(" - tan(halfFovX):",Math.tan(u).toFixed(4)),console.log(" - tan(halfFovY):",Math.tan(c).toFixed(4)),console.log(" - X方向距离计算: (",(r.x*.5).toFixed(2),") / (",Math.tan(u).toFixed(4)," *",s,") =",o.toFixed(2)),console.log(" - Z方向距离计算: (",(r.z*.5).toFixed(2),") / (",Math.tan(c).toFixed(4)," *",s,") =",l.toFixed(2)),console.log(" - X方向距离 (scale="+s+"):",o.toFixed(2)),console.log(" - Z方向距离 (scale="+s+"):",l.toFixed(2))}else if(t==="right"||t==="left"){const o=r.y*.5/(Math.tan(c)*s),l=r.z*.5/(Math.tan(c)*s);console.log(" - Y方向距离 (scale="+s+"):",o.toFixed(2)),console.log(" - Z方向距离 (scale="+s+"):",l.toFixed(2))}else{const o=r.x*.5/(Math.tan(u)*s),l=r.y*.5/(Math.tan(c)*s),m=r.z*.5/(Math.tan(c)*s);console.log(" - 模型 X 尺寸 (宽度):",r.x.toFixed(2)),console.log(" - 模型 Y 尺寸 (高度):",r.y.toFixed(2)),console.log(" - 模型 Z 尺寸 (深度):",r.z.toFixed(2)),console.log(" - tan(halfFovX):",Math.tan(u).toFixed(4)),console.log(" - tan(halfFovY):",Math.tan(c).toFixed(4)),console.log(" - X方向距离计算: (",(r.x*.5).toFixed(2),") / (",Math.tan(u).toFixed(4)," *",s,") =",o.toFixed(2)),console.log(" - Y方向距离计算: (",(r.y*.5).toFixed(2),") / (",Math.tan(c).toFixed(4)," *",s,") =",l.toFixed(2)),console.log(" - Z方向距离计算: (",(r.z*.5).toFixed(2),") / (",Math.tan(c).toFixed(4)," *",s,") =",m.toFixed(2)),console.log(" - X方向距离 (scale="+s+"):",o.toFixed(2)),console.log(" - Y方向距离 (scale="+s+"):",l.toFixed(2)),console.log(" - Z方向距离 (scale="+s+"):",m.toFixed(2)),console.log(" - 最大距离 (Max):",Math.max(o,l,m).toFixed(2))}console.log(" - 最终距离:",p.toFixed(2)),console.log(" - 缩放比例:",s),console.log(" - 动画:",E?"是 ("+w+"ms)":"否")}return{position:f,target:d,distance:p,viewType:t}});i(this,"on",(e,t)=>!e||!t||typeof t!="function"?(console.warn("ThreeIns.on: 无效的参数"),()=>{}):(this.eventsListener[e]||(this.eventsListener[e]=[]),this.eventsListener[e].push(t),()=>this.off(e,t)));this.isReady=!1,this.scene=new a.Scene({}),this.camera=new a.PerspectiveCamera(50,1,.1,2e3),this.renderer=new a.WebGLRenderer({antialias:!0,alpha:!0,precision:"mediump",logarithmicDepthBuffer:!0}),this.version=X,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)}updateCameraFOV(e,t){const h=this.initOpt.initialFov||50,s=Math.tan(Math.PI/180*h/2);this.camera.aspect=e/t,this.camera.fov=360/Math.PI*Math.atan(s*(t/e)),this.camera.updateProjectionMatrix()}initStats(){this.stats=new n.Stats,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)}initCss3dRenderer(){this.css3dRenderer=new n.CSS3DRenderer;const[e,t]=this.getTargetSize();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)}getTargetSize(){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]}off(e,t){if(!e){this.eventsListener={};return}this.eventsListener[e]&&(t?this.eventsListener[e]=this.eventsListener[e].filter(h=>h!==t):this.eventsListener[e]=[])}dispose(){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&&(n.disposeThreeObject(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: 资源已清理完成"))}}i(I,"ViewType",O);exports.intersectColor=g.intersectColor;exports.obbObjects=g.obbObjects;exports.useBatchGLTFLoader=g.useBatchGLTFLoader;exports.useObb=g.useObb;exports.useRaycaster=g.useRaycaster;exports.useThreeJs=g.useThreeJs;exports.CacheMonitor=n.CacheMonitor;exports.ErrorType=n.ErrorType;exports.IDBCache=n.IDBCache;exports.ModelLoadError=n.ModelLoadError;exports.PredictiveLoader=n.PredictiveLoader;exports.ProgressiveSceneBuilder=n.ProgressiveSceneBuilder;exports.RetryHelper=n.RetryHelper;exports.cacheMonitor=n.cacheMonitor;exports.createArrowHelper=n.createArrowHelper;exports.createAxesHelper=n.createAxesHelper;exports.createBox3Helper=n.createBox3Helper;exports.createCameraHelper=n.createCameraHelper;exports.createGridHelper=n.createGridHelper;exports.createMapControls=n.createMapControls;exports.createOrbitControl=n.createOrbitControl;exports.createRaycaster=n.createRaycaster;exports.createStats=n.createStats;exports.dataToObject3D=n.dataToObject3D;exports.dataToObject3DSync=n.dataToObject3DSync;exports.disposeThreeObject=n.disposeThreeObject;exports.object3DToData=n.object3DToData;exports.object3DToDataSync=n.object3DToDataSync;exports.predictiveLoader=n.predictiveLoader;exports.rebuildScene=n.rebuildScene;exports.useGLTFLoader=n.useGLTFLoader;exports.ImageLoader=b.ImageLoader;exports.createInfoPlane=b.createInfoPlane;exports.createTagPlane=b.createTagPlane;exports.getCommonParent=b.getCommonParent;exports.initEnvImage=b.initEnvImage;exports.ModelOptimizer=V.ModelOptimizer;exports.modelOptimizer=V.modelOptimizer;exports.ThreeIns=I;exports.ViewType=O;
package/dist/threejs.js CHANGED
@@ -1,60 +1,430 @@
1
- import { useThreeJs as o } from "./packages/threejs/src/hooks/useThreeJs.js";
2
- import { useRaycaster as a } from "./packages/threejs/src/hooks/useRaycaster.js";
3
- import { intersectColor as p, obbObjects as m, useObb as i } from "./packages/threejs/src/hooks/useObb.js";
4
- import { useGLTFLoader as f } from "./packages/threejs/src/hooks/useGLTFLoader.js";
5
- import { useBatchGLTFLoader as d } from "./packages/threejs/src/hooks/useBatchGLTFLoader.js";
6
- import { createArrowHelper as l, createAxesHelper as b, createBox3Helper as T, createCameraHelper as L, createGridHelper as O, createMapControls as h, createOrbitControl as u, createRaycaster as y, createStats as C } from "./packages/threejs/src/utils/helper.js";
7
- import { createInfoPlane as j, createTagPlane as H } from "./packages/threejs/src/utils/css3dHelper.js";
8
- import { disposeThreeObject as I } from "./packages/threejs/src/utils/disposeObject.js";
9
- import { getCommonParent as P } from "./packages/threejs/src/utils/common.js";
10
- import { ImageLoader as v, initEnvImage as B } from "./packages/threejs/src/utils/ImageLoader.js";
11
- import { dataToObject3D as G, dataToObject3DSync as R, object3DToData as w, object3DToDataSync as z } from "./packages/threejs/src/utils/modelSerialize.js";
12
- import { CacheMonitor as F, cacheMonitor as J } from "./packages/threejs/src/utils/CacheMonitor.js";
13
- import { ErrorType as k, ModelLoadError as q, RetryHelper as K } from "./packages/threejs/src/utils/RetryHelper.js";
14
- import { PredictiveLoader as Q, predictiveLoader as U } from "./packages/threejs/src/utils/PredictiveLoader.js";
15
- import { ProgressiveSceneBuilder as X, rebuildScene as Y } from "./packages/threejs/src/utils/sceneRebuilder.js";
16
- import { ModelOptimizer as _, modelOptimizer as $ } from "./packages/threejs/src/utils/modelOptimizer.js";
17
- import { IDBCache as re } from "./packages/threejs/src/instance/IDBCache.js";
18
- import { ThreeIns as te, ViewType as ae } from "./packages/threejs/src/instance/threeIns.js";
1
+ var A = Object.defineProperty;
2
+ var P = (u, e, t) => e in u ? A(u, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : u[e] = t;
3
+ var i = (u, e, t) => P(u, typeof e != "symbol" ? e + "" : e, t);
4
+ import { i as oe, o as ie, c as ne, b as re, a as ae, u as le } from "./useBatchGLTFLoader-DP_NdYhC.js";
5
+ import { d as j, S as V, s as q, j as X } from "./PredictiveLoader-eiPgVdsJ.js";
6
+ import { C as he, E as de, I as me, M as fe, P as pe, q as ue, R as xe, n as ge, h as Fe, g as Re, b as ze, c as we, a as Me, e as be, f as Ee, i as Le, l as Te, m as Oe, o as Ce, k as ve, p as ye, r as Se, u as De } from "./PredictiveLoader-eiPgVdsJ.js";
7
+ import { I as He, c as Ae, a as Pe, g as je, i as Ve } from "./ImageLoader-CMAmH-92.js";
8
+ import { ModelOptimizer as Xe, modelOptimizer as Ye } from "./modelOptimizer-D6fRg-DF.js";
9
+ import { MathUtils as F, Scene as Y, PerspectiveCamera as B, WebGLRenderer as Z, Box3 as _, Vector3 as a, Box3Helper as G } from "three";
10
+ const N = "1.4.3", W = 50, k = 20, U = 20, y = {
11
+ TOP: "top",
12
+ // 俯视(从上往下)
13
+ RIGHT: "right",
14
+ // 侧视(从右往左)
15
+ LEFT: "left",
16
+ // 左侧视
17
+ ISO: "iso"
18
+ // 正斜视(等轴测视角)
19
+ }, $ = {
20
+ enableDamping: !0,
21
+ dampingFactor: 0.25,
22
+ screenSpacePanning: !1,
23
+ minDistance: 0.1,
24
+ maxDistance: 1e3,
25
+ maxPolarAngle: F.degToRad(60)
26
+ };
27
+ class J {
28
+ /**
29
+ * 构造函数
30
+ * @param {string} selector - DOM 容器选择器
31
+ * @param {Object} option - 配置选项
32
+ * @param {boolean} [option.css3d=false] - 是否启用 CSS3D 渲染器
33
+ * @param {boolean} [option.stats=false] - 是否显示性能统计
34
+ * @param {string} [option.renderType='change'] - 渲染类型: 'loop' 或 'change'
35
+ * @param {boolean} [option.initListener=true] - 是否初始化事件监听器
36
+ * @param {number} [option.initialFov=50] - 初始相机 FOV 值
37
+ * @param {Object} [option.control] - 控制器配置
38
+ * @param {boolean} [option.control.init=true] - 是否初始化控制器
39
+ * @param {Object} [option.control.options={}] - 控制器选项
40
+ */
41
+ constructor(e, t) {
42
+ i(this, "isReady", !1);
43
+ i(this, "scene", null);
44
+ i(this, "camera", null);
45
+ i(this, "renderer", null);
46
+ i(this, "control", null);
47
+ i(this, "css3dRenderer", null);
48
+ i(this, "el", null);
49
+ i(this, "renderRequested", !1);
50
+ i(this, "selector", null);
51
+ i(this, "eventsListener", {});
52
+ i(this, "stats", null);
53
+ i(this, "isDispose", !1);
54
+ i(this, "version", "0.0.0");
55
+ i(this, "boxHelper", null);
56
+ i(this, "initOpt", {
57
+ css3d: !1,
58
+ stats: !1,
59
+ renderType: "change",
60
+ initListener: !0,
61
+ // 使用布尔值代替字符串
62
+ initialFov: 50,
63
+ // 初始 FOV 值,用于避免全屏切换时的累积误差
64
+ control: {
65
+ init: !0,
66
+ options: {}
67
+ }
68
+ });
69
+ /**
70
+ * 初始化场景
71
+ * @param {string} selector - DOM 容器选择器
72
+ */
73
+ i(this, "setup", (e) => {
74
+ if (this.isDispose = !1, this.selector = e, this.el = document.querySelector(e), !this.el) {
75
+ console.error(`ThreeIns: 找不到元素 ${e}`);
76
+ return;
77
+ }
78
+ const [t, h] = this.getTargetSize();
79
+ if (this.updateCameraFOV(t, h), 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, h), this.el.appendChild(this.renderer.domElement), this.initOpt.control && this.initOpt.control.init) {
80
+ this.control = j(this.camera, this.renderer.domElement);
81
+ const s = Object.assign(
82
+ $,
83
+ this.initOpt.control.options || {}
84
+ );
85
+ Object.keys(s).forEach((x) => {
86
+ this.control[x] = s[x];
87
+ });
88
+ }
89
+ setTimeout(() => {
90
+ this.isReady = !0;
91
+ }, 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(
92
+ "change",
93
+ this.requestRenderIfNotRequested
94
+ ), this.initListener();
95
+ });
96
+ /**
97
+ * WebGL 上下文丢失处理
98
+ * @param {Event} e - 事件对象
99
+ */
100
+ i(this, "onContextLost", (e) => {
101
+ e.preventDefault(), this.animationFrameId && cancelAnimationFrame(this.animationFrameId);
102
+ });
103
+ /**
104
+ * WebGL 上下文恢复处理
105
+ * @param {Event} e - 事件对象
106
+ */
107
+ i(this, "onContextRestored", (e) => {
108
+ e.preventDefault(), this.dispose(), setTimeout(() => {
109
+ this.setup(this.selector);
110
+ }, U);
111
+ });
112
+ /**
113
+ * 初始化事件监听器
114
+ */
115
+ i(this, "initListener", () => {
116
+ this.initOpt.initListener && window && window.addEventListener("resize", this.onResize, !1), this.renderer.domElement.addEventListener(
117
+ "webglcontextlost",
118
+ this.onContextLost,
119
+ !1
120
+ ), this.renderer.domElement.addEventListener(
121
+ "webglcontextrestored",
122
+ this.onContextRestored,
123
+ !1
124
+ );
125
+ });
126
+ /**
127
+ * 移除事件监听器
128
+ */
129
+ i(this, "removeListener", () => {
130
+ window && window.removeEventListener("resize", this.onResize, !1), this.renderer && this.renderer.domElement && (this.renderer.domElement.removeEventListener(
131
+ "webglcontextlost",
132
+ this.onContextLost,
133
+ !1
134
+ ), this.renderer.domElement.removeEventListener(
135
+ "webglcontextrestored",
136
+ this.onContextRestored,
137
+ !1
138
+ ));
139
+ });
140
+ /**
141
+ * 渲染循环(loop 模式)
142
+ */
143
+ i(this, "animate", () => {
144
+ this.isDispose || (this.initOpt.renderType === "loop" && this.onRender(), this.animationFrameId = requestAnimationFrame(this.animate));
145
+ });
146
+ /**
147
+ * 执行渲染
148
+ */
149
+ i(this, "onRender", () => {
150
+ 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()));
151
+ });
152
+ /**
153
+ * 请求渲染(如果尚未请求)
154
+ */
155
+ i(this, "requestRenderIfNotRequested", () => {
156
+ this.renderRequested || (this.renderRequested = !0, requestAnimationFrame(() => {
157
+ this.onRender();
158
+ }));
159
+ });
160
+ /**
161
+ * 处理窗口大小变化(带防抖)
162
+ */
163
+ i(this, "onResize", () => {
164
+ this.resizeTimer && clearTimeout(this.resizeTimer), this.resizeTimer = setTimeout(() => {
165
+ const [e, t] = this.getTargetSize();
166
+ this.updateCameraFOV(e, t), this.camera.lookAt(this.scene.position), this.renderer.setSize(e, t), this.css3dRenderer && this.css3dRenderer.setSize(e, t), this.onRender();
167
+ }, W);
168
+ });
169
+ /**
170
+ * @deprecated 此方法已弃用,请使用 setView() 方法代替
171
+ *
172
+ * frameArea 仅为兼容旧版本保留,功能已被 setView() 完全覆盖
173
+ *
174
+ * 旧用法:
175
+ * threeIns.frameArea(model, 1.0)
176
+ *
177
+ * 推荐用法:
178
+ * threeIns.setView(model, ViewType.ISO, { scale: 1.0 })
179
+ *
180
+ * @param {Object3D} model - 要调整视角的 3D 模型对象
181
+ * @param {number} [scale=0.8] - 缩放比例,1=占满画布,0.5=50%,2.0=200%
182
+ * @returns {Object} 返回 setView 的结果
183
+ */
184
+ i(this, "frameArea", (e, t) => (console.warn(
185
+ `[ThreeIns] frameArea() 已弃用,建议使用 setView() 方法。
186
+ 旧用法: threeIns.frameArea(model, scale)
187
+ 新用法: threeIns.setView(model, ViewType.ISO, { scale })`
188
+ ), this.setView(e, y.ISO, { scale: t, animate: !1, showBox: !1 })));
189
+ /**
190
+ * 切换到指定视角
191
+ * 根据视角类型自动调整相机位置和朝向,支持缩放比例控制
192
+ *
193
+ * @param {Object3D} model - 3D 物体对象
194
+ * @param {string} viewType - 视角类型,使用 ViewType 枚举
195
+ * - 'top': 俯视(从上往下看 Y 轴正方向)
196
+ * - 'right': 侧视(从右往左看 X 轴正方向)
197
+ * - 'left': 左侧视(从左往右看 X 轴负方向)
198
+ * - 'iso': 正斜视(等轴测视角,45°角)
199
+ * @param {Object} [options] - 可选配置
200
+ * @param {number} [options.scale=1] - 缩放比例,控制模型在画布中的占比
201
+ * @param {string|Vector3} [options.position='center'] - 模型在画布中的位置
202
+ * - 字符串选项:'center'(中心), 'top-left'(左上), 'top-right'(右上), 'bottom-left'(左下), 'bottom-right'(右下)
203
+ * - Vector3:自定义偏移向量
204
+ * @param {Vector3} [options.offset] - 额外的手动偏移量,在 position 基础上再次调整
205
+ * @param {boolean} [options.showBox=false] - 是否显示包围盒辅助线
206
+ * @param {number} [options.boxColor=0xffff00] - 包围盒颜色
207
+ * @param {boolean} [options.animate=true] - 是否使用动画过渡
208
+ * @param {number} [options.duration=1000] - 动画持续时间(毫秒)
209
+ * @returns {Object} 返回相机位置和模型信息
210
+ * @returns {Vector3} return.position - 相机位置
211
+ * @returns {Vector3} return.target - 相机观察目标点
212
+ * @returns {number} return.distance - 相机到模型的距离
213
+ *
214
+ * @example
215
+ * // 导入 ViewType 枚举
216
+ * import { ThreeIns, ViewType } from 'threejs';
217
+ *
218
+ * // 切换到俯视,模型占满画布,居中显示
219
+ * threeIns.setView(model, ViewType.TOP);
220
+ *
221
+ * // 切换到等轴测,模型占画布的 80%,左上角显示
222
+ * threeIns.setView(model, ViewType.ISO, {
223
+ * scale: 0.8,
224
+ * position: 'top-left'
225
+ * });
226
+ *
227
+ * // 切换到斜视,显示包围盒,右上角显示
228
+ * threeIns.setView(model, ViewType.ISO, {
229
+ * position: 'top-right',
230
+ * showBox: true,
231
+ * animate: false
232
+ * });
233
+ *
234
+ * // 切换到侧视,自定义观察点
235
+ * threeIns.setView(model, ViewType.RIGHT, {
236
+ * position: new THREE.Vector3(100, 0, 0),
237
+ * scale: 0.8
238
+ * });
239
+ *
240
+ * // 组合使用 position 和 offset
241
+ * threeIns.setView(model, ViewType.TOP, {
242
+ * position: 'top-left', // 先自动定位到左上
243
+ * offset: new THREE.Vector3(50, 0, 0), // 再额外向右偏移 50
244
+ * scale: 0.8
245
+ * });
246
+ *
247
+ * // 或者使用类静态属性(向后兼容)
248
+ * threeIns.setView(model, ThreeIns.ViewType.TOP);
249
+ */
250
+ i(this, "setView", (e, t, h = {}) => {
251
+ let s = h.scale || 0.8, x = h.offset || null, R = h.position || "center", z = h.showBox || !1, S = h.boxColor || 16776960, b = h.animate !== void 0 ? h.animate : !0, E = h.duration || 1e3;
252
+ const g = new _().setFromObject(e);
253
+ let c = g.getCenter(new a());
254
+ if (typeof R == "string") {
255
+ const o = g.getSize(new a()), r = {
256
+ center: new a(0, 0, 0),
257
+ "top-left": new a(-o.x * 0.3, o.y * 0.3, o.z * 0.3),
258
+ "top-right": new a(o.x * 0.3, o.y * 0.3, o.z * 0.3),
259
+ "bottom-left": new a(-o.x * 0.3, -o.y * 0.3, o.z * 0.3),
260
+ "bottom-right": new a(o.x * 0.3, -o.y * 0.3, o.z * 0.3)
261
+ }, d = r[R] || r.center;
262
+ t === "top" ? c.add(new a(d.x, 0, d.z)) : t === "right" || t === "left" ? c.add(new a(0, d.y, d.z)) : c.add(d);
263
+ } else R instanceof a && c.add(R);
264
+ x && c.add(x);
265
+ const L = {
266
+ top: new a(0, 1, 0),
267
+ // 从上往下:Y 轴正方向
268
+ right: new a(2, 1, 1).normalize(),
269
+ // 从右往左:X 轴正方向
270
+ left: new a(-2, 1, 1).normalize(),
271
+ // 从左往右:X 轴负方向
272
+ iso: new a(0, 1, 1).normalize()
273
+ // 等轴测:从对角线上方俯视
274
+ }, w = L[t] || L.iso, n = g.getSize(new a()), T = this.camera.aspect, l = F.degToRad(this.camera.fov * 0.5), D = F.degToRad(80), m = Math.min(Math.atan(Math.tan(l) * T), D);
275
+ let f;
276
+ if (t === "top") {
277
+ const o = n.x * 0.5 / (Math.tan(m) * s), r = n.z * 0.5 / (Math.tan(l) * s);
278
+ f = Math.max(o, r);
279
+ } else if (t === "right" || t === "left") {
280
+ const o = n.y * 0.5 / (Math.tan(l) * s), r = n.z * 0.5 / (Math.tan(l) * s);
281
+ f = Math.max(o, r);
282
+ } else {
283
+ const o = n.x * 0.5 / (Math.tan(m) * s), r = n.y * 0.5 / (Math.tan(l) * s), d = n.z * 0.5 / (Math.tan(l) * s);
284
+ f = Math.max(o, r, d);
285
+ }
286
+ const p = w.clone().multiplyScalar(f).add(c);
287
+ if (z && (console.log("📍 相机位置验证:"), console.log(" - 方向向量:", w), console.log(" - 距离:", f.toFixed(2)), console.log(" - 包围盒中心:", c), console.log(" - 计算公式: direction * distance + boxCenter"), console.log(" - 目标位置:", p), console.log(" - 实际相机与中心的距离:", p.clone().sub(c).length().toFixed(2))), z ? (this.boxHelper && (this.scene.remove(this.boxHelper), this.boxHelper = null), this.boxHelper = new G(g, S), this.scene.add(this.boxHelper)) : this.boxHelper && (this.scene.remove(this.boxHelper), this.boxHelper = null), b) {
288
+ const o = this.camera.position.clone(), r = this.control ? this.control.target.clone() : new a(0, 0, 0), d = c, I = Date.now(), O = () => {
289
+ const H = Date.now() - I, C = Math.min(H / E, 1), v = 1 - Math.pow(1 - C, 3);
290
+ if (this.camera.position.lerpVectors(o, p, v), this.control) {
291
+ const M = new a();
292
+ M.lerpVectors(r, d, v), this.control.target.copy(M), this.camera.lookAt(M);
293
+ } else
294
+ this.camera.lookAt(c);
295
+ this.camera.updateProjectionMatrix(), C < 1 ? requestAnimationFrame(O) : (this.camera.position.copy(p), this.camera.lookAt(c), this.camera.updateProjectionMatrix(), this.control && (this.control.target.copy(c), this.control.update()), this.onRender());
296
+ };
297
+ O();
298
+ } else
299
+ this.camera.position.copy(p), this.camera.lookAt(c), this.camera.updateProjectionMatrix(), this.control && (this.control.target.copy(c), this.control.update()), this.onRender();
300
+ if (z) {
301
+ if (console.log("🎥 视角切换信息:"), console.log(" - 视角类型:", t), console.log(" - 相机位置:", p), console.log(" - 观察目标:", c), console.log(" - 方向向量:", w), console.log(" - 包围盒尺寸:", n), console.log(" - 包围盒中心:", g.getCenter(new a())), console.log(" - 水平 FOV:", F.radToDeg(m * 2).toFixed(2) + "°"), console.log(" - 垂直 FOV:", F.radToDeg(l * 2).toFixed(2) + "°"), console.log(" - 宽高比:", T.toFixed(4)), console.log(" - 模型宽度:", n.x.toFixed(2)), console.log(" - 模型高度:", n.y.toFixed(2)), console.log(" - 模型深度:", n.z.toFixed(2)), console.log(" - 传入的 scale 参数:", s), t === "top") {
302
+ const o = n.x * 0.5 / (Math.tan(m) * s), r = n.z * 0.5 / (Math.tan(l) * s);
303
+ console.log(" - 模型 X 尺寸 (宽度):", n.x.toFixed(2)), console.log(" - 模型 Z 尺寸 (深度):", n.z.toFixed(2)), console.log(" - tan(halfFovX):", Math.tan(m).toFixed(4)), console.log(" - tan(halfFovY):", Math.tan(l).toFixed(4)), console.log(" - X方向距离计算: (", (n.x * 0.5).toFixed(2), ") / (", Math.tan(m).toFixed(4), " *", s, ") =", o.toFixed(2)), console.log(" - Z方向距离计算: (", (n.z * 0.5).toFixed(2), ") / (", Math.tan(l).toFixed(4), " *", s, ") =", r.toFixed(2)), console.log(" - X方向距离 (scale=" + s + "):", o.toFixed(2)), console.log(" - Z方向距离 (scale=" + s + "):", r.toFixed(2));
304
+ } else if (t === "right" || t === "left") {
305
+ const o = n.y * 0.5 / (Math.tan(l) * s), r = n.z * 0.5 / (Math.tan(l) * s);
306
+ console.log(" - Y方向距离 (scale=" + s + "):", o.toFixed(2)), console.log(" - Z方向距离 (scale=" + s + "):", r.toFixed(2));
307
+ } else {
308
+ const o = n.x * 0.5 / (Math.tan(m) * s), r = n.y * 0.5 / (Math.tan(l) * s), d = n.z * 0.5 / (Math.tan(l) * s);
309
+ console.log(" - 模型 X 尺寸 (宽度):", n.x.toFixed(2)), console.log(" - 模型 Y 尺寸 (高度):", n.y.toFixed(2)), console.log(" - 模型 Z 尺寸 (深度):", n.z.toFixed(2)), console.log(" - tan(halfFovX):", Math.tan(m).toFixed(4)), console.log(" - tan(halfFovY):", Math.tan(l).toFixed(4)), console.log(" - X方向距离计算: (", (n.x * 0.5).toFixed(2), ") / (", Math.tan(m).toFixed(4), " *", s, ") =", o.toFixed(2)), console.log(" - Y方向距离计算: (", (n.y * 0.5).toFixed(2), ") / (", Math.tan(l).toFixed(4), " *", s, ") =", r.toFixed(2)), console.log(" - Z方向距离计算: (", (n.z * 0.5).toFixed(2), ") / (", Math.tan(l).toFixed(4), " *", s, ") =", d.toFixed(2)), console.log(" - X方向距离 (scale=" + s + "):", o.toFixed(2)), console.log(" - Y方向距离 (scale=" + s + "):", r.toFixed(2)), console.log(" - Z方向距离 (scale=" + s + "):", d.toFixed(2)), console.log(" - 最大距离 (Max):", Math.max(o, r, d).toFixed(2));
310
+ }
311
+ console.log(" - 最终距离:", f.toFixed(2)), console.log(" - 缩放比例:", s), console.log(" - 动画:", b ? "是 (" + E + "ms)" : "否");
312
+ }
313
+ return {
314
+ position: p,
315
+ target: c,
316
+ distance: f,
317
+ viewType: t
318
+ };
319
+ });
320
+ /**
321
+ * 注册事件监听器
322
+ * @param {string} event - 事件名称
323
+ * @param {Function} callback - 回调函数
324
+ * @returns {Function} 返回取消监听的函数
325
+ */
326
+ i(this, "on", (e, t) => !e || !t || typeof t != "function" ? (console.warn("ThreeIns.on: 无效的参数"), () => {
327
+ }) : (this.eventsListener[e] || (this.eventsListener[e] = []), this.eventsListener[e].push(t), () => this.off(e, t)));
328
+ this.isReady = !1, this.scene = new Y({}), this.camera = new B(50, 1, 0.1, 2e3), this.renderer = new Z({
329
+ antialias: !0,
330
+ alpha: !0,
331
+ precision: "mediump",
332
+ logarithmicDepthBuffer: !0
333
+ }), 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);
334
+ }
335
+ /**
336
+ * 更新相机 FOV 以适应容器尺寸
337
+ * @private
338
+ * @param {number} domW - 容器宽度
339
+ * @param {number} domH - 容器高度
340
+ */
341
+ updateCameraFOV(e, t) {
342
+ const h = this.initOpt.initialFov || 50, s = Math.tan(Math.PI / 180 * h / 2);
343
+ this.camera.aspect = e / t, this.camera.fov = 360 / Math.PI * Math.atan(s * (t / e)), this.camera.updateProjectionMatrix();
344
+ }
345
+ /**
346
+ * 初始化性能统计
347
+ */
348
+ initStats() {
349
+ this.stats = new V(), 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);
350
+ }
351
+ /**
352
+ * 初始化 CSS3D 渲染器
353
+ */
354
+ initCss3dRenderer() {
355
+ this.css3dRenderer = new q();
356
+ const [e, t] = this.getTargetSize();
357
+ 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);
358
+ }
359
+ /**
360
+ * 获取目标容器尺寸
361
+ * 使用智能缓存策略:全屏时使用窗口尺寸,非全屏时使用元素尺寸
362
+ * @returns {[number, number]} [width, height]
363
+ */
364
+ getTargetSize() {
365
+ 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];
366
+ }
367
+ /**
368
+ * 移除事件监听器
369
+ * @param {string} event - 事件名称
370
+ * @param {Function} [callback] - 可选的回调函数,如果不提供则移除该事件的所有监听器
371
+ */
372
+ off(e, t) {
373
+ if (!e) {
374
+ this.eventsListener = {};
375
+ return;
376
+ }
377
+ this.eventsListener[e] && (t ? this.eventsListener[e] = this.eventsListener[e].filter((h) => h !== t) : this.eventsListener[e] = []);
378
+ }
379
+ /**
380
+ * 清理所有资源
381
+ */
382
+ dispose() {
383
+ 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 && (X(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: 资源已清理完成"));
384
+ }
385
+ }
386
+ // 存储包围盒辅助器
387
+ // 视角类型枚举(作为类静态属性引用,保持向后兼容)
388
+ i(J, "ViewType", y);
19
389
  export {
20
- F as CacheMonitor,
21
- k as ErrorType,
22
- re as IDBCache,
23
- v as ImageLoader,
24
- q as ModelLoadError,
25
- _ as ModelOptimizer,
26
- Q as PredictiveLoader,
27
- X as ProgressiveSceneBuilder,
28
- K as RetryHelper,
29
- te as ThreeIns,
30
- ae as ViewType,
31
- J as cacheMonitor,
32
- l as createArrowHelper,
33
- b as createAxesHelper,
34
- T as createBox3Helper,
35
- L as createCameraHelper,
36
- O as createGridHelper,
37
- j as createInfoPlane,
38
- h as createMapControls,
39
- u as createOrbitControl,
40
- y as createRaycaster,
41
- C as createStats,
42
- H as createTagPlane,
43
- G as dataToObject3D,
44
- R as dataToObject3DSync,
45
- I as disposeThreeObject,
46
- P as getCommonParent,
47
- B as initEnvImage,
48
- p as intersectColor,
49
- $ as modelOptimizer,
50
- m as obbObjects,
51
- w as object3DToData,
52
- z as object3DToDataSync,
53
- U as predictiveLoader,
54
- Y as rebuildScene,
55
- d as useBatchGLTFLoader,
56
- f as useGLTFLoader,
57
- i as useObb,
58
- a as useRaycaster,
59
- o as useThreeJs
390
+ he as CacheMonitor,
391
+ de as ErrorType,
392
+ me as IDBCache,
393
+ He as ImageLoader,
394
+ fe as ModelLoadError,
395
+ Xe as ModelOptimizer,
396
+ pe as PredictiveLoader,
397
+ ue as ProgressiveSceneBuilder,
398
+ xe as RetryHelper,
399
+ J as ThreeIns,
400
+ y as ViewType,
401
+ ge as cacheMonitor,
402
+ Fe as createArrowHelper,
403
+ Re as createAxesHelper,
404
+ ze as createBox3Helper,
405
+ we as createCameraHelper,
406
+ Me as createGridHelper,
407
+ Ae as createInfoPlane,
408
+ be as createMapControls,
409
+ j as createOrbitControl,
410
+ Ee as createRaycaster,
411
+ Le as createStats,
412
+ Pe as createTagPlane,
413
+ Te as dataToObject3D,
414
+ Oe as dataToObject3DSync,
415
+ X as disposeThreeObject,
416
+ je as getCommonParent,
417
+ Ve as initEnvImage,
418
+ oe as intersectColor,
419
+ Ye as modelOptimizer,
420
+ ie as obbObjects,
421
+ Ce as object3DToData,
422
+ ve as object3DToDataSync,
423
+ ye as predictiveLoader,
424
+ Se as rebuildScene,
425
+ ne as useBatchGLTFLoader,
426
+ De as useGLTFLoader,
427
+ re as useObb,
428
+ ae as useRaycaster,
429
+ le as useThreeJs
60
430
  };
@@ -0,0 +1,5 @@
1
+ "use strict";const c=require("three"),C=require("vue"),I=require("./PredictiveLoader-BXCwkdSX.cjs"),u={c:null,u:[new c.Vector3,new c.Vector3,new c.Vector3],e:[]},h={c:null,u:[new c.Vector3,new c.Vector3,new c.Vector3],e:[]},b=[[],[],[]],a=[[],[],[]],y=[],V=new c.Vector3,B=new c.Vector3,j=new c.Vector3,x=new c.Vector3,Z=new c.Vector3,K=new c.Vector3,v=new c.Matrix3,ee=new c.Box3,_=new c.Matrix4,te=new c.Matrix4,ne=new c.Ray;class G{constructor(e=new c.Vector3,r=new c.Vector3,s=new c.Matrix3){this.center=e,this.halfSize=r,this.rotation=s}set(e,r,s){return this.center=e,this.halfSize=r,this.rotation=s,this}copy(e){return this.center.copy(e.center),this.halfSize.copy(e.halfSize),this.rotation.copy(e.rotation),this}clone(){return new this.constructor().copy(this)}getSize(e){return e.copy(this.halfSize).multiplyScalar(2)}clampPoint(e,r){const s=this.halfSize;x.subVectors(e,this.center),this.rotation.extractBasis(V,B,j),r.copy(this.center);const o=c.MathUtils.clamp(x.dot(V),-s.x,s.x);r.add(V.multiplyScalar(o));const t=c.MathUtils.clamp(x.dot(B),-s.y,s.y);r.add(B.multiplyScalar(t));const f=c.MathUtils.clamp(x.dot(j),-s.z,s.z);return r.add(j.multiplyScalar(f)),r}containsPoint(e){return x.subVectors(e,this.center),this.rotation.extractBasis(V,B,j),Math.abs(x.dot(V))<=this.halfSize.x&&Math.abs(x.dot(B))<=this.halfSize.y&&Math.abs(x.dot(j))<=this.halfSize.z}intersectsBox3(e){return this.intersectsOBB(le.fromBox3(e))}intersectsSphere(e){return this.clampPoint(e.center,K),K.distanceToSquared(e.center)<=e.radius*e.radius}intersectsOBB(e,r=Number.EPSILON){u.c=this.center,u.e[0]=this.halfSize.x,u.e[1]=this.halfSize.y,u.e[2]=this.halfSize.z,this.rotation.extractBasis(u.u[0],u.u[1],u.u[2]),h.c=e.center,h.e[0]=e.halfSize.x,h.e[1]=e.halfSize.y,h.e[2]=e.halfSize.z,e.rotation.extractBasis(h.u[0],h.u[1],h.u[2]);for(let t=0;t<3;t++)for(let f=0;f<3;f++)b[t][f]=u.u[t].dot(h.u[f]);x.subVectors(h.c,u.c),y[0]=x.dot(u.u[0]),y[1]=x.dot(u.u[1]),y[2]=x.dot(u.u[2]);for(let t=0;t<3;t++)for(let f=0;f<3;f++)a[t][f]=Math.abs(b[t][f])+r;let s,o;for(let t=0;t<3;t++)if(s=u.e[t],o=h.e[0]*a[t][0]+h.e[1]*a[t][1]+h.e[2]*a[t][2],Math.abs(y[t])>s+o)return!1;for(let t=0;t<3;t++)if(s=u.e[0]*a[0][t]+u.e[1]*a[1][t]+u.e[2]*a[2][t],o=h.e[t],Math.abs(y[0]*b[0][t]+y[1]*b[1][t]+y[2]*b[2][t])>s+o)return!1;return s=u.e[1]*a[2][0]+u.e[2]*a[1][0],o=h.e[1]*a[0][2]+h.e[2]*a[0][1],!(Math.abs(y[2]*b[1][0]-y[1]*b[2][0])>s+o||(s=u.e[1]*a[2][1]+u.e[2]*a[1][1],o=h.e[0]*a[0][2]+h.e[2]*a[0][0],Math.abs(y[2]*b[1][1]-y[1]*b[2][1])>s+o)||(s=u.e[1]*a[2][2]+u.e[2]*a[1][2],o=h.e[0]*a[0][1]+h.e[1]*a[0][0],Math.abs(y[2]*b[1][2]-y[1]*b[2][2])>s+o)||(s=u.e[0]*a[2][0]+u.e[2]*a[0][0],o=h.e[1]*a[1][2]+h.e[2]*a[1][1],Math.abs(y[0]*b[2][0]-y[2]*b[0][0])>s+o)||(s=u.e[0]*a[2][1]+u.e[2]*a[0][1],o=h.e[0]*a[1][2]+h.e[2]*a[1][0],Math.abs(y[0]*b[2][1]-y[2]*b[0][1])>s+o)||(s=u.e[0]*a[2][2]+u.e[2]*a[0][2],o=h.e[0]*a[1][1]+h.e[1]*a[1][0],Math.abs(y[0]*b[2][2]-y[2]*b[0][2])>s+o)||(s=u.e[0]*a[1][0]+u.e[1]*a[0][0],o=h.e[1]*a[2][2]+h.e[2]*a[2][1],Math.abs(y[1]*b[0][0]-y[0]*b[1][0])>s+o)||(s=u.e[0]*a[1][1]+u.e[1]*a[0][1],o=h.e[0]*a[2][2]+h.e[2]*a[2][0],Math.abs(y[1]*b[0][1]-y[0]*b[1][1])>s+o)||(s=u.e[0]*a[1][2]+u.e[1]*a[0][2],o=h.e[0]*a[2][1]+h.e[1]*a[2][0],Math.abs(y[1]*b[0][2]-y[0]*b[1][2])>s+o))}intersectsPlane(e){this.rotation.extractBasis(V,B,j);const r=this.halfSize.x*Math.abs(e.normal.dot(V))+this.halfSize.y*Math.abs(e.normal.dot(B))+this.halfSize.z*Math.abs(e.normal.dot(j)),s=e.normal.dot(this.center)-e.constant;return Math.abs(s)<=r}intersectRay(e,r){return this.getSize(Z),ee.setFromCenterAndSize(x.set(0,0,0),Z),_.setFromMatrix3(this.rotation),_.setPosition(this.center),te.copy(_).invert(),ne.copy(e).applyMatrix4(te),ne.intersectBox(ee,r)?r.applyMatrix4(_):null}intersectsRay(e){return this.intersectRay(e,x)!==null}fromBox3(e){return e.getCenter(this.center),e.getSize(this.halfSize).multiplyScalar(.5),this.rotation.identity(),this}equals(e){return e.center.equals(this.center)&&e.halfSize.equals(this.halfSize)&&e.rotation.equals(this.rotation)}applyMatrix4(e){const r=e.elements;let s=x.set(r[0],r[1],r[2]).length();const o=x.set(r[4],r[5],r[6]).length(),t=x.set(r[8],r[9],r[10]).length();e.determinant()<0&&(s=-s),v.setFromMatrix4(e);const l=1/s,n=1/o,i=1/t;return v.elements[0]*=l,v.elements[1]*=l,v.elements[2]*=l,v.elements[3]*=n,v.elements[4]*=n,v.elements[5]*=n,v.elements[6]*=i,v.elements[7]*=i,v.elements[8]*=i,this.rotation.multiply(v),this.halfSize.x*=s,this.halfSize.y*=o,this.halfSize.z*=t,x.setFromMatrixPosition(e),this.center.add(x),this}}const le=new G,ue={enableDamping:!0,dampingFactor:.25,screenSpacePanning:!1,minDistance:.1,maxDistance:1e3,maxPolarAngle:c.MathUtils.degToRad(60)};function he(F,e){typeof console<"u"&&console.warn&&console.warn(`[ThreeIns] useThreeJs() Hook 已弃用,建议使用 ThreeIns 类代替。
2
+ 旧用法: const { scene, camera } = useThreeJs(selector, options)
3
+ 新用法: const threeIns = new ThreeIns(selector, options)
4
+
5
+ ThreeIns 类提供更完整的 API 和更好的性能。`);const r=Object.assign({css3d:!1,stats:!1,renderType:"change",control:{init:!0,options:{}}},e||{});let s,o,t,f=[];const l=C.ref(!1),n=C.shallowRef(),i=C.ref(0),d=C.ref(0),m=new c.WebGLRenderer({antialias:!0,alpha:!0,precision:"mediump",logarithmicDepthBuffer:!0}),z=new c.Scene({}),p=new c.PerspectiveCamera(50,1,.1,2e3),M=Math.tan(Math.PI/180*p.fov/2);let R=!1;m.setPixelRatio(window.devicePixelRatio);function L(){l.value=!1;const w=Y();i.value=w[0],d.value=w[1],p.aspect=i.value/d.value,p.position.set(47,39,100),p.fov=360/Math.PI*Math.atan(M*(d.value/i.value)),p.lookAt(0,0,0),p.updateProjectionMatrix(),m.setSize(i.value,d.value),s.appendChild(m.domElement),r.stats&&W(),r.css3d&&oe();let P;if(r.control&&r.control.init){P=I.createOrbitControl(p,m.domElement);const A=Object.assign(ue,r.control.options||{});Object.keys(A).forEach(k=>{P[k]=A[k]})}return C.nextTick(()=>l.value=!0),P}function D(w){w.preventDefault(),cancelAnimationFrame(T)}function U(w){w.preventDefault(),L(),T()}function $(w){f.push(w)}function T(w){f&&f.length&&f.forEach(P=>{typeof P=="function"&&P()}),r.renderType==="loop"&&S(),requestAnimationFrame(T)}function S(){R=!1,o&&o.update(),n.value&&n.value.update(),m.render(z,p),t&&t.render(z,p)}function H(){R||(R=!0,requestAnimationFrame(S))}function g(){C.nextTick(()=>{const w=Y();i.value=w[0],d.value=w[1],p.aspect=i.value/d.value,p.fov=360/Math.PI*Math.atan(M*(d.value/i.value)),p.updateProjectionMatrix(),p.lookAt(z.position),m.setSize(i.value,d.value),t&&t.setSize(i.value,d.value),S()})}function Y(){return s=document.querySelector(F),s?[s.clientWidth,s.clientHeight]:[0,0]}function W(){o=new I.Stats,o.dom.style.cssText="position:absolute;top:0;left:0;cursor:pointer;opacity:0.9;z-index:10000",s.appendChild(o.dom)}function se(w,P,A,k,J){const N=new c.Box3().setFromObject(w),Q=N.getSize(new c.Vector3).length(),E=N.getCenter(new c.Vector3);J&&E.add(J);const ae=Q*P*.5,ie=c.MathUtils.degToRad(A.fov*.5),ce=ae/Math.tan(ie),X=new c.Vector3().subVectors(A.position,E).multiply(new c.Vector3(1,1,1)).normalize().multiplyScalar(ce).add(E),q={x:X.x,y:X.y,z:X.z,lookAt_x:E.x,lookAt_y:E.y,lookAt_z:E.z};return A.position.set(q.x,q.y,q.z),A.lookAt(q.lookAt_x,q.lookAt_y,q.lookAt_z),A.updateProjectionMatrix(),k.target.copy(E),k.update(),Q}function oe(){t=new I.CSS3DRenderer,t.setSize(i.value,d.value),t.domElement.style.position="absolute",t.domElement.style.top=0,t.domElement.style.left=0,t.domElement.style.pointerEvents="none",s.appendChild(t.domElement)}function re(){I.disposeThreeObject(z)}return C.onMounted(()=>{n.value=L(),window.addEventListener("resize",g,!1),m.domElement.addEventListener("webglcontextlost",D,!1),m.domElement.addEventListener("webglcontextrestored",U,!1),r.renderType==="loop"?requestAnimationFrame(T):r.renderType==="change"&&n.value&&n.value.addEventListener("change",H)}),C.onUnmounted(()=>{cancelAnimationFrame(T),m.domElement.removeEventListener("resize",g,!1),m.domElement.removeEventListener("webglcontextlost",D,!1),m.domElement.removeEventListener("webglcontextrestored",U,!1),re()}),{addAnimate:$,frameArea:se,onRender:S,css3dRenderer:t,scene:z,camera:p,control:n,renderer:m,domWidth:i,domHeight:d,isReady:l}}const fe=(F="app")=>{const e=new c.Raycaster;e.params.Line.threshold=8;const r=new c.Vector2,s=document.getElementById(F);function o(l,n){const{scaleX:i,scaleY:d}=f(s),{clientWidth:m,clientHeight:z}=n,p=n.getBoundingClientRect(),M=m*i,R=z*d,L=l.clientX-p.left,D=l.clientY-p.top;return r.x=(l.clientX-p.left)/M*2-1,r.y=-((l.clientY-p.top)/R)*2+1,{pointer:r,x:L,y:D}}function t(l,n,i,d){const{pointer:m,x:z,y:p}=o(l,n);return e.setFromCamera(m,i),{intersects:e.intersectObjects(d),pointer:m,x:z,y:p}}function f(l){const n=window.getComputedStyle(l),i=n.transform||n.webkitTransform||n.mozTransform;if(i&&i!=="none"){const d=i.match(/^matrix\((.+)\)$/);if(d){const m=d[1].split(", "),z=parseFloat(m[0]),p=parseFloat(m[3]);return{scaleX:z,scaleY:p}}}return{scaleX:1,scaleY:1}}return{raycaster:e,pointer:r,getPointer:o,getScale:f,getIntersects:t}},O=[],de=new c.Color(16711680),me=()=>{const F=()=>{O.splice(0)},e=(l,n)=>{n.traverse(i=>{i&&r(l,i)})},r=(l,n)=>{if(n.userData.needCheck&&(n.autoUpdateMatrix=!1,n.updateMatrix(),n.updateMatrixWorld(),n.isMesh)){const i=new c.Box3(new c.Vector3).setFromObject(n);n.geometry.userData.obb=new G,n.geometry.userData.obb.halfSize.copy(i.getSize(new c.Vector3)).multiplyScalar(.5).multiplyScalar(.88),n.userData.obb=new G,n.userData.originColor=n.material.color.clone(),n.userData.parentUid=l,O.push({object:n,parentUid:l})}};return{resetObbs:F,initObb:e,getObbObjectByParentUid:l=>O.filter(n=>n.parentUid===l),addObbFromArray:(l,n)=>{for(let i=0,d=n.length;i<d;i++)r(l,n[i])},removeObbFromArray:l=>{const n=O.filter(i=>!l.includes(i.object));O.splice(0,O.length,...n)},removeUidObb:l=>{for(let n=O.length-1;n>=0;n--)O[n].parentUid===l&&O.splice(n,1)}}};function pe(){const{asyncFetch:F}=I.useGLTFLoader();async function e(o,t={}){const{maxConcurrent:f=3,maxRetries:l=3,onProgress:n,onModelLoad:i,onModelError:d}=t,m=new Map,z=new Map,p=[...o];let M=0,R=0;return new Promise((L,D)=>{const U=async T=>{const{path:S,version:H}=T;R++;try{const g=await F(S,H,Y=>{const W=M/o.length*100+Y/o.length;n==null||n(Math.round(W))},{maxRetries:l});if(g)m.set(S,g),i==null||i(S,g);else throw new Error(`模型加载返回空结果: ${S}`)}catch(g){console.error(`[ 批量加载 ] 加载失败: ${S}`,g),z.set(S,g),d==null||d(S,g)}finally{R--,M++;const g=M/o.length*100;n==null||n(Math.round(g)),$()}},$=()=>{if(M>=o.length){z.size>0&&console.warn(`[ 批量加载 ] 完成,但有 ${z.size} 个模型加载失败`),L(m);return}for(;p.length>0&&R<f;){const T=p.shift();U(T)}};$()})}async function r(o,t={}){console.log(`[ 批量预加载 ] 开始预加载 ${o.length} 个模型`);const f=await e(o,{...t,maxConcurrent:t.maxConcurrent||2});return console.log(`[ 批量预加载 ] 完成,成功加载 ${f.size} 个模型`),f}async function s(o,t={}){const f=new Map;for(let l=0;l<o.length;l++)console.log(`[ 分组批量加载 ] 加载第 ${l+1}/${o.length} 组`),(await e(o[l],{...t,onProgress:i=>{var m;const d=l/o.length*100+i/o.length;(m=t.onProgress)==null||m.call(t,Math.round(d))}})).forEach((i,d)=>{f.set(d,i)});return f}return{batchLoad:e,preload:r,batchLoadGroups:s}}exports.intersectColor=de;exports.obbObjects=O;exports.useBatchGLTFLoader=pe;exports.useObb=me;exports.useRaycaster=fe;exports.useThreeJs=he;