行进立方体未创建预期的网格

Posted

技术标签:

【中文标题】行进立方体未创建预期的网格【英文标题】:Marching cubes not creating expected meshes 【发布时间】:2020-10-10 19:38:44 【问题描述】:

我一直在尝试使用 c# 实现统一的行进立方体,但是正在创建的网格都具有 90 度的旋转。

在这个例子中,我试图创建一个立方体。

这是我当前的代码,如果有人能找出问题所在,那将非常感谢。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(MeshFilter))]
public class train : MonoBehaviour

    //setup e.g varables and lists
    //----------------------------------------------------------------------------------------------------
    //size of the chunk
    public int size = 10;
    //binary stuff
    public List<int> binary = new List<int>();
    int bitewisenum = 0;
    //posithions
    public static Vector3 xyz = new Vector3();
    public Vector3 list_edges = new Vector3();
    //how much air      the cut off point bettween air and solid  0.45 - 0.55 works best
    public float dencity = 0.4f;
    //mesh
    public Vector3[] vertices;
    public List<Vector3> vertices_list = new List<Vector3>();
    public List<Vector3> vertices_list_store = new List<Vector3>();
    public List<Vector3> inverlist = new List<Vector3>();
    //we can convert it back to an array later 
    public List<int> tri = new List<int>();
    Mesh mesh;
    private int[] num;
    private float airsolid_test;
    public float cutoff; // 11 works best
  
    //perlin noise
    //---------------------------------------------------------------------------------------------------
    public static float Perlin3D(float x, float y, float z, float cut)
    
        //float AB = Mathf.PerlinNoise(x, y);
        //float BC = Mathf.PerlinNoise(y, z);
        //float AC = Mathf.PerlinNoise(x, z);
        //
        //
        //float BA = Mathf.PerlinNoise(y, x);
        //float CB = Mathf.PerlinNoise(z, y);
        //float CA = Mathf.PerlinNoise(z, x);
        //
        ////get the avarge
        //float ABC = AB + BC + AC + BA + CB + CA;
        //float per = ABC / 6f;
        //if (y > cut)
        //
        //    per = Mathf.Pow(per * (y / 8.5f), 2.718f) + 0.3f;
        //

        //testing
        float per;
        if (x >= cut)
        
            per = 0f;
         else if (y >= cut)
        
            per = 0f;
        
        else if (z <= 0)
        
            per = 0f;
        
        else if (x <= 0)
        
            per = 0f;
        
        else if (z >= cut)
        
            per = 0f;
        
        else if (y <= 0)
        
            per = 0f;
        else
        
            per = 10f;
        
        //testing ends
        return per;
    
    //----------------------------------------------------------------------------------------
    private void Start()
    
        //set up binary
        binary.Add(1);
        binary.Add(2);
        binary.Add(4);
        binary.Add(8);
        binary.Add(16);
        binary.Add(32);
        binary.Add(64);
        binary.Add(128);

        //setup mesh
        mesh = new Mesh();
        GetComponent<MeshFilter>().mesh = mesh;
        tri.Clear();

        //testing --------------------------------------
        airsolid_test = dencity;
        //0.1 is because of the perlin noise
        for (float x = 0.1f; x < 16; x++)
        
            for (int y = 0; y < 15; y++)
            
                for (int z = 0; z < 15; z++)
                
                    //airsolid_test = dencity;
                    //if (y >= cutoff)
                    ////mountans
                    //    airsolid_test += 0.0f;//0.2f
                    //
                    //else
                    ////caves
                    //    airsolid_test -= 0.005f;//0.005
                    //
                    xyz.x = x;
                    xyz.y = y;
                    xyz.z = z;
                    createshape(x, y, z);
                    upmesh();
                
            
        
    
    //xyz.x = x;
    // xyz.y = y;
    // xyz.z = z;
    // createshape(x, y, z);
    //upmesh();
    //upmesh stands for update mesh
    void upmesh()
    
        mesh.Clear();
        mesh.vertices = vertices;
        mesh.triangles = tri.ToArray();
        mesh.RecalculateNormals();
    


    //-------------------------------------------------------------------------------------

    // this is the main function and you give it an xyz cordanit and it sets the mesh's triangles and veticeys
    void createshape(float x, float y, float z)
    
        //list for the binary
        List<int> bite = new List<int>();
        bite.Clear();
        bitewisenum = 0;



        //this is getting the binay representation for each point on the cube if the point is > the density value store it as a 1 else as a 0 
        // so we end up with a binary number like 10011101
        //position 7
        if (Perlin3D(x + 1, y, z + 1, cutoff) > airsolid_test)
        
            bite.Add(1);
            //these store the value for intertopilation later but im not using it yet
            float Pose_7 = Perlin3D(x + 1, y, z + 1,cutoff);
        
        else
        
            bite.Add(0);
        
        //position 6
        if (Perlin3D(x + 1, y + 1, z + 1, cutoff) > airsolid_test)
        
            bite.Add(1);
            float Pose_6 = Perlin3D(x + 1, y + 1, z + 1, cutoff);
        
        else
        
            bite.Add(0);
        
        //position 5
        if (Perlin3D(x, y + 1, z + 1, cutoff) > airsolid_test)
        
            bite.Add(1);
            float Pose_5 = Perlin3D(x, y + 1, z + 1, cutoff);
        
        else
        
            bite.Add(0);
        
        //position 4
        if (Perlin3D(x, y, z + 1, cutoff) > airsolid_test)
        
            bite.Add(1);
            float Pose_4 = Perlin3D(x, y, z + 1, cutoff);
        
        else
        
            bite.Add(0);
        
        //position 3
        if (Perlin3D(x + 1, y, z, cutoff) > airsolid_test)
        
            bite.Add(1);
            float Pose_3 = Perlin3D(x + 1, y, z, cutoff);
        
        else
        
            bite.Add(0);
        
        //position 2
        if (Perlin3D(x + 1, y + 1, z, cutoff) > airsolid_test)
        
            bite.Add(1);
            float Pose_2 = Perlin3D(x + 1, y + 1, z, cutoff);
        
        else
        
            bite.Add(0);
        
        //position 1
        if (Perlin3D(x, y + 1, z, cutoff) > airsolid_test)
        
            bite.Add(1);
            float Pose_1 = Perlin3D(x, y + 1, z, cutoff);
        
        else
        
            bite.Add(0);
        
        //position 0
        if (Perlin3D(x, y, z, cutoff) > airsolid_test)
        
            bite.Add(1);
            float Pose_0 = Perlin3D(x, y, z, cutoff);
        
        else
        
            bite.Add(0);
        



        //convert binary in to decimal because i dont know an easy way to do this but
        //loop throught all items in the binary list and change them
        for (int i = 0; i <= 7; i++)
        
            if (bite[i] == 1)
            
                bitewisenum += binary[i];
            
        
        //print(bitewisenum);

        //check if its not all air or inside an object
        //this means that we check if its 0 or 255
        //now we need to make the mesh and show it
        if (bitewisenum != 0 && bitewisenum != 255)
        
            //Debug.Log("made a mesh");
            //store the int array for easyer use
            int[] trian = table.TriangleTable[bitewisenum];
            /*
             * at this point the int array describes edges not postions
             * and we need to change that so what we do is loop through ever item in the list and
             * parce it through a function(table.transform_to_postion) this returns a Vector 3
             * which we then add to a list
             */
            vertices_list.Clear();
            for (int num = 0; num < trian.Length; num++)
            
                //get the actule postions
                //we give the function a edge index as an int which represents a edge index and it gives you the actule postion back as a vector 3
                list_edges = transform_to_postion(trian[num]);

                //add them to the list
                vertices_list.Add(list_edges);
                vertices_list_store.Add(list_edges);
                //end of the for loop
            
            // set vetaceys
            vertices = vertices_list_store.ToArray();
            //

            //setting the triangles based off how many items there are on the verticeys list
            if (vertices_list.Count / 3 == 1)
            
                for (int i = 1; i < 4; i++)
                
                    tri.Add(tri.Count);
                
            
            else if (vertices_list.Count / 3 == 2)
            
                for (int i = 1; i < 7; i++)
                
                    tri.Add(tri.Count);
                
            
            else if (vertices_list.Count / 3 == 3)
            
                for (int i = 1; i < 10; i++)
                
                    tri.Add(tri.Count);
                
            
            else if (vertices_list.Count / 3 == 4)
            
                for (int i = 1; i < 13; i++)
                
                    tri.Add(tri.Count);
                
            
            else if (vertices_list.Count / 3 == 5)
            
                for (int i = 1; i < 16; i++)
                
                    tri.Add(tri.Count);
                
            
            /*
            Debug.Log("the legnth of verticys: "+vertices.Length);                                                                                                    
            Debug.Log("the legnth of tri: "+tri.Length);
            Debug.Log("tri legnth  " + tri.Length);
            end of the if loop
            */
        

        //end of the function                                                                                
    

    public static Vector3 transform_to_postion(int number_edge)
    

        Vector3 xyz_of_edge = new Vector3();
        //check which one it is and then set the xyz
        if (number_edge == 0)
        
            xyz_of_edge.x = xyz.x + 0.5f;
            xyz_of_edge.y = xyz.y;
            xyz_of_edge.z = xyz.z + 1f;
        
        else if (number_edge == 1)
        
            xyz_of_edge.x = xyz.x + 1f;
            xyz_of_edge.y = xyz.y;
            xyz_of_edge.z = xyz.z + 0.5f;
        
        else if (number_edge == 2)
        
            xyz_of_edge.x = xyz.x + 0.5f;
            xyz_of_edge.y = xyz.y;
            xyz_of_edge.z = xyz.z;
        
        else if (number_edge == 3)
        
            xyz_of_edge.x = xyz.x;
            xyz_of_edge.y = xyz.y;
            xyz_of_edge.z = xyz.z + 0.5f;
        
        else if (number_edge == 4)
        
            xyz_of_edge.x = xyz.x + 0.5f;
            xyz_of_edge.y = xyz.y + 1f;
            xyz_of_edge.z = xyz.z + 1f;
        
        else if (number_edge == 5)
        
            xyz_of_edge.x = xyz.x + 1f;
            xyz_of_edge.y = xyz.y + 1f;
            xyz_of_edge.z = xyz.z + 0.5f;
        
        else if (number_edge == 6)
        
            xyz_of_edge.x = xyz.x + 0.5f;
            xyz_of_edge.y = xyz.y + 1f;
            xyz_of_edge.z = xyz.z;
        
        else if (number_edge == 7)
        
            xyz_of_edge.x = xyz.x;
            xyz_of_edge.y = xyz.y + 1;
            xyz_of_edge.z = xyz.z + 0.5f;
        
        else if (number_edge == 8)
        
            xyz_of_edge.x = xyz.x;
            xyz_of_edge.y = xyz.y + 0.5f;
            xyz_of_edge.z = xyz.z + 1f;
        
        else if (number_edge == 9)
        
            xyz_of_edge.x = xyz.x + 1f;
            xyz_of_edge.y = xyz.y + 0.5f;
            xyz_of_edge.z = xyz.z + 1f;
        
        else if (number_edge == 10)
        
            xyz_of_edge.x = xyz.x + 1f;
            xyz_of_edge.y = xyz.y + 0.5f;
            xyz_of_edge.z = xyz.z;
        
        else if (number_edge == 11)
        
            xyz_of_edge.x = xyz.x;
            xyz_of_edge.y = xyz.y + 0.5f;
            xyz_of_edge.z = xyz.z;
        
        //Debug.Log("edge index " + number_edge);
        //Debug.Log("edges "+xyz_of_edge);
        //Debug.Log(xyz_of_edge);
        return xyz_of_edge;
    

【问题讨论】:

从您的屏幕截图中猜测,您的 Z 轴和 Y 轴已调换(交换)。 我尝试交换 Z 轴和 Y 轴,但这只是在不同的轴上导致了同样的问题。 【参考方案1】:

我发现问题在于我标记立方体点的方式。我把三角测量表弄错了,这导致了方向错误。 为了解决这个问题,我所做的只是在我的代码中重新定义了指向实际值的点。

【讨论】:

以上是关于行进立方体未创建预期的网格的主要内容,如果未能解决你的问题,请参考以下文章

估计行进立方体输出几何的大小

行进立方体等值

行进立方体 - 获得倾斜的表面

在 Three.js 中基于局部向量定位子网格

unity---Mesh网格编程

unity---Mesh网格编程