在浏览器里造开放世界,第 11 部分:策略模式,不是硬编码模式
作者:Oleg Sidorkin,Cinevva CTO 和联合创始人
刚看到?看系列导览。那里解释了 spike 是什么,并链接了所有部分。
接缝混乱那一章之后,我们得停止反应,开始治理。
Spike 23 用显式策略规则替换了各自为政的行为。chunk 不再按自己本地状态暗示的随便干,而是由一个中央策略系统做决定。这个 chunk 拿哪一级 LOD?渲染成 heightmap 还是 marching cubes?需要过渡 cell 吗,在哪些面上?答案来自一个评估"到相机距离、编辑历史、邻居分辨率状态"的策略函数。
基于距离的 LOD 分配用的是以相机为中心的同心环,类似 clipmap 概念但应用在 chunk 网格上。环 0 的 chunk 拿全分辨率 MC。环 1 拿半分辨率 MC。环 2 及以外切到 heightmap 模式。邻接约束很关键:如果两个相邻 chunk 差超过一个 LOD 级别,策略强制低细节 chunk 升级。这避免了 Transvoxel 表搞不定的接缝 case,因为过渡 cell 只为 2:1 分辨率比定义。
HM/MC 切换逻辑检查每个 chunk 的编辑位图。如果一个 chunk 有任何体素编辑(洞穴、隧道、地形雕刻),它无论距离如何都留在 MC 模式。未编辑的 chunk 走远了就可以降到 heightmap 模式。这种混合做法让我们在重要的地方有体素自由度,在不重要的地方有效率。
这个 spike 从外面看比之前一些更小。实际上对开发体验是个重大改善。
当你的系统能解释为什么一个 chunk 切换了模式,你花在猜上的时间就少。我们加了颜色编码 overlay:绿色表示 heightmap chunk,蓝色表示 MC chunk,橙色表示过渡激活的面。当接缝可见性有专门的渲染控制,视觉 debug 的含糊就少。当 draw 范围显式绑定到策略系统的活跃顶点数,过期几何鬼影就不再浪费你一下午。
我们在这个 spike 里也大改了相机行为。早期 spike 的简单 orbit 控制截图够用,但拿来复现 bug 没用。Spike 23 加了 WASD 飞行相机,速度可配置,高度锁定切换,位置读数。听上去小。但这意味着"我在那个山脊附近某处看到一个 bug"和"bug 出现在位置 (142, 12, -67)、朝向西北"之间的区别。
这一章的关键洞察是:策略没有减少复杂度。它组织了复杂度。同样数量的边缘 case 还在。但现在每个边缘 case 都有名字、有触发条件、有一个你可以下断点的代码位置。这是另一种胜利,决定了一个系统能持续演化还是在自己的重量下塌掉。
到 Spike 23 末尾,我们有了一个近场行为层,可预测到能去接远场 clipmap 环策略而不用持续担心交互 bug。
第 12 部分讲 Spike 24,环过渡、天空盒雾、Three.js 版本级的着色器集成给这个项目的这一章画上句号。
本章涉及的技术
基于距离的 LOD 策略。 一个中央函数,基于到相机距离、编辑历史、邻居状态给每个 chunk 分配 LOD 级别和渲染模式。同心距离环决定基础 LOD:环 0 = 全分辨率 MC,环 1 = 半分辨率 MC,环 2+ = heightmap 模式。策略函数随相机移动每帧跑,触发 chunk 过渡。这把临时的逐 chunk 决策替换成可预测、可 debug 的规则系统。看 GPU 驱动 LOD 选择了解 compute shader 等价物。
邻接约束。 Transvoxel 算法只处理 2:1 分辨率比。如果两个相邻 chunk 差超过一个 LOD 级别(比如 LOD 0 挨着 LOD 2),过渡表不能产出合法接缝几何。策略系统通过在 LOD 差超过 1 时升级低细节 chunk 来强制这一点。这种约束传播可以级联:升一个 chunk 可能逼它的邻居也升级。实现是个简单的迭代 pass,典型网格配置下 2-3 次迭代收敛。
做模式选择的编辑位图。 每个 chunk 维护一个位图,记录它是否含体素 SDF 编辑(洞穴、隧道、雕刻)。有任何编辑的 chunk 无论距离如何都留在 marching cubes 模式,保留创作者的修改。未编辑的 chunk 走远了就降到 heightmap 模式,省 compute 和内存。位图是每 chunk 一个 flag,但可以扩展跟踪编辑密度,做更细粒度的模式决策。
Debug 可视化 overlay。 颜色编码 chunk 渲染:绿色 = heightmap 模式,蓝色 = MC 模式,橙色 = 过渡激活的面。带 LOD 级别数字、模式标签、wireframe 切换的 per-chunk overlay。这些是开发工具不是出货功能,但它们在 debug LOD 过渡和接缝瑕疵时反复回本。配上一个能报精确世界位置的 WASD 飞行相机,"我在某处看到一个 bug"就变成了"bug 出现在 (142, 12, -67),在这种 LOD 配置下"。
12 篇中的第 11 篇。 上一篇:第 10 部分 - 接缝混乱和拐角 boss 战 下一篇:第 12 部分 - 环、天空雾、和我们会再做一遍的事 系列导览:/zh-CN/blog/2026-02-25-open-world-browser-series-guide