You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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,会导致后续索引读取混乱。当立方体数量增加时,错误不断累积,最终让三角形指向完全错误的顶点位置,表现为渲染位置随机。

修复步骤

  1. 修正循环增量:将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步,匹配三角表的结构
    }
}
  1. 完善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;
}
  1. 验证triTable结构:确认你的triTable数组符合标准Marching Cubes定义——每个立方体配置对应16个元素,每3个连续元素为一个三角形的边索引,遇到-1则表示当前配置下没有更多三角形。

内容的提问来源于stack exchange,提问作者JimMcTim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 07:33:52