three-base 2.0.142 → 2.0.145
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DirectionalLight.d.ts +6 -6
- package/DirectionalLight.js +68 -68
- package/EventMap.d.ts +103 -103
- package/EventMap.js +17 -17
- package/EventMesh.d.ts +18 -18
- package/EventMesh.js +59 -59
- package/ExtrudeMesh.d.ts +112 -112
- package/ExtrudeMesh.js +342 -342
- package/FPScontrol.d.ts +511 -511
- package/FPScontrol.js +1799 -1799
- package/FPScontrol.ts +1855 -1855
- package/Fire/Fire.d.ts +28 -28
- package/Fire/Fire.js +80 -80
- package/Fire/FireGeometry.d.ts +9 -9
- package/Fire/FireGeometry.js +40 -40
- package/Fire/FireMaterial.d.ts +28 -28
- package/Fire/FireMaterial.js +32 -32
- package/Fire/index.d.ts +2 -2
- package/Fire/index.js +2 -2
- package/GLTFDracoLoader.d.ts +71 -71
- package/GLTFDracoLoader.js +266 -266
- package/GLTFDracoLoader.ts +1 -1
- package/Grass/Grass.d.ts +8 -8
- package/Grass/Grass.js +38 -38
- package/Grass/index.d.ts +2 -2
- package/Grass/index.js +2 -2
- package/Ground1/Ground1.d.ts +10 -10
- package/Ground1/Ground1.js +71 -71
- package/Ground1/index.d.ts +1 -1
- package/Ground1/index.js +1 -1
- package/MeshBase.d.ts +36 -36
- package/MeshBase.js +247 -247
- package/Mirror.d.ts +25 -25
- package/Mirror.js +143 -143
- package/MktMesh/MktMesh.d.ts +301 -291
- package/MktMesh/MktMesh.js +1064 -1045
- package/MktMesh/MktMesh.ts +32 -11
- package/MktMesh/assetUrl.d.ts +59 -35
- package/MktMesh/assetUrl.js +154 -69
- package/MktMesh/assetUrl.ts +155 -69
- package/MktMesh/mktMappingShader.d.ts +12 -12
- package/MktMesh/mktMappingShader.js +138 -138
- package/MktMesh/mktMappingShader.ts +139 -139
- package/MktMesh/mktShader.d.ts +263 -263
- package/MktMesh/mktShader.js +1236 -1236
- package/MktMesh/mktShader.ts +1344 -1344
- package/MktMesh/panoBitmapTexture.d.ts +25 -25
- package/MktMesh/panoBitmapTexture.js +52 -52
- package/MktMesh/panoBitmapTexture.ts +54 -54
- package/MktMesh/panoSlotBind.d.ts +29 -29
- package/MktMesh/panoSlotBind.js +106 -106
- package/MktMesh/panoSlotBind.ts +153 -153
- package/MktMesh/panoSlotRoster.d.ts +22 -22
- package/MktMesh/panoSlotRoster.js +169 -169
- package/MktMesh/panoSlotRoster.ts +168 -168
- package/MktMesh/panoTileStitcher.d.ts +119 -119
- package/MktMesh/panoTileStitcher.js +529 -529
- package/MktMesh/panoTileStitcher.ts +616 -616
- package/MktMesh/types.d.ts +75 -75
- package/MktMesh/types.js +1 -1
- package/MktMesh/wallCapTessellate.d.ts +33 -33
- package/MktMesh/wallCapTessellate.js +97 -97
- package/MktMesh/wallCapTessellate.ts +68 -68
- package/PipeMesh/PathGeometry.d.ts +44 -44
- package/PipeMesh/PathGeometry.js +307 -307
- package/PipeMesh/PathPoint.d.ts +17 -17
- package/PipeMesh/PathPoint.js +31 -31
- package/PipeMesh/PathPointList.d.ts +31 -31
- package/PipeMesh/PathPointList.js +209 -209
- package/PipeMesh/PathTubeGeometry.d.ts +25 -25
- package/PipeMesh/PathTubeGeometry.js +130 -130
- package/PipeMesh/PipeMesh.d.ts +25 -25
- package/PipeMesh/PipeMesh.js +63 -63
- package/PipeMesh/index.d.ts +1 -1
- package/PipeMesh/index.js +1 -1
- package/PlaneModal1/PlaneModal1.d.ts +34 -34
- package/PlaneModal1/PlaneModal1.js +109 -109
- package/PlaneModal1/index.d.ts +1 -1
- package/PlaneModal1/index.js +1 -1
- package/PlaneText.d.ts +27 -27
- package/PlaneText.js +35 -35
- package/PlaneWithHtml.d.ts +13 -13
- package/PlaneWithHtml.js +64 -64
- package/PointLight/PointLight.d.ts +13 -13
- package/PointLight/PointLight.js +64 -64
- package/PointLight/index.d.ts +1 -1
- package/PointLight/index.js +1 -1
- package/Sky/Sky.d.ts +9 -9
- package/Sky/Sky.js +22 -22
- package/Sky/index.d.ts +1 -1
- package/Sky/index.js +1 -1
- package/SpotLight.d.ts +6 -6
- package/SpotLight.js +72 -72
- package/SpriteModal1/SpriteModal1.d.ts +33 -33
- package/SpriteModal1/SpriteModal1.js +116 -116
- package/SpriteModal1/index.d.ts +1 -1
- package/SpriteModal1/index.js +1 -1
- package/SpriteText.d.ts +46 -46
- package/SpriteText.js +176 -176
- package/SpriteText2.d.ts +48 -48
- package/SpriteText2.js +223 -223
- package/SpriteText3.d.ts +86 -86
- package/SpriteText3.js +517 -517
- package/SpriteText3.ts +599 -599
- package/SpriteWithHtml.d.ts +9 -9
- package/SpriteWithHtml.js +44 -44
- package/Text3D/Text3D.d.ts +20 -20
- package/Text3D/Text3D.js +58 -58
- package/Text3D/fontController.d.ts +60 -60
- package/Text3D/fontController.js +166 -166
- package/Text3D/index.d.ts +1 -1
- package/Text3D/index.js +1 -1
- package/ThreeBase.d.ts +248 -248
- package/ThreeBase.js +1202 -1202
- package/ThreeBase.ts +1314 -1314
- package/ThreeMouse.d.ts +53 -54
- package/ThreeMouse.js +453 -453
- package/Transition.d.ts +45 -45
- package/Transition.js +209 -209
- package/Water/Water.d.ts +5 -5
- package/Water/Water.js +44 -44
- package/Water/index.d.ts +2 -2
- package/Water/index.js +2 -2
- package/WaterFlow/FloatingDuck.d.ts +88 -88
- package/WaterFlow/FloatingDuck.js +307 -307
- package/WaterFlow/FloatingDuck.ts +445 -445
- package/WaterFlow/GPUFluidSimulation.d.ts +56 -56
- package/WaterFlow/GPUFluidSimulation.js +781 -781
- package/WaterFlow/GPUFluidSimulation.ts +827 -827
- package/WaterFlow/ReservoirSystem.d.ts +106 -106
- package/WaterFlow/ReservoirSystem.js +611 -611
- package/WaterFlow/ReservoirSystem.ts +754 -754
- package/WaterFlow/SPHField.d.ts +35 -35
- package/WaterFlow/SPHField.js +203 -203
- package/WaterFlow/SPHField.ts +228 -228
- package/WaterFlow/ScreenSpaceFluidPass.d.ts +69 -69
- package/WaterFlow/ScreenSpaceFluidPass.js +728 -728
- package/WaterFlow/ScreenSpaceFluidPass.ts +789 -789
- package/WaterFlow/ShallowWaterSurface.d.ts +45 -45
- package/WaterFlow/ShallowWaterSurface.js +438 -438
- package/WaterFlow/ShallowWaterSurface.ts +510 -510
- package/WaterFlow/WaterFlow.d.ts +87 -87
- package/WaterFlow/WaterFlow.js +171 -171
- package/WaterFlow/WaterFlow.ts +219 -219
- package/WaterFlow/types.d.ts +161 -161
- package/WaterFlow/types.js +1 -1
- package/WaterFlow/types.ts +189 -189
- package/WaterFlow/waterFlowPass.d.ts +3 -3
- package/WaterFlow/waterFlowPass.js +20 -20
- package/WaterFlow/waterFlowPass.ts +40 -40
- package/collisionOBB.d.ts +42 -42
- package/collisionOBB.js +112 -112
- package/collisionOBB.ts +108 -108
- package/declare.d.ts +25 -25
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/instanced/InstancedBatch.d.ts +57 -57
- package/instanced/InstancedBatch.js +348 -348
- package/instanced/InstancedBatch.ts +406 -406
- package/instanced/InstancedChild.d.ts +174 -174
- package/instanced/InstancedChild.js +264 -264
- package/instanced/InstancedChild.ts +327 -327
- package/instanced/InstancedGroup.d.ts +43 -43
- package/instanced/InstancedGroup.js +126 -126
- package/instanced/InstancedGroup.ts +137 -137
- package/instanced/InstancedMeshBase.d.ts +38 -38
- package/instanced/InstancedMeshBase.js +282 -282
- package/instanced/InstancedTemplate.d.ts +46 -46
- package/instanced/InstancedTemplate.js +125 -125
- package/keyControls.d.ts +29 -30
- package/keyControls.js +101 -101
- package/lensflare/LensFlare.d.ts +39 -39
- package/lensflare/LensFlare.js +284 -284
- package/package.json +6 -1
- package/pass/bloom_pass.d.ts +2 -2
- package/pass/bloom_pass.js +174 -174
- package/pass/cover_pass.d.ts +2 -2
- package/pass/cover_pass.js +108 -108
- package/pass/debugDepthState.d.ts +20 -20
- package/pass/debugDepthState.js +9 -9
- package/pass/debugDepthState.ts +22 -22
- package/pass/depthTestBias.d.ts +12 -12
- package/pass/depthTestBias.js +12 -12
- package/pass/depthTestBias.ts +12 -12
- package/pass/effectUserData.d.ts +27 -27
- package/pass/effectUserData.js +1 -1
- package/pass/effectUserData.ts +46 -46
- package/pass/frosted_glass_pass.d.ts +2 -2
- package/pass/frosted_glass_pass.js +150 -150
- package/pass/fsQuad.d.ts +9 -9
- package/pass/fsQuad.js +28 -28
- package/pass/glow_pass.d.ts +2 -2
- package/pass/glow_pass.js +350 -350
- package/pass/screen_bloom_pass.d.ts +11 -11
- package/pass/screen_bloom_pass.js +136 -136
- package/pass/ssao_pass.d.ts +88 -88
- package/pass/ssao_pass.js +799 -799
- package/pass/ssao_pass.ts +918 -918
- package/pass/stroke_pass.d.ts +2 -2
- package/pass/stroke_pass.js +267 -267
- package/shaders/FXAAShaderMaterial.d.ts +3 -3
- package/shaders/FXAAShaderMaterial.js +20 -20
- package/shaders/baseDepthVisShader.d.ts +11 -11
- package/shaders/baseDepthVisShader.js +36 -36
- package/shaders/baseDepthVisShader.ts +36 -36
- package/shaders/baseTextureToRenderShader.d.ts +2 -2
- package/shaders/baseTextureToRenderShader.js +19 -19
- package/shaders/copyShader.d.ts +3 -3
- package/shaders/copyShader.js +13 -13
- package/shaders/debugDepthCompareShader.d.ts +14 -14
- package/shaders/debugDepthCompareShader.js +49 -49
- package/shaders/debugDepthCompareShader.ts +50 -50
- package/shaders/debugDepthJudgeShader.d.ts +18 -18
- package/shaders/debugDepthJudgeShader.js +52 -52
- package/shaders/debugDepthJudgeShader.ts +54 -54
- package/shaders/debugExcludedShader.d.ts +13 -13
- package/shaders/debugExcludedShader.js +46 -46
- package/shaders/debugExcludedShader.ts +48 -48
- package/spriteTextBg.d.ts +1 -1
- package/spriteTextBg.js +20 -20
- package/spriteTextBg.ts +20 -20
- package/threeLoader.d.ts +35 -35
- package/threeLoader.js +518 -518
- package/threeUtils.d.ts +53 -53
- package/threeUtils.js +329 -329
- package/types.d.ts +2 -2
- 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
|
+
}
|