1. 程式人生 > >Unity中用Mesh畫一個圓環(二)

Unity中用Mesh畫一個圓環(二)

中目標-生成完整面

在之前的內容中我們已經成功生成了一個面,接下來我們要生成剩下的面就很容易了。

我們把之前生成的面當作頂面,接著我們來生成底面。

還記得前面說過\(\color{#1E90FF}{Depth}\)這個引數用來控制深度,也就是頂面和地面之間的距離,放到座標系中就是控制Z的位置。

底面和頂面的頂點生成方法是一樣的,唯一不同的地方就是Z軸的不同。 我們只要用生成頂面的方法改下Z座標,就可以得到底面了。

//下
        for (int i = 0; i <= NumberOfSides; i++)
        {
            float angle = 180 - i * incrementAngle;
            float innerX = (Radius - Thickness) * Mathf.Cos(angle * Mathf.Deg2Rad);
            float innerY = (Radius - Thickness) * Mathf.Sin(angle * Mathf.Deg2Rad);
            vertexList.Add(new Vector3(innerX, innerY, -1 * Depth / 2));
            float outsideX = Radius * Mathf.Cos(angle * Mathf.Deg2Rad);
            float outsideY = Radius * Mathf.Sin(angle * Mathf.Deg2Rad);
            vertexList.Add(new Vector3(outsideX, outsideY, - 1 * Depth / 2));
        }

三角形索引的生成和之前也是一樣的,不同的是一開始的方向,因為頂面的法線是向上的,而底面的法線是向下的:

  direction = 1;
        startIndex += (NumberOfSides + 1) * 2;
        for (int i = 0; i < NumberOfSides * 2; i++)
        {
            int[] triangleIndexs = getTriangleIndexs(i, direction, startIndex);
            direction *= -1;
            for (int j = 0; j < triangleIndexs.Length; j++)
            {
                triangleList.Add(triangleIndexs[j]);
            }
        }

至於UV索引則設定和頂面的一樣即可。

其他生成頂面和底面之後,大部分的工作已經完成了,這時候我們已經生成了我們需要的所有頂點。前後左右也只是用現有的這些頂點進行生成。

我們前面生成的圓柱體是基於圓生成的,如果我們改成基於貝塞爾生成的那也是可以的。

修改方法很簡單,就是改下生成頂點時的過程就好了,其他的不需要動。

具體過程直接看程式碼吧,包看包懂。

當然下面的程式碼是為了方面理解所以寫得冗餘,如果用到專案中建議優化下,不然會被主程打的。

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

//[RequireComponent(typeof(MeshFilter))]  
//[RequireComponent(typeof(MeshRenderer))]  
[ExecuteInEditMode]  
public class DrawArch : MonoBehaviour  
{
    public float Radius = 20.0f;                //外圈的半徑  
    public float Thickness = 10.0f;             //厚度,外圈半徑減去內圈半徑  
    public float Depth = 1.0f;                  //厚度  
    public int NumberOfSides = 30;         //由多少個面組成  
    public float DrawArchDegrees = 90.0f;       //要繪畫多長  
    public Material archMaterial = null;  

    private int VertexCountOneSide = 0;         //生成一面所需的頂點數  
    private Mesh mesh = null;  

    private float incrementAngle = 0;  
    private List<Vector3> vertexList = new List<Vector3>();
    private List<int> triangleList = new List<int>();
    private List<Vector2> uvList = new List<Vector2>();

    // Start is called before the first frame update
    void Start()
    {
        mesh = new Mesh();
    }

    void GenerateMesh()
    {
        VertexCountOneSide = (NumberOfSides + 1) * 2;
        incrementAngle = DrawArchDegrees / NumberOfSides;

        GenerateVertex();
        GenerateTriangleIndex();
        GenerateUV();

        mesh.vertices = vertexList.ToArray();
        mesh.uv = uvList.ToArray();
        mesh.triangles = triangleList.ToArray();

        mesh.RecalculateNormals();
        gameObject.GetComponent<MeshFilter>().mesh = mesh;
        gameObject.GetComponent<MeshRenderer>().material = archMaterial;
    }

    //生成頂點座標
    void GenerateVertex()
    {
        //上
        vertexList.Clear();
        for (int i = 0; i <= NumberOfSides; i++)
        {
            float angle = 180 - i * incrementAngle;
            float innerX = (Radius - Thickness) * Mathf.Cos(angle * Mathf.Deg2Rad);
            float innerY = (Radius - Thickness) * Mathf.Sin(angle * Mathf.Deg2Rad);
            vertexList.Add(new Vector3(innerX, innerY, Depth / 2));
            float outsideX = Radius * Mathf.Cos(angle * Mathf.Deg2Rad);
            float outsideY = Radius * Mathf.Sin(angle * Mathf.Deg2Rad);
            vertexList.Add(new Vector3(outsideX, outsideY, Depth / 2));
        }

        //下
        for (int i = 0; i <= NumberOfSides; i++)
        {
            float angle = 180 - i * incrementAngle;
            float innerX = (Radius - Thickness) * Mathf.Cos(angle * Mathf.Deg2Rad);
            float innerY = (Radius - Thickness) * Mathf.Sin(angle * Mathf.Deg2Rad);
            vertexList.Add(new Vector3(innerX, innerY, -1 * Depth / 2));
            float outsideX = Radius * Mathf.Cos(angle * Mathf.Deg2Rad);
            float outsideY = Radius * Mathf.Sin(angle * Mathf.Deg2Rad);
            vertexList.Add(new Vector3(outsideX, outsideY, - 1 * Depth / 2));
        }

        //前
        for (int i = 0; i <= NumberOfSides * 2 ; i += 2)
        {
            vertexList.Add(vertexList[i]);
            vertexList.Add(vertexList[i + VertexCountOneSide]);
        }
        //後
        for (int i = 0; i <= NumberOfSides * 2; i += 2)
        {
            vertexList.Add(vertexList[i + 1]);
            vertexList.Add(vertexList[i + VertexCountOneSide + 1]);
        }
        //左
        vertexList.Add(vertexList[0]);
        vertexList.Add(vertexList[1]);
        vertexList.Add(vertexList[VertexCountOneSide + 0]);
        vertexList.Add(vertexList[VertexCountOneSide + 1]);
        //右
        vertexList.Add(vertexList[VertexCountOneSide -2]);
        vertexList.Add(vertexList[VertexCountOneSide - 1]);
        vertexList.Add(vertexList[VertexCountOneSide * 2 - 2]);
        vertexList.Add(vertexList[VertexCountOneSide * 2 - 1]);
    }

    void GenerateTriangleIndex()
    {
        //三角形索引
        triangleList.Clear();
        //上
        int direction = -1;
        int startIndex = 0;
        for (int i = 0; i < NumberOfSides * 2; i++)
        {
            int[] triangleIndexs = getTriangleIndexs(i, direction);
            direction *= -1;
            for (int j = 0; j < triangleIndexs.Length; j++)
            {
                triangleList.Add(triangleIndexs[j]);
            }
        }

        //下
        direction = 1;
        startIndex += (NumberOfSides + 1) * 2;
        for (int i = 0; i < NumberOfSides * 2; i++)
        {
            int[] triangleIndexs = getTriangleIndexs(i, direction, startIndex);
            direction *= -1;
            for (int j = 0; j < triangleIndexs.Length; j++)
            {
                triangleList.Add(triangleIndexs[j]);
            }
        }

        //前
        direction = 1;
        startIndex += VertexCountOneSide;
        for (int i = 0; i < NumberOfSides * 2; i++)
        {
            int[] triangleIndexs = getTriangleIndexs(i, direction, startIndex);
            direction *= -1;
            for (int j = 0; j < triangleIndexs.Length; j++)
            {
                triangleList.Add(triangleIndexs[j]);
            }
        }

        //後
        direction = -1;
        startIndex += VertexCountOneSide;
        for (int i = 0; i < NumberOfSides * 2; i++)
        {
            int[] triangleIndexs = getTriangleIndexs(i, direction, startIndex);
            direction *= -1;
            for (int j = 0; j < triangleIndexs.Length; j++)
            {
                triangleList.Add(triangleIndexs[j]);
            }
        }
        startIndex += VertexCountOneSide;
        //左
        triangleList.Add(startIndex + 0);
        triangleList.Add(startIndex + 1);
        triangleList.Add(startIndex + 2);
        triangleList.Add(startIndex + 3);
        triangleList.Add(startIndex + 2);
        triangleList.Add(startIndex + 1);
        //右
        triangleList.Add(startIndex + 4 + 2);
        triangleList.Add(startIndex + 4 + 1);
        triangleList.Add(startIndex + 4 + 0);
        triangleList.Add(startIndex + 4 + 1);
        triangleList.Add(startIndex + 4 + 2);
        triangleList.Add(startIndex + 4 + 3);
    }

    //UV索引
    void GenerateUV()
    {
        uvList.Clear();
        //上
        for (int i = 0; i <= NumberOfSides; i++)
        {
            float angle = 180 - i * incrementAngle;
            float littleX = (1.0f / NumberOfSides) * i;
            uvList.Add(new Vector2(littleX, 0));
            float bigX = (1.0f / NumberOfSides) * i;
            uvList.Add(new Vector2(bigX, 1));
        }

        //下
        for (int i = 0; i <= NumberOfSides; i++)
        {
            float angle = 180 - i * incrementAngle;
            float littleX = (1.0f / NumberOfSides) * i;
            uvList.Add(new Vector2(littleX, 0));
            float bigX = (1.0f / NumberOfSides) * i;
            uvList.Add(new Vector2(bigX, 1));
        }

        //前
        for (int i = 0; i <= NumberOfSides; i++)
        {
            float angle = 180 - i * incrementAngle;
            float littleX = (1.0f / NumberOfSides) * i;
            uvList.Add(new Vector2(littleX, 0));
            float bigX = (1.0f / NumberOfSides) * i;
            uvList.Add(new Vector2(bigX, 1));
        }

        //後
        for (int i = 0; i <= NumberOfSides; i++)
        {
            float angle = 180 - i * incrementAngle;
            float littleX = (1.0f / NumberOfSides) * i;
            uvList.Add(new Vector2(littleX, 0));
            float bigX = (1.0f / NumberOfSides) * i;
            uvList.Add(new Vector2(bigX, 1));
        }
        //左
        uvList.Add(new Vector2(1.0f, 1.0f));
        uvList.Add(new Vector2(0.0f, 1.0f));
        uvList.Add(new Vector2(0.0f, 0.0f));
        uvList.Add(new Vector2(1.0f, 0.0f));
        //右
        uvList.Add(new Vector2(1.0f, 1.0f));
        uvList.Add(new Vector2(0.0f, 1.0f));
        uvList.Add(new Vector2(0.0f, 0.0f));
        uvList.Add(new Vector2(1.0f, 0.0f));
    }

    int[] getTriangleIndexs(int index, int direction, int startIndex = 0)
    {
        int[] triangleIndexs = new int[3] { 0+ startIndex, 1 + startIndex, 2 + startIndex };
        for (int i = 0; i < triangleIndexs.Length; i++)
        {
            triangleIndexs[i] += index;
        }
        if (direction == -1)
        {
            int temp = triangleIndexs[0];
            triangleIndexs[0] = triangleIndexs[2];
            triangleIndexs[2] = temp;
        }
        return triangleIndexs;
    }

    private void Update()
    {
        GenerateMesh();
    }
}