three-base 2.0.142 → 2.0.166

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 (231) hide show
  1. package/DirectionalLight.d.ts +6 -6
  2. package/DirectionalLight.js +68 -68
  3. package/EventMap.d.ts +103 -103
  4. package/EventMap.js +17 -17
  5. package/EventMesh.d.ts +18 -18
  6. package/EventMesh.js +59 -59
  7. package/ExtrudeMesh.d.ts +112 -112
  8. package/ExtrudeMesh.js +342 -342
  9. package/FPScontrol.d.ts +531 -511
  10. package/FPScontrol.js +1866 -1799
  11. package/FPScontrol.ts +1922 -1855
  12. package/Fire/Fire.d.ts +28 -28
  13. package/Fire/Fire.js +80 -80
  14. package/Fire/FireGeometry.d.ts +9 -9
  15. package/Fire/FireGeometry.js +40 -40
  16. package/Fire/FireMaterial.d.ts +28 -28
  17. package/Fire/FireMaterial.js +32 -32
  18. package/Fire/index.d.ts +2 -2
  19. package/Fire/index.js +2 -2
  20. package/GLTFDracoLoader.d.ts +71 -71
  21. package/GLTFDracoLoader.js +266 -266
  22. package/GLTFDracoLoader.ts +1 -1
  23. package/Grass/Grass.d.ts +8 -8
  24. package/Grass/Grass.js +38 -38
  25. package/Grass/index.d.ts +2 -2
  26. package/Grass/index.js +2 -2
  27. package/Ground1/Ground1.d.ts +10 -10
  28. package/Ground1/Ground1.js +71 -71
  29. package/Ground1/index.d.ts +1 -1
  30. package/Ground1/index.js +1 -1
  31. package/MeshBase.d.ts +36 -36
  32. package/MeshBase.js +251 -247
  33. package/MeshBase.ts +6 -2
  34. package/Mirror.d.ts +25 -25
  35. package/Mirror.js +143 -143
  36. package/MktMesh/MktMesh.d.ts +301 -291
  37. package/MktMesh/MktMesh.js +1064 -1045
  38. package/MktMesh/MktMesh.ts +32 -11
  39. package/MktMesh/assetUrl.d.ts +59 -35
  40. package/MktMesh/assetUrl.js +165 -69
  41. package/MktMesh/assetUrl.ts +164 -69
  42. package/MktMesh/mktMappingShader.d.ts +12 -12
  43. package/MktMesh/mktMappingShader.js +138 -138
  44. package/MktMesh/mktMappingShader.ts +139 -139
  45. package/MktMesh/mktShader.d.ts +263 -263
  46. package/MktMesh/mktShader.js +1236 -1236
  47. package/MktMesh/mktShader.ts +1344 -1344
  48. package/MktMesh/panoBitmapTexture.d.ts +25 -25
  49. package/MktMesh/panoBitmapTexture.js +52 -52
  50. package/MktMesh/panoBitmapTexture.ts +54 -54
  51. package/MktMesh/panoSlotBind.d.ts +29 -29
  52. package/MktMesh/panoSlotBind.js +106 -106
  53. package/MktMesh/panoSlotBind.ts +153 -153
  54. package/MktMesh/panoSlotRoster.d.ts +22 -22
  55. package/MktMesh/panoSlotRoster.js +169 -169
  56. package/MktMesh/panoSlotRoster.ts +168 -168
  57. package/MktMesh/panoTileStitcher.d.ts +119 -119
  58. package/MktMesh/panoTileStitcher.js +529 -529
  59. package/MktMesh/panoTileStitcher.ts +616 -616
  60. package/MktMesh/types.d.ts +75 -75
  61. package/MktMesh/types.js +1 -1
  62. package/MktMesh/wallCapTessellate.d.ts +33 -33
  63. package/MktMesh/wallCapTessellate.js +97 -97
  64. package/MktMesh/wallCapTessellate.ts +68 -68
  65. package/PipeMesh/PathGeometry.d.ts +44 -44
  66. package/PipeMesh/PathGeometry.js +307 -307
  67. package/PipeMesh/PathPoint.d.ts +17 -17
  68. package/PipeMesh/PathPoint.js +31 -31
  69. package/PipeMesh/PathPointList.d.ts +31 -31
  70. package/PipeMesh/PathPointList.js +209 -209
  71. package/PipeMesh/PathTubeGeometry.d.ts +25 -25
  72. package/PipeMesh/PathTubeGeometry.js +130 -130
  73. package/PipeMesh/PipeMesh.d.ts +25 -25
  74. package/PipeMesh/PipeMesh.js +63 -63
  75. package/PipeMesh/index.d.ts +1 -1
  76. package/PipeMesh/index.js +1 -1
  77. package/PlaneModal1/PlaneModal1.d.ts +34 -34
  78. package/PlaneModal1/PlaneModal1.js +109 -109
  79. package/PlaneModal1/index.d.ts +1 -1
  80. package/PlaneModal1/index.js +1 -1
  81. package/PlaneText.d.ts +27 -27
  82. package/PlaneText.js +35 -35
  83. package/PlaneWithHtml.d.ts +13 -13
  84. package/PlaneWithHtml.js +66 -64
  85. package/PlaneWithHtml.ts +3 -1
  86. package/PointLight/PointLight.d.ts +13 -13
  87. package/PointLight/PointLight.js +64 -64
  88. package/PointLight/index.d.ts +1 -1
  89. package/PointLight/index.js +1 -1
  90. package/Sky/Sky.d.ts +9 -9
  91. package/Sky/Sky.js +22 -22
  92. package/Sky/index.d.ts +1 -1
  93. package/Sky/index.js +1 -1
  94. package/SpotLight.d.ts +6 -6
  95. package/SpotLight.js +72 -72
  96. package/SpriteModal1/SpriteModal1.d.ts +33 -33
  97. package/SpriteModal1/SpriteModal1.js +116 -116
  98. package/SpriteModal1/index.d.ts +1 -1
  99. package/SpriteModal1/index.js +1 -1
  100. package/SpriteText.d.ts +46 -46
  101. package/SpriteText.js +176 -176
  102. package/SpriteText2.d.ts +48 -48
  103. package/SpriteText2.js +223 -223
  104. package/SpriteText3.d.ts +86 -86
  105. package/SpriteText3.js +517 -517
  106. package/SpriteText3.ts +599 -599
  107. package/SpriteWithHtml.d.ts +9 -9
  108. package/SpriteWithHtml.js +46 -44
  109. package/SpriteWithHtml.ts +3 -1
  110. package/Text3D/Text3D.d.ts +20 -20
  111. package/Text3D/Text3D.js +58 -58
  112. package/Text3D/fontController.d.ts +60 -60
  113. package/Text3D/fontController.js +166 -166
  114. package/Text3D/index.d.ts +1 -1
  115. package/Text3D/index.js +1 -1
  116. package/ThreeBase.d.ts +248 -248
  117. package/ThreeBase.js +1202 -1202
  118. package/ThreeBase.ts +1314 -1314
  119. package/ThreeMouse.d.ts +53 -54
  120. package/ThreeMouse.js +453 -453
  121. package/Transition.d.ts +45 -45
  122. package/Transition.js +209 -209
  123. package/Water/Water.d.ts +5 -5
  124. package/Water/Water.js +44 -44
  125. package/Water/index.d.ts +2 -2
  126. package/Water/index.js +2 -2
  127. package/WaterFlow/FloatingDuck.d.ts +88 -88
  128. package/WaterFlow/FloatingDuck.js +307 -307
  129. package/WaterFlow/FloatingDuck.ts +445 -445
  130. package/WaterFlow/GPUFluidSimulation.d.ts +56 -56
  131. package/WaterFlow/GPUFluidSimulation.js +781 -781
  132. package/WaterFlow/GPUFluidSimulation.ts +827 -827
  133. package/WaterFlow/ReservoirSystem.d.ts +106 -106
  134. package/WaterFlow/ReservoirSystem.js +611 -611
  135. package/WaterFlow/ReservoirSystem.ts +754 -754
  136. package/WaterFlow/SPHField.d.ts +35 -35
  137. package/WaterFlow/SPHField.js +203 -203
  138. package/WaterFlow/SPHField.ts +228 -228
  139. package/WaterFlow/ScreenSpaceFluidPass.d.ts +69 -69
  140. package/WaterFlow/ScreenSpaceFluidPass.js +728 -728
  141. package/WaterFlow/ScreenSpaceFluidPass.ts +789 -789
  142. package/WaterFlow/ShallowWaterSurface.d.ts +45 -45
  143. package/WaterFlow/ShallowWaterSurface.js +438 -438
  144. package/WaterFlow/ShallowWaterSurface.ts +510 -510
  145. package/WaterFlow/WaterFlow.d.ts +87 -87
  146. package/WaterFlow/WaterFlow.js +171 -171
  147. package/WaterFlow/WaterFlow.ts +219 -219
  148. package/WaterFlow/types.d.ts +161 -161
  149. package/WaterFlow/types.js +1 -1
  150. package/WaterFlow/types.ts +189 -189
  151. package/WaterFlow/waterFlowPass.d.ts +3 -3
  152. package/WaterFlow/waterFlowPass.js +20 -20
  153. package/WaterFlow/waterFlowPass.ts +40 -40
  154. package/collisionOBB.d.ts +42 -42
  155. package/collisionOBB.js +112 -112
  156. package/collisionOBB.ts +108 -108
  157. package/declare.d.ts +25 -25
  158. package/index.d.ts +1 -1
  159. package/index.js +1 -1
  160. package/instanced/InstancedBatch.d.ts +57 -57
  161. package/instanced/InstancedBatch.js +348 -348
  162. package/instanced/InstancedBatch.ts +406 -406
  163. package/instanced/InstancedChild.d.ts +174 -174
  164. package/instanced/InstancedChild.js +264 -264
  165. package/instanced/InstancedChild.ts +327 -327
  166. package/instanced/InstancedGroup.d.ts +43 -43
  167. package/instanced/InstancedGroup.js +126 -126
  168. package/instanced/InstancedGroup.ts +137 -137
  169. package/instanced/InstancedMeshBase.d.ts +38 -38
  170. package/instanced/InstancedMeshBase.js +282 -282
  171. package/instanced/InstancedTemplate.d.ts +46 -46
  172. package/instanced/InstancedTemplate.js +125 -125
  173. package/keyControls.d.ts +29 -30
  174. package/keyControls.js +101 -101
  175. package/lensflare/LensFlare.d.ts +39 -39
  176. package/lensflare/LensFlare.js +284 -284
  177. package/package.json +6 -1
  178. package/pass/bloom_pass.d.ts +2 -2
  179. package/pass/bloom_pass.js +174 -174
  180. package/pass/cover_pass.d.ts +2 -2
  181. package/pass/cover_pass.js +108 -108
  182. package/pass/debugDepthState.d.ts +20 -20
  183. package/pass/debugDepthState.js +9 -9
  184. package/pass/debugDepthState.ts +22 -22
  185. package/pass/depthTestBias.d.ts +12 -12
  186. package/pass/depthTestBias.js +12 -12
  187. package/pass/depthTestBias.ts +12 -12
  188. package/pass/effectUserData.d.ts +27 -27
  189. package/pass/effectUserData.js +1 -1
  190. package/pass/effectUserData.ts +46 -46
  191. package/pass/frosted_glass_pass.d.ts +2 -2
  192. package/pass/frosted_glass_pass.js +150 -150
  193. package/pass/fsQuad.d.ts +9 -9
  194. package/pass/fsQuad.js +28 -28
  195. package/pass/glow_pass.d.ts +2 -2
  196. package/pass/glow_pass.js +350 -350
  197. package/pass/screen_bloom_pass.d.ts +11 -11
  198. package/pass/screen_bloom_pass.js +136 -136
  199. package/pass/ssao_pass.d.ts +88 -88
  200. package/pass/ssao_pass.js +799 -799
  201. package/pass/ssao_pass.ts +918 -918
  202. package/pass/stroke_pass.d.ts +2 -2
  203. package/pass/stroke_pass.js +267 -267
  204. package/shaders/FXAAShaderMaterial.d.ts +3 -3
  205. package/shaders/FXAAShaderMaterial.js +20 -20
  206. package/shaders/baseDepthVisShader.d.ts +11 -11
  207. package/shaders/baseDepthVisShader.js +36 -36
  208. package/shaders/baseDepthVisShader.ts +36 -36
  209. package/shaders/baseTextureToRenderShader.d.ts +2 -2
  210. package/shaders/baseTextureToRenderShader.js +19 -19
  211. package/shaders/copyShader.d.ts +3 -3
  212. package/shaders/copyShader.js +13 -13
  213. package/shaders/debugDepthCompareShader.d.ts +14 -14
  214. package/shaders/debugDepthCompareShader.js +49 -49
  215. package/shaders/debugDepthCompareShader.ts +50 -50
  216. package/shaders/debugDepthJudgeShader.d.ts +18 -18
  217. package/shaders/debugDepthJudgeShader.js +52 -52
  218. package/shaders/debugDepthJudgeShader.ts +54 -54
  219. package/shaders/debugExcludedShader.d.ts +13 -13
  220. package/shaders/debugExcludedShader.js +46 -46
  221. package/shaders/debugExcludedShader.ts +48 -48
  222. package/spriteTextBg.d.ts +1 -1
  223. package/spriteTextBg.js +20 -20
  224. package/spriteTextBg.ts +20 -20
  225. package/threeLoader.d.ts +35 -35
  226. package/threeLoader.js +518 -518
  227. package/threeUtils.d.ts +71 -53
  228. package/threeUtils.js +363 -329
  229. package/threeUtils.ts +35 -0
  230. package/types.d.ts +2 -2
  231. package/types.js +6 -6
package/collisionOBB.js CHANGED
@@ -1,112 +1,112 @@
1
- /**
2
- * capsuleVsOBB —— 竖直胶囊(第一人称角色)vs 有向包围盒(OBB)的精确穿透查询
3
- *
4
- * ⭐ 为什么是这套:玩家胶囊在 FPS 里是**竖直**的(start/end 的 x/z 相同,仅 y 不同),
5
- * 于是「胶囊 vs OBB」可精确化简为:
6
- * · 水平面(XZ)= 一个点(胶囊中心水平投影)到 OBB 的 2D 最近距离;
7
- * · 竖直(Y)= 胶囊竖直区间 [yBottom, yTop] 与 OBB 竖直区间是否重叠。
8
- * 这比「线段 vs box 通用最近点」更精确(box 是平面,法线恒定),
9
- * 也比「10 条射线模拟体积」物理正确且不抖(射线没有体积,贴墙必漏检)。
10
- *
11
- * ⭐ 一次调用得:穿透深度 depth(>0 即碰撞)+ 指向玩家的单位法线 normal + 碰撞体最近点 contact。
12
- * 位置修正 = 沿 normal 推出 depth(解析解,非贪心搜索);速度修正 = 滑墙投影 v -= (v·n)n。
13
- *
14
- * 零依赖:只用 three 的 Vector3 / Quaternion(标量运算,任何环境可跑)。
15
- */
16
- import { Vector3, Quaternion } from "three";
17
- /**
18
- * ⭐ 穿透噪声门(2026-09-27 探针实测):深度 ≤ 此值视为**未碰撞**。
19
- * 玩家停在「恰好贴合」位(如夹缝 = 胶囊直径)时,浮点残差会产生 ±1e-6 量级的
20
- * 微穿透 —— 不门掉的话,贴合面会以随机符号反复登记投票,回弹方向被钉死在
21
- * 某一面(实测:0.7m 夹缝里方向恒 +X 朝深墙)。真穿透都是毫米级以上,不受影响。
22
- */
23
- export const CAPSULE_DEPTH_EPS = 1e-4;
24
- // 复用的临时量(避免每帧 GC)
25
- const _local = new Vector3();
26
- const _invQ = new Quaternion();
27
- const _nLocal = new Vector3();
28
- const _closestLocal = new Vector3();
29
- /**
30
- * 竖直胶囊 vs 单个 OBB 的最近穿透。
31
- * @param px 胶囊中心水平 x
32
- * @param pz 胶囊中心水平 z
33
- * @param radius 胶囊半径
34
- * @param yBottom 胶囊竖直区间下界(= 脚底 = start.y - radius)
35
- * @param yTop 胶囊竖直区间上界(= 头顶球顶 = end.y + radius)
36
- * @param obb 世界空间 OBB
37
- * @param normalOut 输出:指向玩家的单位法线(世界空间,水平为主、地面/天花板为竖直)
38
- * @param contactOut 输出:碰撞体上最近点(世界空间)
39
- * @returns 穿透深度(>0 表示碰撞;≤0 表示不碰)
40
- */
41
- export function capsuleVsOBB(px, pz, radius, yBottom, yTop, obb, normalOut, contactOut) {
42
- // 玩家水平点 → OBB 局部空间(只取 x/z;y 由竖直区间单独判定)
43
- _local.set(px - obb.center.x, 0, pz - obb.center.z);
44
- _invQ.copy(obb.quat).invert();
45
- _local.applyQuaternion(_invQ);
46
- const lx = _local.x;
47
- const lz = _local.z;
48
- // 2D 最近点(XZ 平面投影为 2D OBB,半尺寸 half.x / half.z)
49
- const cx = Math.max(-obb.half.x, Math.min(obb.half.x, lx));
50
- const cz = Math.max(-obb.half.z, Math.min(obb.half.z, lz));
51
- const dx = lx - cx;
52
- const dz = lz - cz;
53
- const dH = Math.sqrt(dx * dx + dz * dz);
54
- // 竖直区间重叠判定
55
- const oyMin = obb.center.y - obb.half.y;
56
- const oyMax = obb.center.y + obb.half.y;
57
- const yOverlap = yBottom < oyMax && yTop > oyMin;
58
- if (!yOverlap)
59
- return 0;
60
- if (dH > 1e-6) {
61
- // 水平穿透(点在 OBB 水平投影之外或边缘):法线 = 局部 (dx,0,dz) 指向玩家,转回世界
62
- const depth = radius - dH;
63
- if (depth <= CAPSULE_DEPTH_EPS)
64
- return 0;
65
- _nLocal.set(dx, 0, dz).normalize();
66
- normalOut.copy(_nLocal).applyQuaternion(obb.quat);
67
- // 接触点:box 侧面,y 取玩家竖直区间与 box 重叠段中点
68
- const cy = Math.max(oyMin, Math.min(oyMax, (yBottom + yTop) * 0.5));
69
- _closestLocal.set(cx, cy - obb.center.y, cz).applyQuaternion(obb.quat).add(obb.center);
70
- contactOut.copy(_closestLocal);
71
- return depth;
72
- }
73
- // 水平在 OBB 内部(dH≈0):退化现场(玩家中心已陷进 box 水平投影)。
74
- // ⚠️ 不能只做竖直(旧版会把陷进薄墙的角色竖直弹飞);应取**最小正穿透**的那一面托出,法线朝外。
75
- const penX = obb.half.x - Math.abs(lx);
76
- const penZ = obb.half.z - Math.abs(lz);
77
- const penYTop = oyMax - yBottom; // 到顶面(+y)
78
- const penYBot = yTop - oyMin; // 到底面(-y)
79
- let minPen = Infinity;
80
- let fx = 0, fy = 0, fz = 0;
81
- if (penX > 0 && penX < minPen) {
82
- minPen = penX;
83
- fx = Math.sign(lx) || 1;
84
- fy = 0;
85
- fz = 0;
86
- }
87
- if (penZ > 0 && penZ < minPen) {
88
- minPen = penZ;
89
- fx = 0;
90
- fy = 0;
91
- fz = Math.sign(lz) || 1;
92
- }
93
- if (penYTop > 0 && penYTop < minPen) {
94
- minPen = penYTop;
95
- fx = 0;
96
- fy = 1;
97
- fz = 0;
98
- }
99
- if (penYBot > 0 && penYBot < minPen) {
100
- minPen = penYBot;
101
- fx = 0;
102
- fy = -1;
103
- fz = 0;
104
- }
105
- if (minPen === Infinity || minPen <= CAPSULE_DEPTH_EPS)
106
- return 0;
107
- _nLocal.set(fx, fy, fz).normalize();
108
- normalOut.copy(_nLocal).applyQuaternion(obb.quat);
109
- const cy = fy !== 0 ? (fy > 0 ? oyMax : oyMin) : (yBottom + yTop) * 0.5;
110
- contactOut.set(px, cy, pz);
111
- return minPen;
112
- }
1
+ /**
2
+ * capsuleVsOBB —— 竖直胶囊(第一人称角色)vs 有向包围盒(OBB)的精确穿透查询
3
+ *
4
+ * ⭐ 为什么是这套:玩家胶囊在 FPS 里是**竖直**的(start/end 的 x/z 相同,仅 y 不同),
5
+ * 于是「胶囊 vs OBB」可精确化简为:
6
+ * · 水平面(XZ)= 一个点(胶囊中心水平投影)到 OBB 的 2D 最近距离;
7
+ * · 竖直(Y)= 胶囊竖直区间 [yBottom, yTop] 与 OBB 竖直区间是否重叠。
8
+ * 这比「线段 vs box 通用最近点」更精确(box 是平面,法线恒定),
9
+ * 也比「10 条射线模拟体积」物理正确且不抖(射线没有体积,贴墙必漏检)。
10
+ *
11
+ * ⭐ 一次调用得:穿透深度 depth(>0 即碰撞)+ 指向玩家的单位法线 normal + 碰撞体最近点 contact。
12
+ * 位置修正 = 沿 normal 推出 depth(解析解,非贪心搜索);速度修正 = 滑墙投影 v -= (v·n)n。
13
+ *
14
+ * 零依赖:只用 three 的 Vector3 / Quaternion(标量运算,任何环境可跑)。
15
+ */
16
+ import { Vector3, Quaternion } from "three";
17
+ /**
18
+ * ⭐ 穿透噪声门(2026-09-27 探针实测):深度 ≤ 此值视为**未碰撞**。
19
+ * 玩家停在「恰好贴合」位(如夹缝 = 胶囊直径)时,浮点残差会产生 ±1e-6 量级的
20
+ * 微穿透 —— 不门掉的话,贴合面会以随机符号反复登记投票,回弹方向被钉死在
21
+ * 某一面(实测:0.7m 夹缝里方向恒 +X 朝深墙)。真穿透都是毫米级以上,不受影响。
22
+ */
23
+ export const CAPSULE_DEPTH_EPS = 1e-4;
24
+ // 复用的临时量(避免每帧 GC)
25
+ const _local = new Vector3();
26
+ const _invQ = new Quaternion();
27
+ const _nLocal = new Vector3();
28
+ const _closestLocal = new Vector3();
29
+ /**
30
+ * 竖直胶囊 vs 单个 OBB 的最近穿透。
31
+ * @param px 胶囊中心水平 x
32
+ * @param pz 胶囊中心水平 z
33
+ * @param radius 胶囊半径
34
+ * @param yBottom 胶囊竖直区间下界(= 脚底 = start.y - radius)
35
+ * @param yTop 胶囊竖直区间上界(= 头顶球顶 = end.y + radius)
36
+ * @param obb 世界空间 OBB
37
+ * @param normalOut 输出:指向玩家的单位法线(世界空间,水平为主、地面/天花板为竖直)
38
+ * @param contactOut 输出:碰撞体上最近点(世界空间)
39
+ * @returns 穿透深度(>0 表示碰撞;≤0 表示不碰)
40
+ */
41
+ export function capsuleVsOBB(px, pz, radius, yBottom, yTop, obb, normalOut, contactOut) {
42
+ // 玩家水平点 → OBB 局部空间(只取 x/z;y 由竖直区间单独判定)
43
+ _local.set(px - obb.center.x, 0, pz - obb.center.z);
44
+ _invQ.copy(obb.quat).invert();
45
+ _local.applyQuaternion(_invQ);
46
+ const lx = _local.x;
47
+ const lz = _local.z;
48
+ // 2D 最近点(XZ 平面投影为 2D OBB,半尺寸 half.x / half.z)
49
+ const cx = Math.max(-obb.half.x, Math.min(obb.half.x, lx));
50
+ const cz = Math.max(-obb.half.z, Math.min(obb.half.z, lz));
51
+ const dx = lx - cx;
52
+ const dz = lz - cz;
53
+ const dH = Math.sqrt(dx * dx + dz * dz);
54
+ // 竖直区间重叠判定
55
+ const oyMin = obb.center.y - obb.half.y;
56
+ const oyMax = obb.center.y + obb.half.y;
57
+ const yOverlap = yBottom < oyMax && yTop > oyMin;
58
+ if (!yOverlap)
59
+ return 0;
60
+ if (dH > 1e-6) {
61
+ // 水平穿透(点在 OBB 水平投影之外或边缘):法线 = 局部 (dx,0,dz) 指向玩家,转回世界
62
+ const depth = radius - dH;
63
+ if (depth <= CAPSULE_DEPTH_EPS)
64
+ return 0;
65
+ _nLocal.set(dx, 0, dz).normalize();
66
+ normalOut.copy(_nLocal).applyQuaternion(obb.quat);
67
+ // 接触点:box 侧面,y 取玩家竖直区间与 box 重叠段中点
68
+ const cy = Math.max(oyMin, Math.min(oyMax, (yBottom + yTop) * 0.5));
69
+ _closestLocal.set(cx, cy - obb.center.y, cz).applyQuaternion(obb.quat).add(obb.center);
70
+ contactOut.copy(_closestLocal);
71
+ return depth;
72
+ }
73
+ // 水平在 OBB 内部(dH≈0):退化现场(玩家中心已陷进 box 水平投影)。
74
+ // ⚠️ 不能只做竖直(旧版会把陷进薄墙的角色竖直弹飞);应取**最小正穿透**的那一面托出,法线朝外。
75
+ const penX = obb.half.x - Math.abs(lx);
76
+ const penZ = obb.half.z - Math.abs(lz);
77
+ const penYTop = oyMax - yBottom; // 到顶面(+y)
78
+ const penYBot = yTop - oyMin; // 到底面(-y)
79
+ let minPen = Infinity;
80
+ let fx = 0, fy = 0, fz = 0;
81
+ if (penX > 0 && penX < minPen) {
82
+ minPen = penX;
83
+ fx = Math.sign(lx) || 1;
84
+ fy = 0;
85
+ fz = 0;
86
+ }
87
+ if (penZ > 0 && penZ < minPen) {
88
+ minPen = penZ;
89
+ fx = 0;
90
+ fy = 0;
91
+ fz = Math.sign(lz) || 1;
92
+ }
93
+ if (penYTop > 0 && penYTop < minPen) {
94
+ minPen = penYTop;
95
+ fx = 0;
96
+ fy = 1;
97
+ fz = 0;
98
+ }
99
+ if (penYBot > 0 && penYBot < minPen) {
100
+ minPen = penYBot;
101
+ fx = 0;
102
+ fy = -1;
103
+ fz = 0;
104
+ }
105
+ if (minPen === Infinity || minPen <= CAPSULE_DEPTH_EPS)
106
+ return 0;
107
+ _nLocal.set(fx, fy, fz).normalize();
108
+ normalOut.copy(_nLocal).applyQuaternion(obb.quat);
109
+ const cy = fy !== 0 ? (fy > 0 ? oyMax : oyMin) : (yBottom + yTop) * 0.5;
110
+ contactOut.set(px, cy, pz);
111
+ return minPen;
112
+ }
package/collisionOBB.ts CHANGED
@@ -1,108 +1,108 @@
1
- /**
2
- * capsuleVsOBB —— 竖直胶囊(第一人称角色)vs 有向包围盒(OBB)的精确穿透查询
3
- *
4
- * ⭐ 为什么是这套:玩家胶囊在 FPS 里是**竖直**的(start/end 的 x/z 相同,仅 y 不同),
5
- * 于是「胶囊 vs OBB」可精确化简为:
6
- * · 水平面(XZ)= 一个点(胶囊中心水平投影)到 OBB 的 2D 最近距离;
7
- * · 竖直(Y)= 胶囊竖直区间 [yBottom, yTop] 与 OBB 竖直区间是否重叠。
8
- * 这比「线段 vs box 通用最近点」更精确(box 是平面,法线恒定),
9
- * 也比「10 条射线模拟体积」物理正确且不抖(射线没有体积,贴墙必漏检)。
10
- *
11
- * ⭐ 一次调用得:穿透深度 depth(>0 即碰撞)+ 指向玩家的单位法线 normal + 碰撞体最近点 contact。
12
- * 位置修正 = 沿 normal 推出 depth(解析解,非贪心搜索);速度修正 = 滑墙投影 v -= (v·n)n。
13
- *
14
- * 零依赖:只用 three 的 Vector3 / Quaternion(标量运算,任何环境可跑)。
15
- */
16
-
17
- import { Vector3, Quaternion } from "three";
18
-
19
- /** 有向包围盒(世界空间):center + 旋转 quat + 半尺寸 half(已含 scale) */
20
- export interface OBB {
21
- center: Vector3;
22
- quat: Quaternion;
23
- half: Vector3;
24
- }
25
-
26
- /**
27
- * ⭐ 穿透噪声门(2026-09-27 探针实测):深度 ≤ 此值视为**未碰撞**。
28
- * 玩家停在「恰好贴合」位(如夹缝 = 胶囊直径)时,浮点残差会产生 ±1e-6 量级的
29
- * 微穿透 —— 不门掉的话,贴合面会以随机符号反复登记投票,回弹方向被钉死在
30
- * 某一面(实测:0.7m 夹缝里方向恒 +X 朝深墙)。真穿透都是毫米级以上,不受影响。
31
- */
32
- export const CAPSULE_DEPTH_EPS = 1e-4;
33
-
34
- // 复用的临时量(避免每帧 GC)
35
- const _local = new Vector3();
36
- const _invQ = new Quaternion();
37
- const _nLocal = new Vector3();
38
- const _closestLocal = new Vector3();
39
-
40
- /**
41
- * 竖直胶囊 vs 单个 OBB 的最近穿透。
42
- * @param px 胶囊中心水平 x
43
- * @param pz 胶囊中心水平 z
44
- * @param radius 胶囊半径
45
- * @param yBottom 胶囊竖直区间下界(= 脚底 = start.y - radius)
46
- * @param yTop 胶囊竖直区间上界(= 头顶球顶 = end.y + radius)
47
- * @param obb 世界空间 OBB
48
- * @param normalOut 输出:指向玩家的单位法线(世界空间,水平为主、地面/天花板为竖直)
49
- * @param contactOut 输出:碰撞体上最近点(世界空间)
50
- * @returns 穿透深度(>0 表示碰撞;≤0 表示不碰)
51
- */
52
- export function capsuleVsOBB(
53
- px: number, pz: number, radius: number,
54
- yBottom: number, yTop: number,
55
- obb: OBB, normalOut: Vector3, contactOut: Vector3
56
- ): number {
57
- // 玩家水平点 → OBB 局部空间(只取 x/z;y 由竖直区间单独判定)
58
- _local.set(px - obb.center.x, 0, pz - obb.center.z);
59
- _invQ.copy(obb.quat).invert();
60
- _local.applyQuaternion(_invQ);
61
- const lx = _local.x;
62
- const lz = _local.z;
63
-
64
- // 2D 最近点(XZ 平面投影为 2D OBB,半尺寸 half.x / half.z)
65
- const cx = Math.max(-obb.half.x, Math.min(obb.half.x, lx));
66
- const cz = Math.max(-obb.half.z, Math.min(obb.half.z, lz));
67
- const dx = lx - cx;
68
- const dz = lz - cz;
69
- const dH = Math.sqrt(dx * dx + dz * dz);
70
-
71
- // 竖直区间重叠判定
72
- const oyMin = obb.center.y - obb.half.y;
73
- const oyMax = obb.center.y + obb.half.y;
74
- const yOverlap = yBottom < oyMax && yTop > oyMin;
75
- if (!yOverlap) return 0;
76
-
77
- if (dH > 1e-6) {
78
- // 水平穿透(点在 OBB 水平投影之外或边缘):法线 = 局部 (dx,0,dz) 指向玩家,转回世界
79
- const depth = radius - dH;
80
- if (depth <= CAPSULE_DEPTH_EPS) return 0;
81
- _nLocal.set(dx, 0, dz).normalize();
82
- normalOut.copy(_nLocal).applyQuaternion(obb.quat);
83
- // 接触点:box 侧面,y 取玩家竖直区间与 box 重叠段中点
84
- const cy = Math.max(oyMin, Math.min(oyMax, (yBottom + yTop) * 0.5));
85
- _closestLocal.set(cx, cy - obb.center.y, cz).applyQuaternion(obb.quat).add(obb.center);
86
- contactOut.copy(_closestLocal);
87
- return depth;
88
- }
89
-
90
- // 水平在 OBB 内部(dH≈0):退化现场(玩家中心已陷进 box 水平投影)。
91
- // ⚠️ 不能只做竖直(旧版会把陷进薄墙的角色竖直弹飞);应取**最小正穿透**的那一面托出,法线朝外。
92
- const penX = obb.half.x - Math.abs(lx);
93
- const penZ = obb.half.z - Math.abs(lz);
94
- const penYTop = oyMax - yBottom; // 到顶面(+y)
95
- const penYBot = yTop - oyMin; // 到底面(-y)
96
- let minPen = Infinity;
97
- let fx = 0, fy = 0, fz = 0;
98
- if (penX > 0 && penX < minPen) { minPen = penX; fx = Math.sign(lx) || 1; fy = 0; fz = 0; }
99
- if (penZ > 0 && penZ < minPen) { minPen = penZ; fx = 0; fy = 0; fz = Math.sign(lz) || 1; }
100
- if (penYTop > 0 && penYTop < minPen) { minPen = penYTop; fx = 0; fy = 1; fz = 0; }
101
- if (penYBot > 0 && penYBot < minPen) { minPen = penYBot; fx = 0; fy = -1; fz = 0; }
102
- if (minPen === Infinity || minPen <= CAPSULE_DEPTH_EPS) return 0;
103
- _nLocal.set(fx, fy, fz).normalize();
104
- normalOut.copy(_nLocal).applyQuaternion(obb.quat);
105
- const cy = fy !== 0 ? (fy > 0 ? oyMax : oyMin) : (yBottom + yTop) * 0.5;
106
- contactOut.set(px, cy, pz);
107
- return minPen;
108
- }
1
+ /**
2
+ * capsuleVsOBB —— 竖直胶囊(第一人称角色)vs 有向包围盒(OBB)的精确穿透查询
3
+ *
4
+ * ⭐ 为什么是这套:玩家胶囊在 FPS 里是**竖直**的(start/end 的 x/z 相同,仅 y 不同),
5
+ * 于是「胶囊 vs OBB」可精确化简为:
6
+ * · 水平面(XZ)= 一个点(胶囊中心水平投影)到 OBB 的 2D 最近距离;
7
+ * · 竖直(Y)= 胶囊竖直区间 [yBottom, yTop] 与 OBB 竖直区间是否重叠。
8
+ * 这比「线段 vs box 通用最近点」更精确(box 是平面,法线恒定),
9
+ * 也比「10 条射线模拟体积」物理正确且不抖(射线没有体积,贴墙必漏检)。
10
+ *
11
+ * ⭐ 一次调用得:穿透深度 depth(>0 即碰撞)+ 指向玩家的单位法线 normal + 碰撞体最近点 contact。
12
+ * 位置修正 = 沿 normal 推出 depth(解析解,非贪心搜索);速度修正 = 滑墙投影 v -= (v·n)n。
13
+ *
14
+ * 零依赖:只用 three 的 Vector3 / Quaternion(标量运算,任何环境可跑)。
15
+ */
16
+
17
+ import { Vector3, Quaternion } from "three";
18
+
19
+ /** 有向包围盒(世界空间):center + 旋转 quat + 半尺寸 half(已含 scale) */
20
+ export interface OBB {
21
+ center: Vector3;
22
+ quat: Quaternion;
23
+ half: Vector3;
24
+ }
25
+
26
+ /**
27
+ * ⭐ 穿透噪声门(2026-09-27 探针实测):深度 ≤ 此值视为**未碰撞**。
28
+ * 玩家停在「恰好贴合」位(如夹缝 = 胶囊直径)时,浮点残差会产生 ±1e-6 量级的
29
+ * 微穿透 —— 不门掉的话,贴合面会以随机符号反复登记投票,回弹方向被钉死在
30
+ * 某一面(实测:0.7m 夹缝里方向恒 +X 朝深墙)。真穿透都是毫米级以上,不受影响。
31
+ */
32
+ export const CAPSULE_DEPTH_EPS = 1e-4;
33
+
34
+ // 复用的临时量(避免每帧 GC)
35
+ const _local = new Vector3();
36
+ const _invQ = new Quaternion();
37
+ const _nLocal = new Vector3();
38
+ const _closestLocal = new Vector3();
39
+
40
+ /**
41
+ * 竖直胶囊 vs 单个 OBB 的最近穿透。
42
+ * @param px 胶囊中心水平 x
43
+ * @param pz 胶囊中心水平 z
44
+ * @param radius 胶囊半径
45
+ * @param yBottom 胶囊竖直区间下界(= 脚底 = start.y - radius)
46
+ * @param yTop 胶囊竖直区间上界(= 头顶球顶 = end.y + radius)
47
+ * @param obb 世界空间 OBB
48
+ * @param normalOut 输出:指向玩家的单位法线(世界空间,水平为主、地面/天花板为竖直)
49
+ * @param contactOut 输出:碰撞体上最近点(世界空间)
50
+ * @returns 穿透深度(>0 表示碰撞;≤0 表示不碰)
51
+ */
52
+ export function capsuleVsOBB(
53
+ px: number, pz: number, radius: number,
54
+ yBottom: number, yTop: number,
55
+ obb: OBB, normalOut: Vector3, contactOut: Vector3
56
+ ): number {
57
+ // 玩家水平点 → OBB 局部空间(只取 x/z;y 由竖直区间单独判定)
58
+ _local.set(px - obb.center.x, 0, pz - obb.center.z);
59
+ _invQ.copy(obb.quat).invert();
60
+ _local.applyQuaternion(_invQ);
61
+ const lx = _local.x;
62
+ const lz = _local.z;
63
+
64
+ // 2D 最近点(XZ 平面投影为 2D OBB,半尺寸 half.x / half.z)
65
+ const cx = Math.max(-obb.half.x, Math.min(obb.half.x, lx));
66
+ const cz = Math.max(-obb.half.z, Math.min(obb.half.z, lz));
67
+ const dx = lx - cx;
68
+ const dz = lz - cz;
69
+ const dH = Math.sqrt(dx * dx + dz * dz);
70
+
71
+ // 竖直区间重叠判定
72
+ const oyMin = obb.center.y - obb.half.y;
73
+ const oyMax = obb.center.y + obb.half.y;
74
+ const yOverlap = yBottom < oyMax && yTop > oyMin;
75
+ if (!yOverlap) return 0;
76
+
77
+ if (dH > 1e-6) {
78
+ // 水平穿透(点在 OBB 水平投影之外或边缘):法线 = 局部 (dx,0,dz) 指向玩家,转回世界
79
+ const depth = radius - dH;
80
+ if (depth <= CAPSULE_DEPTH_EPS) return 0;
81
+ _nLocal.set(dx, 0, dz).normalize();
82
+ normalOut.copy(_nLocal).applyQuaternion(obb.quat);
83
+ // 接触点:box 侧面,y 取玩家竖直区间与 box 重叠段中点
84
+ const cy = Math.max(oyMin, Math.min(oyMax, (yBottom + yTop) * 0.5));
85
+ _closestLocal.set(cx, cy - obb.center.y, cz).applyQuaternion(obb.quat).add(obb.center);
86
+ contactOut.copy(_closestLocal);
87
+ return depth;
88
+ }
89
+
90
+ // 水平在 OBB 内部(dH≈0):退化现场(玩家中心已陷进 box 水平投影)。
91
+ // ⚠️ 不能只做竖直(旧版会把陷进薄墙的角色竖直弹飞);应取**最小正穿透**的那一面托出,法线朝外。
92
+ const penX = obb.half.x - Math.abs(lx);
93
+ const penZ = obb.half.z - Math.abs(lz);
94
+ const penYTop = oyMax - yBottom; // 到顶面(+y)
95
+ const penYBot = yTop - oyMin; // 到底面(-y)
96
+ let minPen = Infinity;
97
+ let fx = 0, fy = 0, fz = 0;
98
+ if (penX > 0 && penX < minPen) { minPen = penX; fx = Math.sign(lx) || 1; fy = 0; fz = 0; }
99
+ if (penZ > 0 && penZ < minPen) { minPen = penZ; fx = 0; fy = 0; fz = Math.sign(lz) || 1; }
100
+ if (penYTop > 0 && penYTop < minPen) { minPen = penYTop; fx = 0; fy = 1; fz = 0; }
101
+ if (penYBot > 0 && penYBot < minPen) { minPen = penYBot; fx = 0; fy = -1; fz = 0; }
102
+ if (minPen === Infinity || minPen <= CAPSULE_DEPTH_EPS) return 0;
103
+ _nLocal.set(fx, fy, fz).normalize();
104
+ normalOut.copy(_nLocal).applyQuaternion(obb.quat);
105
+ const cy = fy !== 0 ? (fy > 0 ? oyMax : oyMin) : (yBottom + yTop) * 0.5;
106
+ contactOut.set(px, cy, pz);
107
+ return minPen;
108
+ }
package/declare.d.ts CHANGED
@@ -1,25 +1,25 @@
1
- // three-base 独立编译 / npm 发包的环境声明。
2
- // three-base 脱离演示站单独跑 tsc 时没有 vite/client 提供静态资源模块声明,
3
- // 各组件 import 的 .png / .jpg / .glb 等在此声明,避免 TS2307。
4
- // (演示站根 tsconfig 走 vite/client,本文件与之并存无冲突,二者 wildcard 声明可合并。)
5
- declare module "*.png";
6
- declare module "*.jpg";
7
- declare module "*.jpeg";
8
- declare module "*.webp";
9
- declare module "*.svg";
10
- declare module "*.gif";
11
- declare module "*.glb";
12
- declare module "*.gltf";
13
- declare module "*.hdr";
14
- declare module "*.obj";
15
- declare module "*.stl";
16
- declare module "*.usdz";
17
- declare module "*.zip";
18
- declare module "*.mp3";
19
- declare module "*.mp4";
20
- declare module "*.woff";
21
- declare module "*.woff2";
22
- declare module "*.ttf";
23
-
24
- declare interface Window {
25
- }
1
+ // three-base 独立编译 / npm 发包的环境声明。
2
+ // three-base 脱离演示站单独跑 tsc 时没有 vite/client 提供静态资源模块声明,
3
+ // 各组件 import 的 .png / .jpg / .glb 等在此声明,避免 TS2307。
4
+ // (演示站根 tsconfig 走 vite/client,本文件与之并存无冲突,二者 wildcard 声明可合并。)
5
+ declare module "*.png";
6
+ declare module "*.jpg";
7
+ declare module "*.jpeg";
8
+ declare module "*.webp";
9
+ declare module "*.svg";
10
+ declare module "*.gif";
11
+ declare module "*.glb";
12
+ declare module "*.gltf";
13
+ declare module "*.hdr";
14
+ declare module "*.obj";
15
+ declare module "*.stl";
16
+ declare module "*.usdz";
17
+ declare module "*.zip";
18
+ declare module "*.mp3";
19
+ declare module "*.mp4";
20
+ declare module "*.woff";
21
+ declare module "*.woff2";
22
+ declare module "*.ttf";
23
+
24
+ declare interface Window {
25
+ }
package/index.d.ts CHANGED
@@ -1 +1 @@
1
- export { default } from "./ThreeBase";
1
+ export { default } from "./ThreeBase";
package/index.js CHANGED
@@ -1 +1 @@
1
- export { default } from "./ThreeBase";
1
+ export { default } from "./ThreeBase";
@@ -1,57 +1,57 @@
1
- import { Group, InstancedMesh } from "three";
2
- import InstancedChild from "./InstancedChild";
3
- import { InstancedTemplate } from "./InstancedTemplate";
4
- /**
5
- * 内部类:封装一个 batch 的真实 InstancedMesh(多 submesh 时每个 submesh 一个,共享同一组实例序号)。
6
- * - 按 batchKey 分组(相同 geometry+material 或相同 instanceUrl+animation 为一类);
7
- * - 增量同步:仅 needUpdate=true 的实例才重写 matrix/color,写完后立即置 false;
8
- * - 列表变化(增删/重排)时全量 compact 重写并重建索引;
9
- * - 含骨骼动画时:用共享姿态 AnimationMixer 驱动 skeleton,每帧烘焙到共享几何(LBS);
10
- * - 含非骨骼节点动画时:同样用共享姿态 AnimationMixer 驱动节点变换,每帧把"节点相对根的世界变换"
11
- * 烘焙进几何(节点变换动画的实例化方案)。
12
- */
13
- export default class InstancedBatch {
14
- key: string;
15
- /** 渲染组:持有本 batch 的 InstancedMesh,由 InstancedGroup add 进 scene */
16
- group: Group;
17
- template?: InstancedTemplate;
18
- ready: boolean;
19
- private _children;
20
- private _meshes;
21
- private _capacity;
22
- private _step;
23
- private _loading?;
24
- private _mixer?;
25
- private _clipName?;
26
- /** 当前正在播放的动画剪辑名(运行时可由 child.playClip 切换) */
27
- private _currentClip?;
28
- /** 首例实例是否声明碰撞(构造时快照,buildMeshes 用它给 InstancedMesh 打标记) */
29
- private _sampleFpsCollision;
30
- /** 当前正在播放的 AnimationAction(切换时先 stop 旧的) */
31
- private _currentAction?;
32
- /** 非骨骼动画:需每帧烘焙节点变换的几何列表(与 _meshes 顺序对齐) */
33
- private _nodeBake;
34
- constructor(key: string, sample: InstancedChild, capacity?: number, step?: number);
35
- /** 模板就绪后,为每个 submesh 建一个 InstancedMesh,并启动动画(若有) */
36
- private buildMeshes;
37
- /** 每帧同步:children 为按 batchKey 收集的 InstancedChild 列表 */
38
- sync(children: InstancedChild[], delta: number): void;
39
- /** 容量不足时按 step 扩容(只扩不缩,避免频繁 realloc) */
40
- private ensureCapacity;
41
- /** 全量重写所有实例(列表变化时调用) */
42
- private compactWrite;
43
- /** 根据当前首批实例的 fpsCollision 标记,把真实 InstancedMesh 的 userData.fpsCollision 同步过去,
44
- * 并在开启时通知所有 FPScontrol 重建碰撞列表。碰撞以整个 batch 为单位开关。 */
45
- private _applyCollisionFlag;
46
- /** 把单个实例的 matrix + color 写入所有 submesh 的对应槽位 */
47
- private writeInstance;
48
- /** 事件路由:给定 InstancedMesh 与 instanceId,返回对应 InstancedChild */
49
- resolveInstance(mesh: InstancedMesh, instanceId: number): InstancedChild | null;
50
- /** 该 batch 是否有任一 child 注册了指定类型监听(供 ThreeMouse 决定是否可拾取) */
51
- hasListener(types: string[]): boolean;
52
- /** 该 batch 是否有任一 child 设置了鼠标手势(cursor),供 InstancedGroup 决定是否收集 */
53
- hasCursor(): boolean;
54
- /** 拾取用 InstancedMesh 列表 */
55
- get pickables(): InstancedMesh[];
56
- dispose(): void;
57
- }
1
+ import { Group, InstancedMesh } from "three";
2
+ import InstancedChild from "./InstancedChild";
3
+ import { InstancedTemplate } from "./InstancedTemplate";
4
+ /**
5
+ * 内部类:封装一个 batch 的真实 InstancedMesh(多 submesh 时每个 submesh 一个,共享同一组实例序号)。
6
+ * - 按 batchKey 分组(相同 geometry+material 或相同 instanceUrl+animation 为一类);
7
+ * - 增量同步:仅 needUpdate=true 的实例才重写 matrix/color,写完后立即置 false;
8
+ * - 列表变化(增删/重排)时全量 compact 重写并重建索引;
9
+ * - 含骨骼动画时:用共享姿态 AnimationMixer 驱动 skeleton,每帧烘焙到共享几何(LBS);
10
+ * - 含非骨骼节点动画时:同样用共享姿态 AnimationMixer 驱动节点变换,每帧把"节点相对根的世界变换"
11
+ * 烘焙进几何(节点变换动画的实例化方案)。
12
+ */
13
+ export default class InstancedBatch {
14
+ key: string;
15
+ /** 渲染组:持有本 batch 的 InstancedMesh,由 InstancedGroup add 进 scene */
16
+ group: Group;
17
+ template?: InstancedTemplate;
18
+ ready: boolean;
19
+ private _children;
20
+ private _meshes;
21
+ private _capacity;
22
+ private _step;
23
+ private _loading?;
24
+ private _mixer?;
25
+ private _clipName?;
26
+ /** 当前正在播放的动画剪辑名(运行时可由 child.playClip 切换) */
27
+ private _currentClip?;
28
+ /** 首例实例是否声明碰撞(构造时快照,buildMeshes 用它给 InstancedMesh 打标记) */
29
+ private _sampleFpsCollision;
30
+ /** 当前正在播放的 AnimationAction(切换时先 stop 旧的) */
31
+ private _currentAction?;
32
+ /** 非骨骼动画:需每帧烘焙节点变换的几何列表(与 _meshes 顺序对齐) */
33
+ private _nodeBake;
34
+ constructor(key: string, sample: InstancedChild, capacity?: number, step?: number);
35
+ /** 模板就绪后,为每个 submesh 建一个 InstancedMesh,并启动动画(若有) */
36
+ private buildMeshes;
37
+ /** 每帧同步:children 为按 batchKey 收集的 InstancedChild 列表 */
38
+ sync(children: InstancedChild[], delta: number): void;
39
+ /** 容量不足时按 step 扩容(只扩不缩,避免频繁 realloc) */
40
+ private ensureCapacity;
41
+ /** 全量重写所有实例(列表变化时调用) */
42
+ private compactWrite;
43
+ /** 根据当前首批实例的 fpsCollision 标记,把真实 InstancedMesh 的 userData.fpsCollision 同步过去,
44
+ * 并在开启时通知所有 FPScontrol 重建碰撞列表。碰撞以整个 batch 为单位开关。 */
45
+ private _applyCollisionFlag;
46
+ /** 把单个实例的 matrix + color 写入所有 submesh 的对应槽位 */
47
+ private writeInstance;
48
+ /** 事件路由:给定 InstancedMesh 与 instanceId,返回对应 InstancedChild */
49
+ resolveInstance(mesh: InstancedMesh, instanceId: number): InstancedChild | null;
50
+ /** 该 batch 是否有任一 child 注册了指定类型监听(供 ThreeMouse 决定是否可拾取) */
51
+ hasListener(types: string[]): boolean;
52
+ /** 该 batch 是否有任一 child 设置了鼠标手势(cursor),供 InstancedGroup 决定是否收集 */
53
+ hasCursor(): boolean;
54
+ /** 拾取用 InstancedMesh 列表 */
55
+ get pickables(): InstancedMesh[];
56
+ dispose(): void;
57
+ }