Skip to content

在浏览器里造开放世界,第 8 部分:不丢掉基线的情况下做集成

作者:Oleg Sidorkin,Cinevva CTO 和联合创始人

刚看到?看系列导览。那里解释了 spike 是什么,并链接了所有部分。

集成是项目变乱的地方。你有几个孤立工作的部分。你把它们接起来,突然每个 bug 都像可能在任何地方。

Spike 13 和 14 就是我们对这个陷阱的回应。Spike 13 立了一个干净的 Three.js WebGPU 基线。就一个 renderer、一个 scene、一个 camera、一个简单 mesh。没有地形、没有 compute、没有特效。我们确认 Three.js 的 WebGPU 后端正确初始化、渲染循环稳定、TSL(Three.js Shading Language)节点材质按预期工作。只有这个检查点过了,我们才开始加层。

在新标签页里打开 Spike 13 ↗ · 看源码

Spike 14 是增量加固。一次加一个能力:先是相机控制,然后是光照,然后是来自 marching cubes 管线的 compute 生成的 mesh,然后是把 GPU 输出直接接到 Three.js 几何属性上的 buffer 接线。每加一个,都验证之前的层还在按预期工作。

在新标签页里打开 Spike 14 ↗ · 看源码

听上去慢。慢了正好一天,但很快就在接缝逻辑和策略切换变复杂时给我们省下了好几天。

证明这种纪律值得的 bug 类别,是细线瑕疵。看上去像几何损坏的细针状东西,其实是过期数据。compute shader 往一个 buffer 里写 N 个顶点,但 draw call 还配置成渲染前一帧的 N+M 个顶点。多出来的顶点装的是上一次 dispatch 留下的垃圾。视觉效果是不可预测地出现又消失的、闪烁的薄三角形。

这类 bug 不是靠直觉打败的。是靠受控的 delta 打败的——你确切知道上一次工作状态和当前坏状态之间改了什么。

WebGPU 集成还教了我们 buffer 生命周期。WebGPU 里的 GPU buffer 一旦为特定 usage 映射就不可变。如果 marching cubes 输出长了、你需要扩 vertex buffer,你得新建一个 buffer 并更新绑定。没有 realloc。把这个生命周期搞对——在不和飞行中的 GPU 工作竞态的前提下销毁旧 buffer——需要显式的 fence 管理,这在 WebGL 里是没有的。

第 9 部分进入 Transvoxel 接缝工作。那一章故意从脚手架开始。到这时候我们已经完全内化了一个教训:仓促集成产生谜题,受控搭建产生可 debug 的问题。

本章涉及的技术

WebGPU。 WebGL 的接班人,给浏览器提供低层 GPU 访问,带 compute shader 和 indirect rendering。WebGPU 对开放世界来说两个关键特性:compute shader 让 GPU 侧地形生成、植被放置、剔除成为可能;indirect rendering 让 GPU 基于 compute 输出决定画什么,在密集场景里消除 CPU 瓶颈。桌面端 Chrome、Edge、Firefox 都支持。看 WebGPU 作为性能解锁

Three.js Shading Language (TSL)。 Three.js 基于节点的着色器系统,用可组合的 JavaScript 表达式替代原始 GLSL/WGSL。texture()positionWorldsmoothstep()fog() 这些 TSL 节点在运行时构建一张着色器图,编译成对应后端(WebGL 的 GLSL 或 WebGPU 的 WGSL)。TSL 让你能一次写完材质逻辑,同时面向两个渲染器。节点图每帧求值,所以动态 uniform 和条件分支天然能用。

WebGPU 里的 GPU buffer 生命周期。 WebGPU buffer 创建时带特定 usage flag(VERTEXSTORAGECOPY_DST 等),创建之后不能改大小。如果一次 marching cubes dispatch 产出的顶点比 buffer 能装的多,你必须新建一个 buffer、更新绑定、销毁旧的。销毁还被飞行中的 GPU 命令引用的 buffer 会报错。显式 fence 管理(通过 device.queue.onSubmittedWorkDone())确保旧 buffer 在 GPU 用完之前不会被销毁。这种生命周期纪律在 WebGL 里不存在,那里 driver 隐式管内存。

增量加固。 集成的一种流程纪律:立一个已知良好的基线,一次加一个能力,每次加完都验证之前的层还在工作。这种做法慢一天,但在之后 debug 时省好几天,因为每一次回退都能追到一个具体、受控的改动。基线-再-增量的模式在 3A 开放世界开发里很常见,那里系统按特定顺序集成以管理风险。


12 篇中的第 8 篇。 上一篇:第 7 部分 - Marching cubes 和第一批真正的洞穴 下一篇:第 9 部分 - Transvoxel 从脚手架开始 系列导览:/zh-CN/blog/2026-02-25-open-world-browser-series-guide