WebGPU 工程大模型:工作集与资源生命周期

1 阅读3分钟

工程大模型的性能问题,常被简化成“首屏够不够快”。但真实应用通常要连续打开模型、切换楼层、隐藏构件、进入剖切、退出项目再加载下一份数据。只优化第一次出现画面的速度,几轮操作后内存和显存仍会持续上涨。

1. 场景总量不等于当前工作集

一个工厂或大型装配可能包含很多几何,但当前视角真正需要的通常只是其中一部分。运行时应明确区分:

  • 元数据总量:结构、属性与稳定对象身份;
  • 可见候选集:经过空间索引与视锥筛选的块;
  • GPU 驻留集:当前真正需要的顶点、索引、纹理和实例缓冲;
  • 交互保护集:被选中、测量、剖切或正在定位的对象。

如果把整个模型一次性变成场景对象,LOD 只能减少部分绘制开销,却无法自动消除 CPU 对象、GPU 缓冲和纹理驻留。

2. 资源必须有明确所有者

加载器、场景树、渲染批次和业务组件都可能持有同一份资源引用。没有所有权规则时,最常见的结果是:页面看起来已经移除了对象,但 Buffer、Texture 或材质仍被缓存、事件监听器或异步任务引用。

我更倾向于为每个模型会话维护 ResourceRegistry:

  • 资源创建时登记类型、字节数、所属缓存版本和引用者;
  • 批次进入 GPU 驻留集时增加引用;
  • 离开工作集后进入可回收队列;
  • 只有 CPU、GPU、交互与异步任务引用全部归零时才真正释放。

这比在组件销毁时遍历 scene.children 更可靠,因为渲染资源并不一定与可见节点一一对应。

3. 异步加载也要能取消

用户快速切换模型时,旧请求可能仍在下载、解码或上传。即使最后不挂到场景,它们也会制造峰值和竞态。每个模型会话应有 generation 或 AbortSignal:新会话建立后,旧会话的网络请求、Worker 任务、解码结果和 GPU 提交都必须检查代际,过期结果直接丢弃并回收。

4. 释放不是一句 dispose

Three.js 官方明确说明,BufferGeometry、Material、Texture 和 WebGLRenderTarget 等对象的 GPU 资源需要显式释放;把 JavaScript 对象移出场景并不会自动完成这件事。WebGPU 路线同样需要管理 Buffer/Texture 的销毁、绑定缓存、管线引用和 device lost 后的重建。

验收时不要只看 FPS。至少记录:

  • 连续切换 N 个模型后的 CPU 内存与 GPU 占用;
  • 退出项目后资源是否回到可接受基线;
  • 快速切换时是否有旧任务回写新场景;
  • device lost 或页面恢复后能否重建当前工作集;
  • 被选中对象在 LOD/批次变化后是否仍保持稳定身份。

我们做 ModelView 时,把源模型、查看缓存、稳定对象身份、工作集和 GPU 驻留资源分开管理。说明一下,我是 ModelView 的开发者;Windows 标准版可以用真实 BIM、机械 CAD 或工业装配模型验证重复打开与持续审阅:gitee.com/onedraw/mod…

参考资料