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
@@ -1,43 +1,43 @@
1
- import { Object3D } from "three";
2
- import InstancedChild from "./InstancedChild";
3
- import InstancedBatch from "./InstancedBatch";
4
- /**
5
- * 固定在 ThreeBase.scene 里的分组器。每帧收集所有 InstancedChild,按 batchKey(glb+当前生效动画)分组,
6
- * 为每个 key 创建/复用 InstancedBatch,把实例的世界矩阵 / 颜色同步进真实 InstancedMesh。
7
- * batch 常驻(空桶不销毁),切换动画 = 实例在「glb+旧动画」「glb+新动画」两个常驻 batch 间迁移。
8
- *
9
- * 同时也是事件路由中枢:ThreeMouse 命中 InstancedMesh 后,通过本类把 (mesh, instanceId)
10
- * 还原成对应的 InstancedChild,使逻辑实例成为透明事件接收端。
11
- */
12
- export default class InstancedGroup extends Object3D {
13
- /** batchKey -> InstancedBatch */
14
- batches: Map<string, InstancedBatch>;
15
- private _clock;
16
- /**
17
- * 本组的归属 tag(可选)。多 InstancedGroup 共存时用于隔离:
18
- * - 声明了 owner 的组:**只**收集 `getOwner() === owner` 的实例(未声明归属的实例一律不收);
19
- * - 未声明 owner 的组(如 ThreeBase 的默认组):只收**未声明归属**的实例,跳过已归属他组的实例。
20
- * 这样主编辑器(默认组)与预览弹窗(owner="preview")各自只画自己的实例,互不污染。
21
- */
22
- readonly owner?: string;
23
- constructor(owner?: string);
24
- /** 本组是否该收集该实例:按 owner 归属隔离(详见 owner 字段注释) */
25
- private _accepts;
26
- /** 每帧由 ThreeBase.render 在 scene.updateMatrixWorld 之后调用 */
27
- update(): void;
28
- /** 事件路由:命中 InstancedMesh 时返回对应 InstancedChild,否则 null */
29
- resolveInstance(mesh: Object3D, instanceId: number | undefined): InstancedChild | null;
30
- /** 收集可拾取的 InstancedMesh(已就绪 batch,且注册了监听或设置了 cursor 的),供 ThreeMouse 候选 */
31
- collectPickable(out: Object3D[]): void;
32
- /**
33
- * 释放本组的全部 batch(实例缓冲 + 从组内摘除 mesh)。
34
- *
35
- * 用途:自建 InstancedGroup 的场景(如预览弹窗的独立轻量渲染器)在销毁时调用,
36
- * 避免 InstancedMesh 的实例缓冲随组对象一起被丢弃却未释放。
37
- *
38
- * 注:batch 的 geometry/material **不会**被释放(InstancedBatch.dispose 刻意跳过)——
39
- * 它们来自 `InstancedChild` 的 static geometry/material 或模板缓存,是跨实例共享资源。
40
- * ⚠️ 默认的 ThreeBase 组**不要**调用本方法:它随应用生命周期常驻,batch 复用是设计意图。
41
- */
42
- dispose(): void;
43
- }
1
+ import { Object3D } from "three";
2
+ import InstancedChild from "./InstancedChild";
3
+ import InstancedBatch from "./InstancedBatch";
4
+ /**
5
+ * 固定在 ThreeBase.scene 里的分组器。每帧收集所有 InstancedChild,按 batchKey(glb+当前生效动画)分组,
6
+ * 为每个 key 创建/复用 InstancedBatch,把实例的世界矩阵 / 颜色同步进真实 InstancedMesh。
7
+ * batch 常驻(空桶不销毁),切换动画 = 实例在「glb+旧动画」「glb+新动画」两个常驻 batch 间迁移。
8
+ *
9
+ * 同时也是事件路由中枢:ThreeMouse 命中 InstancedMesh 后,通过本类把 (mesh, instanceId)
10
+ * 还原成对应的 InstancedChild,使逻辑实例成为透明事件接收端。
11
+ */
12
+ export default class InstancedGroup extends Object3D {
13
+ /** batchKey -> InstancedBatch */
14
+ batches: Map<string, InstancedBatch>;
15
+ private _clock;
16
+ /**
17
+ * 本组的归属 tag(可选)。多 InstancedGroup 共存时用于隔离:
18
+ * - 声明了 owner 的组:**只**收集 `getOwner() === owner` 的实例(未声明归属的实例一律不收);
19
+ * - 未声明 owner 的组(如 ThreeBase 的默认组):只收**未声明归属**的实例,跳过已归属他组的实例。
20
+ * 这样主编辑器(默认组)与预览弹窗(owner="preview")各自只画自己的实例,互不污染。
21
+ */
22
+ readonly owner?: string;
23
+ constructor(owner?: string);
24
+ /** 本组是否该收集该实例:按 owner 归属隔离(详见 owner 字段注释) */
25
+ private _accepts;
26
+ /** 每帧由 ThreeBase.render 在 scene.updateMatrixWorld 之后调用 */
27
+ update(): void;
28
+ /** 事件路由:命中 InstancedMesh 时返回对应 InstancedChild,否则 null */
29
+ resolveInstance(mesh: Object3D, instanceId: number | undefined): InstancedChild | null;
30
+ /** 收集可拾取的 InstancedMesh(已就绪 batch,且注册了监听或设置了 cursor 的),供 ThreeMouse 候选 */
31
+ collectPickable(out: Object3D[]): void;
32
+ /**
33
+ * 释放本组的全部 batch(实例缓冲 + 从组内摘除 mesh)。
34
+ *
35
+ * 用途:自建 InstancedGroup 的场景(如预览弹窗的独立轻量渲染器)在销毁时调用,
36
+ * 避免 InstancedMesh 的实例缓冲随组对象一起被丢弃却未释放。
37
+ *
38
+ * 注:batch 的 geometry/material **不会**被释放(InstancedBatch.dispose 刻意跳过)——
39
+ * 它们来自 `InstancedChild` 的 static geometry/material 或模板缓存,是跨实例共享资源。
40
+ * ⚠️ 默认的 ThreeBase 组**不要**调用本方法:它随应用生命周期常驻,batch 复用是设计意图。
41
+ */
42
+ dispose(): void;
43
+ }
@@ -1,126 +1,126 @@
1
- import { Clock, Object3D } from "three";
2
- import { instancedChildRegistry, instancedChildOwner } from "./InstancedChild";
3
- import InstancedBatch from "./InstancedBatch";
4
- const PICK_EVENT_TYPES = [
5
- "mouseenter",
6
- "mouseleave",
7
- "mousemove",
8
- "click",
9
- "leftclick",
10
- "rightclick",
11
- "dbclick",
12
- "mousedown",
13
- "mouseup",
14
- ];
15
- /**
16
- * 固定在 ThreeBase.scene 里的分组器。每帧收集所有 InstancedChild,按 batchKey(glb+当前生效动画)分组,
17
- * 为每个 key 创建/复用 InstancedBatch,把实例的世界矩阵 / 颜色同步进真实 InstancedMesh。
18
- * batch 常驻(空桶不销毁),切换动画 = 实例在「glb+旧动画」「glb+新动画」两个常驻 batch 间迁移。
19
- *
20
- * 同时也是事件路由中枢:ThreeMouse 命中 InstancedMesh 后,通过本类把 (mesh, instanceId)
21
- * 还原成对应的 InstancedChild,使逻辑实例成为透明事件接收端。
22
- */
23
- export default class InstancedGroup extends Object3D {
24
- /** batchKey -> InstancedBatch */
25
- batches = new Map();
26
- _clock = new Clock();
27
- /**
28
- * 本组的归属 tag(可选)。多 InstancedGroup 共存时用于隔离:
29
- * - 声明了 owner 的组:**只**收集 `getOwner() === owner` 的实例(未声明归属的实例一律不收);
30
- * - 未声明 owner 的组(如 ThreeBase 的默认组):只收**未声明归属**的实例,跳过已归属他组的实例。
31
- * 这样主编辑器(默认组)与预览弹窗(owner="preview")各自只画自己的实例,互不污染。
32
- */
33
- owner;
34
- constructor(owner) {
35
- super();
36
- this.owner = owner;
37
- }
38
- /** 本组是否该收集该实例:按 owner 归属隔离(详见 owner 字段注释) */
39
- _accepts(child) {
40
- const childOwner = instancedChildOwner.get(child);
41
- if (this.owner === undefined) {
42
- // 无归属的组(ThreeBase 默认组):只收未声明归属的实例,跳过已归属他组的
43
- return childOwner === undefined;
44
- }
45
- // 有归属的组:只收 owner 完全一致的实例
46
- return childOwner === this.owner;
47
- }
48
- /** 每帧由 ThreeBase.render 在 scene.updateMatrixWorld 之后调用 */
49
- update() {
50
- const delta = this._clock.getDelta();
51
- // 1. 按 batchKey 收集所有活着的 InstancedChild(按 owner 归属过滤,避免多组互相污染)
52
- const groups = new Map();
53
- for (const child of instancedChildRegistry) {
54
- if (!this._accepts(child))
55
- continue;
56
- // 强制刷新世界矩阵(实例可能位于任意层级,不依赖 scene 遍历顺序)
57
- child.updateWorldMatrix(true, false);
58
- child.markDirtyIfWorldChanged();
59
- const key = child.getBatchKey();
60
- let arr = groups.get(key);
61
- if (!arr) {
62
- arr = [];
63
- groups.set(key, arr);
64
- }
65
- arr.push(child);
66
- }
67
- // 2. 创建 / 更新每个有实例的 batch(按 glb+当前动画分桶,每个动画一个常驻 batch)
68
- for (const [key, children] of groups) {
69
- let batch = this.batches.get(key);
70
- if (!batch) {
71
- batch = new InstancedBatch(key, children[0]);
72
- this.batches.set(key, batch);
73
- this.add(batch.group);
74
- }
75
- batch.sync(children, delta);
76
- }
77
- // 3. 持久化:实例已迁移走的空 batch 仍需 sync([]) 把 count 归零,避免残留上一帧实例;
78
- // 但【不销毁】,使其常驻可复用 —— 切换动作时实例在常驻 batch 间迁移,无需频繁创建/销毁 InstancedBatch。
79
- for (const [key, batch] of this.batches) {
80
- if (!groups.has(key)) {
81
- batch.sync([], delta);
82
- }
83
- }
84
- }
85
- /** 事件路由:命中 InstancedMesh 时返回对应 InstancedChild,否则 null */
86
- resolveInstance(mesh, instanceId) {
87
- if (instanceId === undefined) {
88
- return null;
89
- }
90
- const key = mesh.userData?.__batchKey;
91
- if (!key) {
92
- return null;
93
- }
94
- const batch = this.batches.get(key);
95
- if (!batch) {
96
- return null;
97
- }
98
- return batch.resolveInstance(mesh, instanceId);
99
- }
100
- /** 收集可拾取的 InstancedMesh(已就绪 batch,且注册了监听或设置了 cursor 的),供 ThreeMouse 候选 */
101
- collectPickable(out) {
102
- for (const batch of this.batches.values()) {
103
- if (batch.ready && (batch.hasListener(PICK_EVENT_TYPES) || batch.hasCursor())) {
104
- for (const im of batch.pickables) {
105
- out.push(im);
106
- }
107
- }
108
- }
109
- }
110
- /**
111
- * 释放本组的全部 batch(实例缓冲 + 从组内摘除 mesh)。
112
- *
113
- * 用途:自建 InstancedGroup 的场景(如预览弹窗的独立轻量渲染器)在销毁时调用,
114
- * 避免 InstancedMesh 的实例缓冲随组对象一起被丢弃却未释放。
115
- *
116
- * 注:batch 的 geometry/material **不会**被释放(InstancedBatch.dispose 刻意跳过)——
117
- * 它们来自 `InstancedChild` 的 static geometry/material 或模板缓存,是跨实例共享资源。
118
- * ⚠️ 默认的 ThreeBase 组**不要**调用本方法:它随应用生命周期常驻,batch 复用是设计意图。
119
- */
120
- dispose() {
121
- for (const batch of this.batches.values()) {
122
- batch.dispose();
123
- }
124
- this.batches.clear();
125
- }
126
- }
1
+ import { Clock, Object3D } from "three";
2
+ import { instancedChildRegistry, instancedChildOwner } from "./InstancedChild";
3
+ import InstancedBatch from "./InstancedBatch";
4
+ const PICK_EVENT_TYPES = [
5
+ "mouseenter",
6
+ "mouseleave",
7
+ "mousemove",
8
+ "click",
9
+ "leftclick",
10
+ "rightclick",
11
+ "dbclick",
12
+ "mousedown",
13
+ "mouseup",
14
+ ];
15
+ /**
16
+ * 固定在 ThreeBase.scene 里的分组器。每帧收集所有 InstancedChild,按 batchKey(glb+当前生效动画)分组,
17
+ * 为每个 key 创建/复用 InstancedBatch,把实例的世界矩阵 / 颜色同步进真实 InstancedMesh。
18
+ * batch 常驻(空桶不销毁),切换动画 = 实例在「glb+旧动画」「glb+新动画」两个常驻 batch 间迁移。
19
+ *
20
+ * 同时也是事件路由中枢:ThreeMouse 命中 InstancedMesh 后,通过本类把 (mesh, instanceId)
21
+ * 还原成对应的 InstancedChild,使逻辑实例成为透明事件接收端。
22
+ */
23
+ export default class InstancedGroup extends Object3D {
24
+ /** batchKey -> InstancedBatch */
25
+ batches = new Map();
26
+ _clock = new Clock();
27
+ /**
28
+ * 本组的归属 tag(可选)。多 InstancedGroup 共存时用于隔离:
29
+ * - 声明了 owner 的组:**只**收集 `getOwner() === owner` 的实例(未声明归属的实例一律不收);
30
+ * - 未声明 owner 的组(如 ThreeBase 的默认组):只收**未声明归属**的实例,跳过已归属他组的实例。
31
+ * 这样主编辑器(默认组)与预览弹窗(owner="preview")各自只画自己的实例,互不污染。
32
+ */
33
+ owner;
34
+ constructor(owner) {
35
+ super();
36
+ this.owner = owner;
37
+ }
38
+ /** 本组是否该收集该实例:按 owner 归属隔离(详见 owner 字段注释) */
39
+ _accepts(child) {
40
+ const childOwner = instancedChildOwner.get(child);
41
+ if (this.owner === undefined) {
42
+ // 无归属的组(ThreeBase 默认组):只收未声明归属的实例,跳过已归属他组的
43
+ return childOwner === undefined;
44
+ }
45
+ // 有归属的组:只收 owner 完全一致的实例
46
+ return childOwner === this.owner;
47
+ }
48
+ /** 每帧由 ThreeBase.render 在 scene.updateMatrixWorld 之后调用 */
49
+ update() {
50
+ const delta = this._clock.getDelta();
51
+ // 1. 按 batchKey 收集所有活着的 InstancedChild(按 owner 归属过滤,避免多组互相污染)
52
+ const groups = new Map();
53
+ for (const child of instancedChildRegistry) {
54
+ if (!this._accepts(child))
55
+ continue;
56
+ // 强制刷新世界矩阵(实例可能位于任意层级,不依赖 scene 遍历顺序)
57
+ child.updateWorldMatrix(true, false);
58
+ child.markDirtyIfWorldChanged();
59
+ const key = child.getBatchKey();
60
+ let arr = groups.get(key);
61
+ if (!arr) {
62
+ arr = [];
63
+ groups.set(key, arr);
64
+ }
65
+ arr.push(child);
66
+ }
67
+ // 2. 创建 / 更新每个有实例的 batch(按 glb+当前动画分桶,每个动画一个常驻 batch)
68
+ for (const [key, children] of groups) {
69
+ let batch = this.batches.get(key);
70
+ if (!batch) {
71
+ batch = new InstancedBatch(key, children[0]);
72
+ this.batches.set(key, batch);
73
+ this.add(batch.group);
74
+ }
75
+ batch.sync(children, delta);
76
+ }
77
+ // 3. 持久化:实例已迁移走的空 batch 仍需 sync([]) 把 count 归零,避免残留上一帧实例;
78
+ // 但【不销毁】,使其常驻可复用 —— 切换动作时实例在常驻 batch 间迁移,无需频繁创建/销毁 InstancedBatch。
79
+ for (const [key, batch] of this.batches) {
80
+ if (!groups.has(key)) {
81
+ batch.sync([], delta);
82
+ }
83
+ }
84
+ }
85
+ /** 事件路由:命中 InstancedMesh 时返回对应 InstancedChild,否则 null */
86
+ resolveInstance(mesh, instanceId) {
87
+ if (instanceId === undefined) {
88
+ return null;
89
+ }
90
+ const key = mesh.userData?.__batchKey;
91
+ if (!key) {
92
+ return null;
93
+ }
94
+ const batch = this.batches.get(key);
95
+ if (!batch) {
96
+ return null;
97
+ }
98
+ return batch.resolveInstance(mesh, instanceId);
99
+ }
100
+ /** 收集可拾取的 InstancedMesh(已就绪 batch,且注册了监听或设置了 cursor 的),供 ThreeMouse 候选 */
101
+ collectPickable(out) {
102
+ for (const batch of this.batches.values()) {
103
+ if (batch.ready && (batch.hasListener(PICK_EVENT_TYPES) || batch.hasCursor())) {
104
+ for (const im of batch.pickables) {
105
+ out.push(im);
106
+ }
107
+ }
108
+ }
109
+ }
110
+ /**
111
+ * 释放本组的全部 batch(实例缓冲 + 从组内摘除 mesh)。
112
+ *
113
+ * 用途:自建 InstancedGroup 的场景(如预览弹窗的独立轻量渲染器)在销毁时调用,
114
+ * 避免 InstancedMesh 的实例缓冲随组对象一起被丢弃却未释放。
115
+ *
116
+ * 注:batch 的 geometry/material **不会**被释放(InstancedBatch.dispose 刻意跳过)——
117
+ * 它们来自 `InstancedChild` 的 static geometry/material 或模板缓存,是跨实例共享资源。
118
+ * ⚠️ 默认的 ThreeBase 组**不要**调用本方法:它随应用生命周期常驻,batch 复用是设计意图。
119
+ */
120
+ dispose() {
121
+ for (const batch of this.batches.values()) {
122
+ batch.dispose();
123
+ }
124
+ this.batches.clear();
125
+ }
126
+ }
@@ -1,137 +1,137 @@
1
- import { Clock, Object3D } from "three";
2
- import InstancedChild, { instancedChildRegistry, instancedChildOwner } from "./InstancedChild";
3
- import InstancedBatch from "./InstancedBatch";
4
-
5
- const PICK_EVENT_TYPES = [
6
- "mouseenter",
7
- "mouseleave",
8
- "mousemove",
9
- "click",
10
- "leftclick",
11
- "rightclick",
12
- "dbclick",
13
- "mousedown",
14
- "mouseup",
15
- ];
16
-
17
- /**
18
- * 固定在 ThreeBase.scene 里的分组器。每帧收集所有 InstancedChild,按 batchKey(glb+当前生效动画)分组,
19
- * 为每个 key 创建/复用 InstancedBatch,把实例的世界矩阵 / 颜色同步进真实 InstancedMesh。
20
- * batch 常驻(空桶不销毁),切换动画 = 实例在「glb+旧动画」「glb+新动画」两个常驻 batch 间迁移。
21
- *
22
- * 同时也是事件路由中枢:ThreeMouse 命中 InstancedMesh 后,通过本类把 (mesh, instanceId)
23
- * 还原成对应的 InstancedChild,使逻辑实例成为透明事件接收端。
24
- */
25
- export default class InstancedGroup extends Object3D {
26
- /** batchKey -> InstancedBatch */
27
- batches = new Map<string, InstancedBatch>();
28
- private _clock = new Clock();
29
-
30
- /**
31
- * 本组的归属 tag(可选)。多 InstancedGroup 共存时用于隔离:
32
- * - 声明了 owner 的组:**只**收集 `getOwner() === owner` 的实例(未声明归属的实例一律不收);
33
- * - 未声明 owner 的组(如 ThreeBase 的默认组):只收**未声明归属**的实例,跳过已归属他组的实例。
34
- * 这样主编辑器(默认组)与预览弹窗(owner="preview")各自只画自己的实例,互不污染。
35
- */
36
- readonly owner?: string;
37
-
38
- constructor(owner?: string) {
39
- super();
40
- this.owner = owner;
41
- }
42
-
43
- /** 本组是否该收集该实例:按 owner 归属隔离(详见 owner 字段注释) */
44
- private _accepts(child: InstancedChild): boolean {
45
- const childOwner = instancedChildOwner.get(child);
46
- if (this.owner === undefined) {
47
- // 无归属的组(ThreeBase 默认组):只收未声明归属的实例,跳过已归属他组的
48
- return childOwner === undefined;
49
- }
50
- // 有归属的组:只收 owner 完全一致的实例
51
- return childOwner === this.owner;
52
- }
53
-
54
- /** 每帧由 ThreeBase.render 在 scene.updateMatrixWorld 之后调用 */
55
- update(): void {
56
- const delta = this._clock.getDelta();
57
-
58
- // 1. 按 batchKey 收集所有活着的 InstancedChild(按 owner 归属过滤,避免多组互相污染)
59
- const groups = new Map<string, InstancedChild[]>();
60
- for (const child of instancedChildRegistry) {
61
- if (!this._accepts(child)) continue;
62
- // 强制刷新世界矩阵(实例可能位于任意层级,不依赖 scene 遍历顺序)
63
- child.updateWorldMatrix(true, false);
64
- child.markDirtyIfWorldChanged();
65
- const key = child.getBatchKey();
66
- let arr = groups.get(key);
67
- if (!arr) {
68
- arr = [];
69
- groups.set(key, arr);
70
- }
71
- arr.push(child);
72
- }
73
-
74
- // 2. 创建 / 更新每个有实例的 batch(按 glb+当前动画分桶,每个动画一个常驻 batch)
75
- for (const [key, children] of groups) {
76
- let batch = this.batches.get(key);
77
- if (!batch) {
78
- batch = new InstancedBatch(key, children[0]);
79
- this.batches.set(key, batch);
80
- this.add(batch.group);
81
- }
82
- batch.sync(children, delta);
83
- }
84
-
85
- // 3. 持久化:实例已迁移走的空 batch 仍需 sync([]) 把 count 归零,避免残留上一帧实例;
86
- // 但【不销毁】,使其常驻可复用 —— 切换动作时实例在常驻 batch 间迁移,无需频繁创建/销毁 InstancedBatch。
87
- for (const [key, batch] of this.batches) {
88
- if (!groups.has(key)) {
89
- batch.sync([], delta);
90
- }
91
- }
92
- }
93
-
94
- /** 事件路由:命中 InstancedMesh 时返回对应 InstancedChild,否则 null */
95
- resolveInstance(mesh: Object3D, instanceId: number | undefined): InstancedChild | null {
96
- if (instanceId === undefined) {
97
- return null;
98
- }
99
- const key = (mesh as any).userData?.__batchKey as string | undefined;
100
- if (!key) {
101
- return null;
102
- }
103
- const batch = this.batches.get(key);
104
- if (!batch) {
105
- return null;
106
- }
107
- return batch.resolveInstance(mesh as any, instanceId);
108
- }
109
-
110
- /** 收集可拾取的 InstancedMesh(已就绪 batch,且注册了监听或设置了 cursor 的),供 ThreeMouse 候选 */
111
- collectPickable(out: Object3D[]): void {
112
- for (const batch of this.batches.values()) {
113
- if (batch.ready && (batch.hasListener(PICK_EVENT_TYPES) || batch.hasCursor())) {
114
- for (const im of batch.pickables) {
115
- out.push(im);
116
- }
117
- }
118
- }
119
- }
120
-
121
- /**
122
- * 释放本组的全部 batch(实例缓冲 + 从组内摘除 mesh)。
123
- *
124
- * 用途:自建 InstancedGroup 的场景(如预览弹窗的独立轻量渲染器)在销毁时调用,
125
- * 避免 InstancedMesh 的实例缓冲随组对象一起被丢弃却未释放。
126
- *
127
- * 注:batch 的 geometry/material **不会**被释放(InstancedBatch.dispose 刻意跳过)——
128
- * 它们来自 `InstancedChild` 的 static geometry/material 或模板缓存,是跨实例共享资源。
129
- * ⚠️ 默认的 ThreeBase 组**不要**调用本方法:它随应用生命周期常驻,batch 复用是设计意图。
130
- */
131
- dispose(): void {
132
- for (const batch of this.batches.values()) {
133
- batch.dispose();
134
- }
135
- this.batches.clear();
136
- }
137
- }
1
+ import { Clock, Object3D } from "three";
2
+ import InstancedChild, { instancedChildRegistry, instancedChildOwner } from "./InstancedChild";
3
+ import InstancedBatch from "./InstancedBatch";
4
+
5
+ const PICK_EVENT_TYPES = [
6
+ "mouseenter",
7
+ "mouseleave",
8
+ "mousemove",
9
+ "click",
10
+ "leftclick",
11
+ "rightclick",
12
+ "dbclick",
13
+ "mousedown",
14
+ "mouseup",
15
+ ];
16
+
17
+ /**
18
+ * 固定在 ThreeBase.scene 里的分组器。每帧收集所有 InstancedChild,按 batchKey(glb+当前生效动画)分组,
19
+ * 为每个 key 创建/复用 InstancedBatch,把实例的世界矩阵 / 颜色同步进真实 InstancedMesh。
20
+ * batch 常驻(空桶不销毁),切换动画 = 实例在「glb+旧动画」「glb+新动画」两个常驻 batch 间迁移。
21
+ *
22
+ * 同时也是事件路由中枢:ThreeMouse 命中 InstancedMesh 后,通过本类把 (mesh, instanceId)
23
+ * 还原成对应的 InstancedChild,使逻辑实例成为透明事件接收端。
24
+ */
25
+ export default class InstancedGroup extends Object3D {
26
+ /** batchKey -> InstancedBatch */
27
+ batches = new Map<string, InstancedBatch>();
28
+ private _clock = new Clock();
29
+
30
+ /**
31
+ * 本组的归属 tag(可选)。多 InstancedGroup 共存时用于隔离:
32
+ * - 声明了 owner 的组:**只**收集 `getOwner() === owner` 的实例(未声明归属的实例一律不收);
33
+ * - 未声明 owner 的组(如 ThreeBase 的默认组):只收**未声明归属**的实例,跳过已归属他组的实例。
34
+ * 这样主编辑器(默认组)与预览弹窗(owner="preview")各自只画自己的实例,互不污染。
35
+ */
36
+ readonly owner?: string;
37
+
38
+ constructor(owner?: string) {
39
+ super();
40
+ this.owner = owner;
41
+ }
42
+
43
+ /** 本组是否该收集该实例:按 owner 归属隔离(详见 owner 字段注释) */
44
+ private _accepts(child: InstancedChild): boolean {
45
+ const childOwner = instancedChildOwner.get(child);
46
+ if (this.owner === undefined) {
47
+ // 无归属的组(ThreeBase 默认组):只收未声明归属的实例,跳过已归属他组的
48
+ return childOwner === undefined;
49
+ }
50
+ // 有归属的组:只收 owner 完全一致的实例
51
+ return childOwner === this.owner;
52
+ }
53
+
54
+ /** 每帧由 ThreeBase.render 在 scene.updateMatrixWorld 之后调用 */
55
+ update(): void {
56
+ const delta = this._clock.getDelta();
57
+
58
+ // 1. 按 batchKey 收集所有活着的 InstancedChild(按 owner 归属过滤,避免多组互相污染)
59
+ const groups = new Map<string, InstancedChild[]>();
60
+ for (const child of instancedChildRegistry) {
61
+ if (!this._accepts(child)) continue;
62
+ // 强制刷新世界矩阵(实例可能位于任意层级,不依赖 scene 遍历顺序)
63
+ child.updateWorldMatrix(true, false);
64
+ child.markDirtyIfWorldChanged();
65
+ const key = child.getBatchKey();
66
+ let arr = groups.get(key);
67
+ if (!arr) {
68
+ arr = [];
69
+ groups.set(key, arr);
70
+ }
71
+ arr.push(child);
72
+ }
73
+
74
+ // 2. 创建 / 更新每个有实例的 batch(按 glb+当前动画分桶,每个动画一个常驻 batch)
75
+ for (const [key, children] of groups) {
76
+ let batch = this.batches.get(key);
77
+ if (!batch) {
78
+ batch = new InstancedBatch(key, children[0]);
79
+ this.batches.set(key, batch);
80
+ this.add(batch.group);
81
+ }
82
+ batch.sync(children, delta);
83
+ }
84
+
85
+ // 3. 持久化:实例已迁移走的空 batch 仍需 sync([]) 把 count 归零,避免残留上一帧实例;
86
+ // 但【不销毁】,使其常驻可复用 —— 切换动作时实例在常驻 batch 间迁移,无需频繁创建/销毁 InstancedBatch。
87
+ for (const [key, batch] of this.batches) {
88
+ if (!groups.has(key)) {
89
+ batch.sync([], delta);
90
+ }
91
+ }
92
+ }
93
+
94
+ /** 事件路由:命中 InstancedMesh 时返回对应 InstancedChild,否则 null */
95
+ resolveInstance(mesh: Object3D, instanceId: number | undefined): InstancedChild | null {
96
+ if (instanceId === undefined) {
97
+ return null;
98
+ }
99
+ const key = (mesh as any).userData?.__batchKey as string | undefined;
100
+ if (!key) {
101
+ return null;
102
+ }
103
+ const batch = this.batches.get(key);
104
+ if (!batch) {
105
+ return null;
106
+ }
107
+ return batch.resolveInstance(mesh as any, instanceId);
108
+ }
109
+
110
+ /** 收集可拾取的 InstancedMesh(已就绪 batch,且注册了监听或设置了 cursor 的),供 ThreeMouse 候选 */
111
+ collectPickable(out: Object3D[]): void {
112
+ for (const batch of this.batches.values()) {
113
+ if (batch.ready && (batch.hasListener(PICK_EVENT_TYPES) || batch.hasCursor())) {
114
+ for (const im of batch.pickables) {
115
+ out.push(im);
116
+ }
117
+ }
118
+ }
119
+ }
120
+
121
+ /**
122
+ * 释放本组的全部 batch(实例缓冲 + 从组内摘除 mesh)。
123
+ *
124
+ * 用途:自建 InstancedGroup 的场景(如预览弹窗的独立轻量渲染器)在销毁时调用,
125
+ * 避免 InstancedMesh 的实例缓冲随组对象一起被丢弃却未释放。
126
+ *
127
+ * 注:batch 的 geometry/material **不会**被释放(InstancedBatch.dispose 刻意跳过)——
128
+ * 它们来自 `InstancedChild` 的 static geometry/material 或模板缓存,是跨实例共享资源。
129
+ * ⚠️ 默认的 ThreeBase 组**不要**调用本方法:它随应用生命周期常驻,batch 复用是设计意图。
130
+ */
131
+ dispose(): void {
132
+ for (const batch of this.batches.values()) {
133
+ batch.dispose();
134
+ }
135
+ this.batches.clear();
136
+ }
137
+ }