Unity利用代码生成空心立方体(立方体挖走一个圆柱)

先看效果

还未生成mesh时挖去圆柱的立方体

 

生成mesh后挖去圆柱的立方体

放代码为敬(脚本挂在空物体上即可):

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

[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class body : MonoBehaviour
{
    //the outside radius must lager than the inside one
    [Range(0, 100)] public float innerRadius;
    [Range(1, 100)] public float outsideRadius;
    [Range(1, 100)] public float outsideRadius1;
    public int blockCounts = 80;          //how many blocks that the obj will be split into?
    public float height = 10;             //the height of the obj.
    
    private float increment;
    private float currentAngle = 0;

    private MeshFilter meshFilter;

    void Start()
    {
        meshFilter = transform.GetComponent<MeshFilter>();

        GenerateMesh();

        //show the order we generate the obj.
        StartCoroutine(SequenceTest());

    }

    private void GenerateMesh()
    {
        //declare all the array we need
        List<Vector3> vertices = new List<Vector3>();
        List<Vector2> uvs = new List<Vector2>();
        List<int> triangles = new List<int>();

        //initialize the parameters
        increment = 2 * Mathf.PI / blockCounts;
        
        //Generate the vertex we need
        vertices = GenerateVertics();
        //Fill the triangles in order
        triangles = FillTriangles(vertices.Count);

        meshFilter.mesh.vertices = vertices.ToArray();
        meshFilter.mesh.triangles = triangles.ToArray();

    }

    private List<Vector3> GenerateVertics()
    {
        //The order to Generate the vertics :   choose the left bottom as the first point, and assign the id by clockwise, inside circle generate first
        //顶点标号顺序  : 以左下角为起点,以顺时针顺序给各顶点标号,从内层圆环开始

        List<Vector3> vertices = new List<Vector3>();

        //used to load the radius we have    [Use Array to help us expand the plies]
        float[] radiuses = { innerRadius, outsideRadius };
        float[] radiuses1 = { innerRadius, outsideRadius1 };
        
        //For now this code will generate the inner circle first
        for (int i = 0; i < radiuses.Length; i++)
        {
            if (i == 0)
            {
                for (int j = 0; j < blockCounts * 4; j += 4)
                {
                    //TODO : for now ,this script will generate 4 more vertices
                    Vector3 v1 = new Vector3(radiuses[i] * Mathf.Sin(currentAngle), 0, radiuses[i] * Mathf.Cos(currentAngle));
                    Vector3 v2 = new Vector3(radiuses[i] * Mathf.Sin(currentAngle), height, radiuses[i] * Mathf.Cos(currentAngle));
                    
                    //Generate next two vertices
                    currentAngle += increment;

                    Vector3 v3 = new Vector3(radiuses[i] * Mathf.Sin(currentAngle), height, radiuses[i] * Mathf.Cos(currentAngle));
                    Vector3 v4 = new Vector3(radiuses[i] * Mathf.Sin(currentAngle), 0, radiuses[i] * Mathf.Cos(currentAngle));
                    vertices.Add(v1);
                    vertices.Add(v2);
                    vertices.Add(v3);
                    vertices.Add(v4);
                }
            }
            int c = blockCounts / 4, k0 = c/2, k1 = 0, k2 = 0, k3 = 0, k4 = 0,k5 = 0;    //c = 10,正方形一个边有10个点位
            float deltaMeshdistance = radiuses1[1] / c;     //deltaMeshdistance = 3,相邻点位的距离
            if (i == 1)
            {
                if ((0.5 * c <= k0) && (k0 < c))
                {
                    for (int j = 0; j < blockCounts * 4; j += 4)
                    {
                        if ((0.5 * c <= k0) && (k0 < c))
                        {
                            Vector3 v1 = new Vector3(k5 * deltaMeshdistance, 0, radiuses1[i] / 2);
                            Vector3 v2 = new Vector3(k5 * deltaMeshdistance, height, radiuses1[i] / 2);
                            k0++;k5++;
                            Vector3 v3 = new Vector3(k5 * deltaMeshdistance, height, radiuses1[i] / 2);
                            Vector3 v4 = new Vector3(k5 * deltaMeshdistance, 0, radiuses1[i] / 2);
                            vertices.Add(v1);
                            vertices.Add(v2);
                            vertices.Add(v3);
                            vertices.Add(v4);
                        }
                    }
                }
                if ((c <= k0) && (k0 < 2 * c))
                {
                    for (int j = 0; j < blockCounts * 4; j += 4)
                    {
                        if ((c <= k0) && (k0 < 2 * c))
                        {
                            Vector3 v1 = new Vector3(radiuses1[i] / 2, 0, radiuses1[i] / 2 - k1 * deltaMeshdistance);
                            Vector3 v2 = new Vector3(radiuses1[i] / 2, height, radiuses1[i] / 2 - k1 * deltaMeshdistance);
                            k0++; k1++;
                            Vector3 v3 = new Vector3(radiuses1[i] / 2, height, radiuses1[i] / 2 - k1 * deltaMeshdistance);
                            Vector3 v4 = new Vector3(radiuses1[i] / 2, 0, radiuses1[i] / 2 - k1 * deltaMeshdistance);
                            vertices.Add(v1);
                            vertices.Add(v2);
                            vertices.Add(v3);
                            vertices.Add(v4);
                        }
                    }
                }
                if ((2 * c <= k0) && (k0 < 3 * c))
                {
                    for (int j = 0; j < blockCounts * 4; j += 4)
                    {
                        if ((2 * c <= k0) && (k0 < 3 * c))
                        {
                            Vector3 v1 = new Vector3(radiuses1[i] / 2 - k2 * deltaMeshdistance, 0, -radiuses1[i] / 2);
                            Vector3 v2 = new Vector3(radiuses1[i] / 2 - k2 * deltaMeshdistance, height, -radiuses1[i] / 2);
                            k0++;k2++;
                            Vector3 v3 = new Vector3(radiuses1[i] / 2 - k2 * deltaMeshdistance, height, -radiuses1[i] / 2);
                            Vector3 v4 = new Vector3(radiuses1[i] / 2 - k2 * deltaMeshdistance, 0, -radiuses1[i] / 2);
                            vertices.Add(v1);
                            vertices.Add(v2);
                            vertices.Add(v3);
                            vertices.Add(v4);
                        }
                    }
                }
                if ((3 * c <= k0) && (k0 < 4 * c))
                {
                    for (int j = 0; j < blockCounts * 4; j += 4)
                    {
                        if ((3 * c <= k0) && (k0 < 4 * c))
                        {
                            Vector3 v1 = new Vector3(-radiuses1[i] / 2, 0, -radiuses1[i] / 2 + k3 * deltaMeshdistance);
                            Vector3 v2 = new Vector3(-radiuses1[i] / 2, height, -radiuses1[i] / 2 + k3 * deltaMeshdistance);
                            k0++;k3++;
                            Vector3 v3 = new Vector3(-radiuses1[i] / 2, height, -radiuses1[i] / 2 + k3 * deltaMeshdistance);
                            Vector3 v4 = new Vector3(-radiuses1[i] / 2, 0, -radiuses1[i] / 2 + k3 * deltaMeshdistance);
                            vertices.Add(v1);
                            vertices.Add(v2);
                            vertices.Add(v3);
                            vertices.Add(v4);
                        }
                    }
                }
                if ((4 * c <= k0) && (k0 < 4.5 * c))
                {
                    for (int j = 0; j < blockCounts * 4; j += 4)
                    {
                        if ((4 * c <= k0) && (k0 < 4.5 * c))
                        {
                            Vector3 v1 = new Vector3(-radiuses1[i] / 2 + k4 * deltaMeshdistance, 0, radiuses1[i] / 2);
                            Vector3 v2 = new Vector3(-radiuses1[i] / 2 + k4 * deltaMeshdistance, height, radiuses1[i] / 2);
                            k0++;k4++;
                            Vector3 v3 = new Vector3(-radiuses1[i] / 2 + k4 * deltaMeshdistance, height, radiuses1[i] / 2);
                            Vector3 v4 = new Vector3(-radiuses1[i] / 2 + k4 * deltaMeshdistance, 0, radiuses1[i] / 2);
                            vertices.Add(v1);
                            vertices.Add(v2);
                            vertices.Add(v3);
                            vertices.Add(v4);
                        }
                    }
                }
            }            
        }

        return vertices;
    }

    /// <summary>
    /// 填充三角形
    /// </summary>
    /// <param name="vertCount"></param>
    /// <returns></returns>
    private List<int> FillTriangles(int vertCount)  
    {       
        List<int> triangles = new List<int>();

        //1.fill the inner && outside surface 填充内外表面
        for (int i = 0; i < vertCount - 2; i += 2)
        {
            if (i == vertCount - 2 || i == vertCount - 1)     //connect with the origin points
            {
                triangles.AddRange(GetTriangleOrder(i, i + 1, i - (blockCounts - 2), i - (blockCounts - 3)));
            }
            else if (i < vertCount / 2)
            {
                //inner circle only needs to see the inside surface
                triangles.AddRange(GetTriangleOrder(i, i + 1, i + 2, i + 3));
            }
            else
            {
                //outside surface
                triangles.AddRange(GetTriangleOrder(i + 3, i + 2, i + 1, i));
            }
        }

        //2.fill the top && bottom surface  填充顶部和底部        
        for (int i = 0, j = vertCount / 2; i < vertCount / 2; i += 2, j += 2)   //i < 160
        {
            if (i >= vertCount / 2 - 2) //i >= 156, vertCount = 320
            {
                triangles.AddRange(GetTriangleOrder(0, vertCount / 2, j, i));   //123, 341  填充顶部
                triangles.AddRange(GetTriangleOrder(i + 1, j + 1, vertCount / 2 + 1, 1));   //填充底部
                //triangles.AddRange(GetTriangleOrder(1, 161, 318, 158));   //123, 341  填充顶部
                //triangles.AddRange(GetTriangleOrder(159, 319, 160, 0));   //填充底部                
            }
            else
            {
                triangles.AddRange(GetTriangleOrder(i + 3, j + 3, j, i));
                triangles.AddRange(GetTriangleOrder(i + 1, j + 1, j + 2, i + 2));
            }             
        }           
        return triangles;
    }

    private List<int> GetTriangleOrder(int p1, int p2, int p3, int p4)     //the input must be from the left bottom corner && sort by clockwise
    {
        //use this code to return a particular order

        List<int> output = new List<int>();

        //Add first triangle
        output.Add(p1);
        output.Add(p2);
        output.Add(p3);

        //Add the second one
        output.Add(p3);
        output.Add(p4);
        output.Add(p1);

        return output;
    }

    /// <summary>
    /// 协程,网格生成过程
    /// </summary>
    /// <returns></returns>
    IEnumerator SequenceTest()
    {
        float interval = 0.01f;
        Debug.Log(meshFilter.mesh.triangles.Length);
        for (int i = 0; i < meshFilter.mesh.triangles.Length; i += 3)
        {
            Debug.DrawLine(meshFilter.mesh.vertices[meshFilter.mesh.triangles[i]], meshFilter.mesh.vertices[meshFilter.mesh.triangles[i + 1]], Color.red, 100f);

            yield return new WaitForSeconds(interval);
            Debug.DrawLine(meshFilter.mesh.vertices[meshFilter.mesh.triangles[i + 1]], meshFilter.mesh.vertices[meshFilter.mesh.triangles[i + 2]], Color.yellow, 100f);

            yield return new WaitForSeconds(interval);
            Debug.DrawLine(meshFilter.mesh.vertices[meshFilter.mesh.triangles[i + 2]], meshFilter.mesh.vertices[meshFilter.mesh.triangles[i]], Color.blue, 100f);

            yield return new WaitForSeconds(interval);

        }
    }
}

我这里用到了协程,可以看到网格的生成过程,如果想直接看到结果,改动如下:

将第27行的
StartCoroutine(SequenceTest());
改为
SequenceTest();
再将SequenceTest()函数前的IEnumerator换为 private void
删除所有yield行的代码即可

在代码中

innerRadius为圆的半径,可以自行设定

blockCounts为切割的份数,数量越大消耗的电脑性能越多

height为高度,可以自行设定

increment为圆的角度增量

网格的生成顺序如下图红色箭头所示:

猜你喜欢

转载自blog.csdn.net/weixin_50736953/article/details/126533781