资源与所有权
Engine 采用一条简单规则:Engine 创建或接纳的标准资源由 Engine 在 Entity/World/Engine 终态释放;业务创建并借给 Engine 的 native Pass、Camera 与自定义资源由业务释放。
Entity destroy
const entity = engine.createEntity(gltf.scene);
engine.world.root.add(entity);
// 不再使用整棵子树:
entity.destroy();destroy() 递归销毁 Entity 子树、解除 Object3D parent、终结 Script,并对一次性资源快照按 identity 去重释放:
- Object3D direct
geometry; - Object3D direct
material或 material array; - Material own data property 直接引用的 Texture;
- Scene direct
background/environmentTexture; - SkinnedMesh direct Skeleton 与其 boneTexture。
engine.dispose() 会共享一个资源去重 Set,避免同一次 Engine 终态中跨剩余 roots 重复释放同一 identity。
明确不扫描的边
Engine 不递归猜测业务所有权,因此不会自动释放:
- ShaderMaterial uniforms 内的 Texture;
userData或普通业务 container 内的资源;customDepthMaterial/customDistanceMaterial;- Scene
overrideMaterial; - WebGLRenderTarget;
- 业务创建后借给 Pipeline 的原生 Pass;
- 额外业务 Camera 的附属资源。
这些资源应由创建它们的 System、Script、Pass Definition 或应用 owner 在自己的终态回调中释放。
borrowed Pass
const pass = new ShaderPass(MyShader);
const Definition = createPass('effect', ({ onDestroy, usePass }) => {
usePass(pass);
onDestroy(() => pass.dispose());
});
engine.pipeline.addPass(Definition);Pipeline 删除 Definition 时只停止持有和执行 borrowed Pass,不调用其 dispose()。示例把释放责任显式放在业务 Definition 的 onDestroy。
共享资源
Engine 的单次 destroy operation 会按 identity 去重,但不会为业务维护跨时间、跨独立 Entity destroy 的引用计数。若资源需要跨子树保留,设置严格标记 resource.userData.shared = true;Entity、World 和 Engine 终态都会跳过它。需要明确无视该保护时,在终态前调用独立 disposeObject3D() 的 { force: true }。
推荐:
- 可释放资源尽量只属于一个 Entity 子树;
- 真正共享的资源设置
userData.shared = true,由更高层业务 owner 管理; force: true只用于调用方确认当前子树已不再被任何 owner 使用的终态场景。
失败语义
资源 discovery 在任何 dispose callback 前完成。释放阶段 best-effort 尝试所有已发现标准资源:一个错误原样抛出,多个错误形成扁平 AggregateError。Entity 已先进入 destroyed 终态,不支持 retry;直接工具的完整边界见 disposeObject3D()。