Skip to content

地面的重生

背景:地面系统有 3 条独立渲染路径(solid/grid/checker),维护成本高且各有 bug。ADR-091 决策统一为单一 canvas 路径。 过程:删除 GridMaterial 依赖 → 新增 _generateGroundTexture() → 512×512 canvas 统一绘制 → 所有 flat 样式走同一路径。


七月十二日,下午。

Riku 站在屏幕前,看着 env-impl.ts 的代码。345 行未提交的改动,像一团乱麻。

地面系统有三种样式:solid(纯色)、grid(网格)、checker(棋盘格)。每种样式一条独立的渲染路径。

"三条路径," Riku 对自己说,"三条路,三个坑。"


三条路

样式技术路径问题
solidStandardMaterial.diffuseColor
gridGridMaterial(Babylon.js 独立 shader)WebGL shader 编译延迟导致首次渲染变纯色;重启后才恢复
checkercanvas 128×128 → toDataURL()TextureStandardMaterialcanvas 分辨率低、toDataURL 编码可能异步、常被 opacityTexture 遮挡导致不可见

"grid 的问题是 shader 编译延迟," Riku 对 Jieling 说,"第一次切换到 grid 样式,地面会变成纯色。要等 shader 编译完,重启应用才能恢复。"

"checker 的问题呢?"

"checker 的 canvas 只有 128×128 像素," Riku 说,"分辨率太低,棋盘格模糊。而且 toDataURL 是异步的,可能在渲染时还没准备好。"

"所以要统一?"

"对," Riku 说,"三条路合并成一条。"


统一

Riku 打开 ADR-091 的文档,标题是「地面纹理统一 —— 4 种样式合并为单一 canvas + StandardMaterial 路径」。

核心思路:所有 flat 样式都用 canvas 绘制纹理,然后作为 StandardMaterial.diffuseTexture 应用。

typescript
function _generateGroundTexture(state: GroundState, scene: Scene): Texture {
    const canvas = document.createElement('canvas');
    canvas.width = 512;
    canvas.height = 512;
    const ctx = canvas.getContext('2d')!;
    
    // 根据 groundStyle 绘制
    switch (state.groundStyle) {
        case 'solid':
            ctx.fillStyle = state.groundColor;
            ctx.fillRect(0, 0, 512, 512);
            break;
        case 'grid':
            ctx.fillStyle = state.groundColor;
            ctx.fillRect(0, 0, 512, 512);
            ctx.strokeStyle = state.groundLineColor;
            ctx.lineWidth = 2;
            // 画网格
            for (let i = 0; i <= 512; i += state.tileSize) {
                ctx.beginPath();
                ctx.moveTo(i, 0);
                ctx.lineTo(i, 512);
                ctx.stroke();
                ctx.beginPath();
                ctx.moveTo(0, i);
                ctx.lineTo(512, i);
                ctx.stroke();
            }
            break;
        case 'checker':
            // 画棋盘格
            break;
    }
    
    const texture = new Texture(canvas.toDataURL(), scene);
    return texture;
}

"512×512 像素," Riku 说,"比 checker 的 128×128 清晰四倍。"

"GridMaterial 呢?" Jieling 问。

"删掉," Riku 说,"不再需要。GridMaterial 是 Babylon.js 的独立 shader,编译慢,还有延迟问题。用 canvas 画网格,效果一样,没有 shader 编译问题。"


删除

Riku 打开 package.json,删除了 @babylonjs/materials 依赖。

"这个包只提供 GridMaterial," 他说,"删掉它,bundle 体积减小 50KB。"

他跑了一遍构建。通过。

打开应用,切换到 grid 样式。地面立刻显示网格,没有延迟。

"现在呢?"

"现在它即时生效。"


尾声

Riku 提交了代码。

feat: 地面纹理统一(ADR-091)— 删除 GridMaterial,所有 flat 样式走 canvas 路径

他站在窗边,看着远处的天际线。七月的阳光已经落下去了,路灯一盏一盏亮起来。

地面从三条路变成了一条路。路变宽了,坑填平了。

"地面是城市的地基," Riku 对自己说,"地基稳了,城市才能站稳。"


教训:渲染路径不是越多越好。三条独立路径意味着三倍的维护成本、三倍的 bug 概率。统一为一条路径,用 canvas 绘制所有样式,是最简单、最可靠的方案。