抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

Marching Cubes

Marching可以理解为一种循环

步进正方形(Marching Cubes)是一种非常常用的构建三角形网格的算法,在三维空间中均匀摆放正方形,循环遍历这些正方形,插值出三角形表面

Marching Cubes每个顶点有两个参数,顶点位置和权重(SDF)

MarchingCubes

MarchingCubes2

Unity显示三角形网格

注意!Unity拼装Mesh时,要先设置vertices,再设置triangles(尤其是在使用SetIndices接口,而非直接改mesh成员的方式),因为Unity在修改triangles时会对内部的信息做一次合法性检测,如果此时vertices是空的,就会报越界的错

// 构建一个Mesh,填充Vertex Buffer和Index Buffer
Mesh constructMesh = new Mesh();
constructMesh.vertices = verts; // 这里的vertices仅有positionOS
constructMesh.triangles = tris; // 一个int数组,每三个组成一个三角形,内容是vertices的索引,于是一般情形下远多于三倍的vertices数量
constructMesh.RecalculateNormals(); // 重建法线(应该是对面法线求平均值)
// 替换MeshFilter的sharedMesh
meshFilter.sharedMesh = constructMesh;

Unity Compute Shader

// 创建一个Buffer
ComputeBuffer buffer = new ComputeBuffer(count, stride, type);
  • stride是Buffer内每个元素的大小,注意CPU和Shader中定义要一致
  • type是Buffer的类型
    • AppendStructuredBuffer
    • RWStructuredBuffer

AppendStructuredBuffer

有些像一个总容量固定的vector,在使用时需要提前分配一个足够大的总容量

// 在CPU端设置有效容量
_trianglesBuffer.SetCounterValue(0);
// 在CPU端获取当前有效容量
int ReadTriangleCount() {
int[] triCount = { 0 };
ComputeBuffer.CopyCount(_trianglesBuffer, _trianglesCountBuffer, 0);
_trianglesCountBuffer.GetData(triCount);
return triCount[0];
}
AppendStructuredBuffer<Triangle> _Triangles;

[numthreads(numThreads, numThreads, numThreads)]
void March(uint3 id : SV_DispatchThreadID)
{
// 在GPU端在Buffer尾部添加新元素
_Triangles.Append(tri);
}

构建Marching Cubes

  • 构建一个立方体Grids
  • 生成SDF
  • 根据SDF获得CubeIndex
  • 使用CubeIndex从LUT中读取边的数组
  • 从相邻三个边插值出三角形三个点的顶点坐标

这里生成的vertex buffer数量和index buffer相同,是全展的,存在性能浪费

int edges[] = triTable[cubeIndex];

for (int i = 0; edges[i] != -1; i += 3)
{
// First edge lies between vertex e00 and vertex e01
int e00 = edgeConnections[edges[i]][0];
int e01 = edgeConnections[edges[i]][1];

// Second edge lies between vertex e10 and vertex e11
int e10 = edgeConnections[edges[i + 1]][0];
int e11 = edgeConnections[edges[i + 1]][1];

// Third edge lies between vertex e20 and vertex e21
int e20 = edgeConnections[edges[i + 2]][0];
int e21 = edgeConnections[edges[i + 2]][1];
Triangle tri;
tri.a = interp(cornerOffsets[e00], cubeValues[e00], cornerOffsets[e01], cubeValues[e01]) + id;
tri.b = interp(cornerOffsets[e10], cubeValues[e10], cornerOffsets[e11], cubeValues[e11]) + id;
tri.c = interp(cornerOffsets[e20], cubeValues[e20], cornerOffsets[e21], cubeValues[e21]) + id;
_Triangles.Append(tri);
}

marchingCube效果

参考

Marching Cubes

评论