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 Vector2[] bezierPoints = new Vector2[4];
    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[] points = GetCirclePoint(Radius - Thickness,  i);
            //vertexList.Add(new Vector3(points[0], points[1], Depth / 2));
            //points = GetCirclePoint(Radius, i);
            //vertexList.Add(new Vector3(points[0], points[1], Depth / 2));
            float[] points = GetBezierPoint(i);
            vertexList.Add(new Vector3(points[0], points[1], Depth / 2));
            points = GetBezierPoint(i);
            vertexList.Add(new Vector3(points[0] - 1, points[1], Depth / 2));
        }

        //下
        for (int i = 0; i <= NumberOfSides; i++)
        {
            //float[] points = GetCirclePoint(Radius - Thickness,  i);
            //vertexList.Add(new Vector3(points[0], points[1], -1 * Depth / 2));
            //points = GetCirclePoint(Radius, i);
            //vertexList.Add(new Vector3(points[0], points[1], -1 * Depth / 2));
            float[] points = GetBezierPoint(i);
            vertexList.Add(new Vector3(points[0], points[1], -1 * Depth / 2));
            points = GetBezierPoint(i);
            vertexList.Add(new Vector3(points[0] - 1, points[1], -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();
    }

    float[] GetCirclePoint(float radius, int index)
    {
        float angle = 180 - index * incrementAngle;
        float[] points = new float[2];
        float x = radius * Mathf.Cos(angle * Mathf.Deg2Rad);
        float y = radius * Mathf.Sin(angle * Mathf.Deg2Rad);
        points[0] = x;
        points[1] = y;
        return points;
    }

    float[] GetBezierPoint(int index)
    {
        float t = 1.0f / (NumberOfSides + 1) * index;
        float[] points = new float[2];
        var vec = Bezier(bezierPoints[0], bezierPoints[1], bezierPoints[2], bezierPoints[3], t);
        points[0] = vec.x;
        points[1] = vec.y;
        return points;
    }

    Vector2 Bezier(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3, float t)
    {
        Vector2 result;
        Vector2 p0p1 = (1 - t) * p0 + t * p1;
        Vector2 p1p2 = (1 - t) * p1 + t * p2;
        Vector2 p2p3 = (1 - t) * p2 + t * p3;
        Vector2 p0p1p2 = (1 - t) * p0p1 + t * p1p2;
        Vector2 p1p2p3 = (1 - t) * p1p2 + t * p2p3;
        result = (1 - t) * p0p1p2 + t * p1p2p3;
        return result;
    }
}


posted @ 2019-11-16 21:07  唐好酸  阅读(593)  评论(0编辑  收藏  举报