Marching Cubes算法渲染异常:n个立方体后位置随机偏移
问题:Marching Cubes算法渲染异常,超过N个立方体后位置随机
我实现了Marching Cubes算法,在渲染前N个立方体时一切正常(N的大小取决于渲染区域尺寸),但第N个之后的所有立方体都会被渲染到看似随机的位置。小尺度场景下运行正常,立方体的坐标数据看起来没问题。示意图中的节点表示多边形应该绘制的位置,求帮助!
渲染代码
void Update() { List<Vector3> vertices = new List<Vector3>(); List<int> triangles = new List<int>(); int numCubesRendered = 0; // 记录已渲染的立方体数量,用于索引计算 foreach (Cube cube in createPoints.cubeHandler.cubeList) { short cubeBinary = CalculateBinaryCubeIndex(cube); // 示例:1000 0000 0000 1100 表示边2、3、15被相交 /* 遍历所有可能的边,根据三角表添加需要的三角形 */ for (int i = 0; i < 16; i++) { if (triTable[cubeBinary, i] != -1) // triTable是存储所有立方体配置的数组 { // 按顺时针顺序添加三角形,避免背面剔除错误 triangles.Add(triTable[cubeBinary, i + 2] + (numCubesRendered * 12)); triangles.Add(triTable[cubeBinary, i + 1] + (numCubesRendered * 12)); triangles.Add(triTable[cubeBinary, i] + (numCubesRendered * 12)); i += 2; } } // 遍历立方体的所有边,生成顶点 for (int j = 0; j < 12; j++) { // 获取边的两个端点索引 int indexA = cornerIndexFromEdge[j, 0]; int indexB = cornerIndexFromEdge[j, 1]; Vector3 vertexPos = (cube.vertices[indexA].GetPosition() + cube.vertices[indexB].GetPosition()) / 2; vertices.Add(vertexPos); } ++numCubesRendered; } drawTriangles(vertices, triangles); } // 通过二进制计算立方体配置的索引,用一个short表示所有顶点的表面状态 public short CalculateBinaryCubeIndex(Cube cube) { short cubeIndex = 0; float surfaceRange = createPoints.surfaceRange; if (cube.vertices[0].surfaceLevel >= surfaceRange) cubeIndex |= 1; if (cube.vertices[1].surfaceLevel >= surfaceRange) cubeIndex |= 2; if (cube.vertices[2].surfaceLevel >= surfaceRange) cubeIndex |= 4; if (cube.vertices[3].surfaceLevel >= surfaceRange) cubeIndex |= 8; if (cube.vertices[4].surfaceLevel >= surfaceRange) cubeIndex |= 16; if (cube.vertices[5].surfaceLevel >= surfaceRange) cubeIndex |= 32; if (cube.vertices[6].surfaceLevel >= surfaceRange) cubeIndex |= 64; if (cube.vertices[7].surfaceLevel >= surfaceRange) cubeIndex |= 128; /* 立方体完全在表面外/内,无需生成三角形 */ if (edgeTable[cubeIndex] == 0) return 0; return cubeIndex; } public Mesh drawTriangles(List<Vector3> vertices, List<int> triangles) { Mesh mesh = new Mesh(); mesh = GetComponent<MeshFilter>().mesh; mesh.vertices = vertices.ToArray(); mesh.triangles = triangles.ToArray(); return mesh; }
问题分析与修复
核心错误
三角形索引循环的增量逻辑错误:标准Marching Cubes的triTable是每3个连续元素定义一个三角形,但代码中处理完一组三角形后执行i += 2,会导致后续索引读取混乱。当立方体数量增加时,错误不断累积,最终让三角形指向完全错误的顶点位置,表现为渲染位置随机。
修复步骤
- 修正循环增量:将
i += 2改为i += 3,确保每次处理完一个三角形的3个索引后,跳转到下一组三角形的起始位置:
for (int i = 0; i < 16; i++) { if (triTable[cubeBinary, i] != -1) { triangles.Add(triTable[cubeBinary, i + 2] + (numCubesRendered * 12)); triangles.Add(triTable[cubeBinary, i + 1] + (numCubesRendered * 12)); triangles.Add(triTable[cubeBinary, i] + (numCubesRendered * 12)); i += 3; // 修正为每次跳3步,匹配三角表的结构 } }
- 完善Mesh更新:在
drawTriangles方法中添加法线和边界计算,确保光照和渲染区域正确:
public Mesh drawTriangles(List<Vector3> vertices, List<int> triangles) { Mesh mesh = GetComponent<MeshFilter>().mesh; mesh.Clear(); // 先清空旧数据,避免残留问题 mesh.vertices = vertices.ToArray(); mesh.triangles = triangles.ToArray(); mesh.RecalculateNormals(); // 重新计算法线,保证光照显示正确 mesh.RecalculateBounds(); // 重新计算边界,保证相机能正确裁剪渲染区域 return mesh; }
- 验证triTable结构:确认你的
triTable数组符合标准Marching Cubes定义——每个立方体配置对应16个元素,每3个连续元素为一个三角形的边索引,遇到-1则表示当前配置下没有更多三角形。
内容的提问来源于stack exchange,提问作者JimMcTim
相关产品推荐
相关产品推荐

