行进立方体在网格中生成孔

Marching Cubes generating holes in mesh

提问人:Statey 提问时间:6/26/2017 最后编辑:HarrYStatey 更新时间:8/1/2023 访问量:3852

问:

我正在Unity中开发Marching Cubes实现。我的代码基于 Paul Bourke 的代码,实际上进行了大量修改,但无论如何,我正在检查某个位置的块是否为 null,如果它是空的,则在其上放置调试纹理。

Here is an image of the problem

这是我的MC脚本。

    public class MarchingCubes
{
private World world;
private Chunk chunk;
private List<Vector3> vertices = new List<Vector3> ();
private List<Vector3> normals = new List<Vector3> ();
private Vector3[] ns;
private List<int> triangles = new List<int> ();
private List<Vector2> uvs = new List<Vector2> ();
private Vector3[] positions = new Vector3[8];
private float[] corners = new float[8];
private Vector3i size = new Vector3i (16, 128, 16);

Vector3[] vertlist = new Vector3[12];

private float isolevel = 1f;

private float Corner (Vector3i pos)
{
    int x = pos.x;
    int y = pos.y;
    int z = pos.z;
    if (x < size.x && z < size.z) {
        return chunk.GetValue (x, y, z);
    } else {
        int ix = chunk.X, iz = chunk.Z;
        int rx = chunk.region.x, rz = chunk.region.z;
        if (x >= size.x) {
            ix++;
            x = 0;
        }

        if (z >= size.z) {
            iz++;
            z = 0;
        }
        return chunk.region.GetChunk (ix, iz).GetValue (x, y, z);
    }
}

Block block;

public Mesh MarchChunk (World world, Chunk chunk, Mesh mesh)
{
    this.world = world;
    this.chunk = chunk;

    vertices.Clear ();
    triangles.Clear ();
    uvs.Clear ();

    for (int x = 0; x < size.x; x++) {
        for (int y = 1; y < size.y - 2; y++) {
            for (int z = 0; z < size.z; z++) {

                block = chunk.GetBlock (x, y, z);
                int cubeIndex = 0;

                for (int i = 0; i < corners.Length; i++) {
                    corners [i] = Corner (new Vector3i (x, y, z) + offset [i]);
                    positions [i] = (new Vector3i (x, y, z) + offset [i]).ToVector3 ();

                    if (corners [i] < isolevel)
                        cubeIndex |= (1 << i);
                }

                if (eTable [cubeIndex] == 0)
                    continue;

                for (int i = 0; i < vertlist.Length; i++) {
                    if ((eTable [cubeIndex] & 1 << i) == 1 << i)
                        vertlist [i] = LinearInt (positions [eCons [i, 0]], positions [eCons [i, 1]], corners [eCons [i, 0]], corners [eCons [i, 1]]);
                }

                for (int i = 0; triTable [cubeIndex, i] != -1; i += 3) {
                    int index = vertices.Count;

                    vertices.Add (vertlist [triTable [cubeIndex, i]]);
                    vertices.Add (vertlist [triTable [cubeIndex, i + 1]]);
                    vertices.Add (vertlist [triTable [cubeIndex, i + 2]]);

                    float tec = (0.125f);
                    Vector2 uvBase = block != null ? block.UV : new Vector2 ();

                    uvs.Add (uvBase);
                    uvs.Add (uvBase + new Vector2 (0, tec));
                    uvs.Add (uvBase + new Vector2 (tec, tec));
                                    
                    triangles.Add (index + 0);
                    triangles.Add (index + 1);
                    triangles.Add (index + 2);
                }
            }
        }
    }       

    if (mesh == null)
        mesh = new Mesh ();
    mesh.Clear ();
    mesh.vertices = vertices.ToArray ();
    mesh.triangles = triangles.ToArray ();
    mesh.uv = uvs.ToArray ();
    mesh.RecalculateNormals ();
    return mesh;
}

bool IsBitSet (int b, int pos)
{
    return ((b & pos) == pos);
}

Vector3 LinearInt (Vector3 p1, Vector3 p2, float v1, float v2)
{
    Vector3 p;
    p.x = p1.x + (isolevel - v1) * (p2.x - p1.x) / (v2 - v1);
    p.y = p1.y + (isolevel - v1) * (p2.y - p1.y) / (v2 - v1);
    p.z = p1.z + (isolevel - v1) * (p2.z - p1.z) / (v2 - v1);
    return p;
}

private static int[,] eCons = new int[12, 2] {
    { 0, 1 },
    { 1, 2 },
    { 2, 3 },
    { 3, 0 },
    { 4, 5 },
    { 5, 6 },
    { 6, 7 },
    { 7, 4 },
    { 0, 4 },
    { 1, 5 },
    { 2, 6 },
    { 3, 7 }
};

private static Vector3i[] offset = new Vector3i[8] {
    new Vector3i (0, 0, 1),
    new Vector3i (1, 0, 1),
    new Vector3i (1, 0, 0),
    new Vector3i (0, 0, 0),
    new Vector3i (0, 1, 1),
    new Vector3i (1, 1, 1),
    new Vector3i (1, 1, 0),
    new Vector3i (0, 1, 0)
};
  }

我没有把这些表放在示例中,因为它们与 Bourke 代码中的表相同。

编辑: 我发现蓝色三角形处的单元格值为 0,因此不必对它们进行三角测量,但它们下方的单元格值为 1,因此会创建一个顶部三角形来完成网格。

C# unity-game-engine 行进立方体

评论

7赞 Jeroen van Langen 6/26/2017
它看起来像一个表格问题,因为它总是一样的。我已经看到位 6 和 7 在下表中交换的实现: 请看这一行: WEBGL_Marchingcubes of threejs.org我注意到了这一点,因为我正在使用 geometryshader 在 GPU 上进行实现)cubeIndexif (grid.val[6] < isolevel) cubeindex |= 128; if (grid.val[7] < isolevel) cubeindex |= 64;
11赞 Martin Liversage 6/26/2017
也许无关紧要,但这里是:原始算法存在一个缺陷,可能导致生成的网格中出现漏洞。很多年前,我写了一篇关于这个问题的论文。我还写了一篇硕士论文(丹麦语),其中我谈到了这个问题。我试图在我的论文的第 81 页进行说明。在第 87 页上,您可以看到所有可能的网格,其中麻烦的网格标有 *。
2赞 Statey 6/26/2017
好的,我会试试这个,一旦我得到一些东西,我就会告诉你。
0赞 Statey 6/26/2017
所以@JeroenvanLangen这是交错的,但由于特定顶点索引处的非有限值,它给了我错误
4赞 Martin Liversage 6/27/2017
@Statey:我不确定你遇到的问题是否是原始算法中的歧义造成的,所以我不能给你具体的建议。但是,处理带孔的立方体网格问题的策略是对立方体模糊边的中心(或模糊立方体的中心)进行插值,以确定插值点应位于等值面内部还是外部。然后,这用于创建正确的等值面网格,并且由于对所有立方体的决策都是确定性的,因此网格将连接起来,没有孔。

答: 暂无答案