Unity 在代码中利用Mesh实时生成圆环/空心圆柱

    本篇文章主要介绍了利用Unity中的mesh 实时生成圆环的过程以及思想,我会在开头直接放出源码。如若有任何疑问,可向后继续观看详细解说~~~

    (PSPSPS:Mesh生成的顺序,方式等有很多,当前代码中部分逻辑若不理解,可自行推导一下圆的方程,即可得出解答   //顺带说一下,代码中的英文是我锻炼英文用的。。。。遇见语法错误不准笑……)

首先 放上效果图:

Unity 在代码中利用Mesh实时生成圆环/空心圆柱_第1张图片

 

代码如下:

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

[RequireComponent(typeof(MeshFilter) , typeof(MeshRenderer))]
public class CylinderGenerateScript : MonoBehaviour {

    //the outside radius must lager than the inside one
    [Range(0, 100)] public float innerRadius;
    [Range(1, 100)] public float outsideRadius;
    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();

        GenerateMesh();

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

    }


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


        //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 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 vertices = new List();

        //used to load the radius we have    [Use Array to help us expand the plies]
        float[] radiuses = {innerRadius , outsideRadius };

        //For now this code will generate the inner circle first
        for (int i = 0; i < radiuses.Length; i++)
        {
            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);
            }
        }

        return vertices;
    }

    private List FillTriangles( int vertCount )
    {

        List triangles = new List();

        //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+=4 , j+=4)
        {

            if(i >= vertCount/2 - 2)
            {
                triangles.AddRange(GetTriangleOrder(0, vertCount/2 , j , i));
                triangles.AddRange(GetTriangleOrder(i + 1, j + 1, vertCount / 2 + 1, 1));
            }
            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 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 output = new List();

        //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;
    }


    IEnumerator SequenceTest()
    {

        float interval = 0.01f;

        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);

        }
    }
}

    Mesh的生成过程说白了就是生成点,然后再将各点连接成为一个个的小三角形的过程,以上的代码也都是基于这个思想的。

    在Mesh的生成过程中,先说一些基本的东西:

  •   Mesh的组成分为几个部分:

              vertices :mesh中的顶点集,mesh所有的顶点位置信息都存储在这里,其类型为vertex。

             triangles : mesh中存储连接顺序的集合,在mesh生成中,unity会依照此集合中的标号依次连接vertices中的顶点,在Unity中,由于mesh都是由一个个的小三角形组成的,因此,这个集合使用时将是每三个顶点号为一组,然后以此往复向后。(请注意在给triangles 赋值时,标号一定不要超过vertices中记录的标号,否则会导致错误出现。)

            uvs :mesh中存储材质的集合,类型为vector3的数组,这个数组提供的参数将会用于贴图在物体表面的匹配。

 

  • 添加此脚本(所有自动生成Mesh的脚本)需要先在物体上添加MeshFilter 以及 MeshRenderer组件,然后才能正常生成物体,否则会报错

 

解说在此解说在此解说在此::::::

  •     首先需要说的就是各个变量的定义----》

               innerRadius,outsideRadius:内层以及外层环形的半径,内层圆半径请勿大于外层,本文代码中,并未提供判断此项的方法。

               blockCounts                          :规定圆环会被划分为多少份来生成,此项越小,环形的边界也会相应的慢慢变为多边形的样子,同时,此项不宜过大,否则生成的效果一样,但是需要花费更多的CPU资源来生成,请自行斟酌。

               height                                      : 规定生成的圆环的高度。

               increment                                :划分这么多份,每一份的角度。后面生成各个点时,需要用到。

               其余的~~~~~~~~~~~~~~~~~~:略!

  • 然后就是我们的生成思想了~~~

               角度计算:在这里,我们首先要求出分了这么多块,每一块的角度,也就是基本的圆的公式:2 * PI / blockCounts  , 算出这个值以后,我们通过GenerateVertics函数就可以开始生成顶点信息了,

              顶点生成:我这里采用的是先生成内层顶点,然后依次向外延伸,生成外层顶点的顺序,在自己生成顶点时请注意,一定要记好自己生成顶点的顺序,否则后面填充triangles数组时会产生混乱。

             各边连接(填充triangles):这里就是连接各个顶点的过程,一般情况下,一个小的面(四边形)需要填充两个三角形,这也就意味着我们每四个顶点,要互相连接,形成两个三角形。(PSPSPS:大写的强调:三角形不可重叠 &&& 三角形的连接顺序为你所需要看见的面的方向的顺时针,否则是看不见的。当然你可以将顺时针和逆时针都加进去,这样可以做到双面可见

  • 最后的话,就是我们的调试程序了~~:

            这里是用了一个协程操作,来向我们一步一步的展示了这个三角形的具体生成过程,这一小段代码取自这里这里这里。

    到这里也就没什么了,其实主要就是计算顶点,以及判断生成顺序的一个问题而已~~,希望大家喜欢~~

 

本帅哥乃小白界中的一员,难免有错,发现的话,请评论啥玩意的~~大家一起学习啊~~~

            

 

 

       

你可能感兴趣的:(Unity菜鸡互啄)