<p>核心是用 async function* 构建可中断、可组合、带状态的材质加载流水线,yield 主动交出控制权给调度器;需按依赖图拆解为原子步骤分段加载异构材质资源;迭代器须绑定宿主生命周期防泄漏;支持 next(value) 注入运行时参数动态调整;错误处理应结构化 yield 而非 throw。</p>

核心在于用 async function* 构建可中断、可组合、带状态的材质加载流水线,yield 不是“暂停”,而是主动让出控制权,把加载节奏交还给调度器——比如渲染帧循环或资源优先级队列。
材质加载必须分段,不能一锅端
异构材质(PBR、Unlit、Toon、粒子特效材质等)依赖不同资源:着色器编译结果、多张纹理(baseColor、normal、roughness)、GPU buffer 初始化、甚至运行时生成的LUT。一次性 await 所有依赖会阻塞整个管线。应按依赖图拆解为原子步骤:
- 先 yield 加载基础 effect asset(如
.effect文件),校验 shader 编译是否通过 - 再 yield 并行加载关键纹理(视锥内物体的 baseColor + normal),用
Promise.allSettled容错 - 最后 yield GPU 资源上传(
device.queue.submit或GraphicsDevice.CopyTexture),确保 GPU 可见性同步
yield\* 要绑定上下文生命周期
每个材质实例的异步迭代器必须与它的使用场景强关联。例如:
- 若材质用于即将进入视野的 LOD2 物体,迭代器应在
OnBecameVisible触发后启动,并在OnBecameInvisible时调用return()中断未完成的 yield - 若材质属于 UI 粒子系统,应绑定 Canvas 渲染帧末尾——用
yield new WaitForEndOfFrame()对齐 UI 刷新时机,避免撕裂 - 不可让迭代器脱离宿主对象存活,否则会造成内存泄漏和状态错乱
用 next(value) 注入运行时参数
材质加载不是只读流程。真实场景中常需动态调整:
- 加载过程中检测到显存紧张,可传入
{ budget: 'low' },让后续 yield 跳过 Mipmap 生成或降采样纹理 - 用户切换画质档位,外部调用
iterator.next({ quality: 'ultra' }),驱动材质选择更高精度 normal map 或启用 subsurface scattering - 网络条件变化时注入带宽提示,触发 texture loader 切换压缩格式(ASTC → ETC2)
错误处理不能靠 try-catch 包裹整个 generator
generator 内部抛出异常会导致迭代器立即终止,无法恢复。正确做法是每个 yield 步骤单独兜底:
- 对每个
await操作外层包一层try/catch,捕获后 yield 一个{ status: 'failed', reason: 'timeout' }结构化错误项 - 允许消费者决定是跳过该材质、回退到 fallback 材质,还是重试当前 step
- 避免在 generator 中直接
throw,改用yield { error: ... }保持迭代器存活

















