这是一篇关于用 TypeScript、WebGL 和 Rust 编写的 3D 引擎的系列文章的第一篇,主要内容如下:
- 背景与目标:引擎主要用于制作演示,基于传统的光栅化 3D 渲染管线,具备多种功能,如支持多种材质的 GLTF 模型加载、实例化、视锥体剔除等。
- Makaron Crisis 与旧引擎:第一个版本的引擎使用射线行进有符号距离场(SDF)进行渲染,在制作名为“Makaron Crisis”的演示时创建,该演示关于 2023 年芬兰通心粉短缺,此版本在渲染复杂形状时存在问题。
新引擎与优化历程:
- 视锥体剔除与实例化优化:视锥体剔除是一种渲染优化技术,用于剔除相机不可见的物体。引擎使用实例化渲染所有可见物体,每帧将物体的实例数据发送到 GPU,但 WebGL2 限制了通过 uniform buffer objects(UBO)传递 per-instance 数据的大小,导致可渲染物体数量受限。作者对不同的视锥体剔除实现进行了优化和测试,包括 SimpleCuller、ThreadedCuller、WasmCuller 和 OctreeCuller 等。
- SimpleCuller:最初实现的简单版本,通过深度优先遍历场景收集可剔除物体,随着时间有了一些改进,但 Oriented Bounding Boxes(OBB)的检查比 Spheres 慢,且 Firefox 比 Chrome 慢。
- ThreadedCuller:使用 Web Worker 进行并行处理,但由于同步问题和序列化/反序列化开销,性能反而更差,还导致引擎在 Firefox 中无法工作,增加了额外的代码包,使渲染循环异步,出现了随机故障,最终被放弃。
- WasmCuller:将 Rust 集成到引擎中,通过
wasm-bindgen
进行编译,经历了多个迭代版本。迭代 1 中,虽然 culling 时间缩短,但由于序列化和 WASM 调用开销,整体 frametime 没有改善;迭代 2 简化了 WASM culler,但添加对象到 culler 的速度变慢,总体渲染性能更差;迭代 3 利用js-sys
中的view_mut_raw
方法共享内存,减少了 overhead,是三种 WASM culler 中最快的,但序列化仍然是主要瓶颈,在 Firefox 中 culling OBBs 比 culling spheres 更快,可能是 Firefox 的优化。 - OctreeCuller:在火车上的餐厅车厢中编写的八叉树实现,用于加速空间查询。介绍了八叉树的基本概念、实现细节,如何时细分和停止、如何处理非点对象和动态对象等。测试结果表明,八叉树 culler 在某些情况下比简单 culler 更快,但仍有改进空间,最佳的每个叶子节点的对象数量为 128 - 256,与常见的 8 - 16 不同。
- DoNothingCuller:测试不进行视锥体剔除的性能,发现上传到 GPU 的实例数据增加,但如果场景不复杂且 GPU 性能强,不剔除可能是最快的解决方案。
- 总结与未来展望:作者认为可以进一步优化视锥体剔除,但对 WASM culler 感到失望,对 Firefox 和 Chrome 的内置分析器也不满意,希望 Web 平台能提供更高效的线性代数和视锥体剔除 API。最后作者邀请读者关注他在 Bluesky 上的账号,期待下一篇文章。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。