Greedy Meshing: 体素贪心网格化算法

Greedy Meshing 是体素游戏(Minecraft 类)的事实标准网格化算法,将共面且同材质的相邻体素面合并为最大可能的矩形,从而减少渲染的三角形数量。

算法原理

核心思想来自 Mikola Lysenko 在 0fps.net 的经典文章。算法按以下顺序扫描和合并:

顺序:从上→下,左→右
每个未被覆盖的面 → 取最宽可能的 quad → 尽量向上延伸高度

Jason Gedge 的动画视觉化展示了这一过程:在每个未被覆盖的位置,算法会尝试水平扩展宽度,然后在该宽度基础上垂直扩展高度,直到不能再合并为止。

性能对比

算法速度输出质量典型场景
Naive极快最差(6面/体素)< 1000 体素的编辑器预览
Face Culling很快一般(仅表面面)实时更新频繁的场景
Greedy~3× 耗时最优(球形数据减面 67%)体素地形、Minecraft 类游戏
Marching Cubes中等平滑表面(大量小三角)医疗可视化、洞穴地形

block-mesh 库的实测数据:

  • visible_block_faces:单核 ~4000万 quad/秒(2.5 GHz Intel i7)
  • greedy_quads:约 3× 耗时,但输出 quad 数量约为球形数据的 1/3

Rust 实现

block-mesh 库

bonsairobo/block-mesh-rs 是体素网格化的事实标准库,被 126+ downstream 仓库使用。

核心 trait 系统:

  • Voxel — 定义可见性(Empty / Opaque / Translucent)
  • MergeVoxel — 定义合并等价性(材质、颜色等)
  • ndshape::ConstShape — 编译时 3D 数组形状,支持 padding

典型代码模式(含 1-voxel boundary padding):

use block_mesh::ndshape::{ConstShape, ConstShape3u32};
use block_mesh::{greedy_quads, GreedyQuadsBuffer, MergeVoxel, Voxel, VoxelVisibility, RIGHT_HANDED_Y_UP_CONFIG};
 
type ChunkShape = ConstShape3u32<18, 18, 18>; // 16³ + 1 padding each side
let mut buffer = GreedyQuadsBuffer::new(voxels.len());
 
greedy_quads(
    &voxels, &ChunkShape {},
    [0; 3], [17; 3],           // 迭代范围(排除 padding)
    &RIGHT_HANDED_Y_UP_CONFIG.faces,
    &mut buffer
);

bevy_voxel_world 的内部实现

bevy_voxel_world 使用类似 greedy 的面合并策略,但在 Bevy Task Pool 中并行执行,支持运行时增量更新而无需重新生成整个 mesh。

关键细节

与 Ambient Occlusion 的兼容性

合并面时需要考虑 AO 计算。如果两个相邻体素面的顶点 AO 值不同,它们不能被合并。这会降低 greedy 的有效性。

Binary Greedy Meshing(优化变种)

block-mesh-bgm 提供了基于二进制掩码的快速 greedy mesher,通过 bitwise 测试替换逐体素比较,适合高性能场景。

相关页面