参数变化与重建
重建策略
- 参数变化触发的几何重建必须经过防抖处理(推荐 100–200ms),保证滑杆连续拖动时不因逐帧重建而掉帧。
- 重建范围必须限定为内容 group 子树;相机位置、OrbitControls 状态、环境动效 rig 均不得因参数变化而重置。
资源释放
两种生命周期,不得合成同一个 dispose 函数。
每次重建释放本次构建创建的资源:
- 所有
geometry.dispose() - 所有
material.dispose(),以及为本次构建创建的纹理
未正确释放会导致用户持续调参过程中 GPU 内存增长,最终页面卡死。
仅在卸载时释放跨重建存活的资源:
- PMREM 的 RenderTarget 与环境贴图
- 跨重建复用的共享纹理——程序化噪声纹理、与 2D 画布共用的
CanvasTexture(见渲染质量) controls.dispose()与renderer.dispose()
两份清单互不容纳对方的条目。每次重建重新生成环境贴图,等于每个防抖周期跑一趟多趟 PMREM 渲染——比你想避免的那个泄漏更贵;每次重建释放共享纹理则更糟——下一帧材质拿到一张死纹理,直接渲染成空白。
注意:遍历内容子树、见到纹理就 dispose 会同时踩中这两个坑——材质引用共享纹理,但并不拥有它。释放你创建的,不要释放你引用的。
尺寸、设备像素比与零尺寸防护
renderer.setPixelRatio()必须封顶——Math.min(window.devicePixelRatio, 2)。在手机或 5K 屏上按 DPR 3 渲染,片元开销是 DPR 2 的 2.25 倍且肉眼无差别,这是「开发机上跑得好好的、到用户那儿掉帧」最常见的原因。- 响应容器尺寸变化必须三件齐全:
camera.aspect、camera.updateProjectionMatrix()、renderer.setSize()。漏了updateProjectionMatrix()画面拉伸,漏了setSize()还按旧分辨率渲染。 - 组件可能在隐藏页签或折叠面板中以 0×0 尺寸挂载。ResizeObserver 收到 0×0 尺寸时必须忽略并保留既有视图状态,待获得非零尺寸后再执行初始化或自适应,确保页签切换后视图完好。