Skip to content

在浏览器里造开放世界,第 7 部分:Marching cubes 和第一批真正的洞穴

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

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

Heightmap 一切都好,直到你需要悬岩。

你一旦想要开凿的隧道、悬挑的岩唇或者洞顶,纯 heightfield 管线就开始挡你。Heightmap 在每个 XZ 坐标上存一个 Y 值。它在物理上没法表示任何会折回到自己上面的表面。我们需要一个体素表示。

Spike 12 用 WebGPU compute shader 在 GPU 上实现了 marching cubes。算法在一个 3D 网格上求 SDF(signed distance field)的值,并在零等值面提取三角网格。每个网格 cell 通过查找表分到 256 种 case 中的一种,然后吐出对应的三角形。我们同时跑了四个 64 立方的活跃 chunk,并测试了带逐帧 remesh 的动画 SDF 编辑。

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

第一个收获是对 compute 管线本身的信心。一次 dispatch 就能求 SDF、分类 cell、把顶点吐进 GPU buffer,全程不用 CPU 回读。第二个收获是发现"它能跑"是怎么迅速变成"找瑕疵"的。缺失的三角形很少是 marching cubes 理论的问题。是查找表索引对不上、draw 范围错误读到活跃顶点数之外、或者在 chunk 边界附近邻居 SDF 采样不可用时的边缘 case。

这个 spike 逼着我们按区域思考。相机附近,你要体素自由度,让玩家可以挖、可以掘、可以看到洞穴。相机远处,你要 clipmap 的效率——一张平的 heightmap 更便宜,也完全够用。这种二元性成了从 Spike 13 之后我们不断打磨的架构的脊梁。

我最喜欢的一个 debug 时刻是编辑进行中切换 wireframe。看着拓扑实时形成又溶解,把质量上的权衡立刻显出来。你能看到哪里顶点密度够、哪里太粗,以及之后 LOD 过渡到底要在哪里加 Transvoxel 支持来避免裂缝。

第 8 部分讲集成的挑战。把原始 compute 驱动的 mesh 和 Three.js 场景图逻辑放进一条稳定的渲染管线里,比孤立 demo 暗示的要难。

本章涉及的技术

Marching cubes。 从 3D 标量场里提取三角网格的算法(Lorensen 和 Cline,1987)。规则 3D 网格里的每个 cell 通过在 8 个角上采样标量场来分类。符号模式产生一个 case 索引(0-255),查找表把每个 case 映射成一组三角形。顶点通过在两个角之间插值放在网格边上。这个算法是 embarrassingly parallel 的,每个 cell 独立处理,非常适合 GPU compute。看我们的地形指南里的 SDF 和 marching cubes

Signed Distance Field (SDF)。 一种体素表示,在 3D 空间每个点上存到最近表面的有符号距离。正值在外面,负值在里面,零等值面就是表面。SDF 可以表示任意 3D 形状:洞穴、拱、悬岩、heightmap 没法表达的悬浮几何。编辑很自然:加材料是对距离场做 min(),挖(移除)是对取反形状做 max(),平滑混合用 smoothMin()。看 SDF 地形表示

WebGPU compute shader。 跑通用计算的 GPU 程序,不绑在光栅化管线上。Compute shader dispatch 一组 workgroup 并行执行。Marching cubes 里,每个线程处理一个网格 cell:采 SDF、分类 cell、查三角化表、插值边顶点、用 atomic counter 追加到 mesh buffer。不需要 CPU 回读,因为输出 buffer 直接被当作顶点数据拿去渲染。Will Usher 的 webgpu-marching-cubes 演示了浏览器里实时处理 256^3 网格。看我们的地形指南里的 WebGPU 驱动 LOD

Heightmap + SDF 混合架构。 浏览器地形的实操做法:heightmap 覆盖整个世界(便宜、紧凑),SDF 体积只存在于需要洞穴、悬岩或者创作者凿出来的特征的 chunk 里(5-10% 的 chunk)。相机附近,体素自由度允许凿洞和洞穴。远处,heightmap 提供高效的平坦地形。看混合地形表示


12 篇中的第 7 篇。 上一篇:第 6 部分 - Clipmap 改变了剧情 下一篇:第 8 部分 - 不丢掉基线的情况下做集成 系列导览:/zh-CN/blog/2026-02-25-open-world-browser-series-guide