1. 程式人生 > >Unity Mesh(一) 初步使用Mesh畫平面圖形

Unity Mesh(一) 初步使用Mesh畫平面圖形

最近發現Mesh很牛的樣子,雖然以前也見過人家大牛用這個寫過工具,當時沒大在意,現在開始接觸,覺得挺好玩的,首先先上我畫的幾個圖:

據說還可以畫各種形狀,原理就是所有圖形都是由三角形組成的。

下面我們一一的解釋下:

一.畫三角形

首先,給元件新增MeshFilter和MeshRenderer兩個元件,這兩個元件是Mesh必須的,然後我們自己新建一個材質備用,用來給Mesh賦值使用,Mesh畫出來圖案的材質就是你你新建的材質。

重要的兩步:

第一步:指定定點,比如我們畫三角形,我們指定三個定點

第二部:指定三角形順序,注意個triangles的陣列的大小必須是3的倍數,然後三角形的點順序必須是順時針的,當然你逆時針只能在反面看到。

下面我們看下指令碼:

void DrawTriangle()
    {
        gameObject.AddComponent<MeshFilter>();
        gameObject.AddComponent<MeshRenderer>();
        gameObject.GetComponent<MeshRenderer>().material = mat;
 
        Mesh mesh = GetComponent<MeshFilter>().mesh;
        mesh.Clear();
 
        //設定頂點
        mesh.vertices = new Vector3[] { new Vector3(0, 0, 0), new Vector3(0, 1, 0), new Vector3(1, 1, 0) };
        //設定三角形頂點順序,順時針設定
        mesh.triangles = new int[] { 0, 1, 2 };
    }

最終圖片如圖所示:

三角形還是比較簡單的,Unity官網API介紹就有這個例項,這裡面我們暫時先不考慮UV.

二.畫正方形

有了三角形,我們畫正方形也會簡單很多,我們分析一下正方形是由兩個三角形組成的,我們畫兩個三角形就可以了,在上面的基礎上我們再加一個點(1,0)就可以了,

程式碼如下:

#region 畫正方形
    void DrawSquare()
    {
        gameObject.AddComponent<MeshFilter>();
        gameObject.AddComponent<MeshRenderer>();
        gameObject.GetComponent<MeshRenderer>().material = mat;
 
        Mesh mesh = GetComponent<MeshFilter>().mesh;
        mesh.Clear();
 
        mesh.vertices = new Vector3[] { new Vector3(0, 0, 0), new Vector3(0, 1, 0), new Vector3(1, 1, 0), new Vector3(1, 0, 0) };
        mesh.triangles = new int[]
        { 0, 1, 2,
          0, 2, 3
        };
    }
    #endregion

圖形如圖:

正方形能畫,那什麼梯形,平行四邊形,菱形啥的肯定也不在話下,這裡我就不寫demo了。

三.畫圓

一開始畫圓還沒啥頭緒,後來想想,圓其實也是有很多個三角形組成的,類似這樣:

鄙人畫畫比較醜,將就著看吧,類似這樣可以細分成很多個小三角形,然後定點座標就是各點組成:

頂點的集合有黃色的點組成,除了圓心,其它的點的座標都是根據角度確定的,這個我們上學時幾何學過,我就不細說了。

這樣我們的畫圓的函式需要引數有:半徑,圓心座標,分割的份數

頂點的程式碼如下:

//頂點
        Vector3[] vertices = new Vector3[segments + 1];
        vertices[0] = centerCircle;
        float deltaAngle = Mathf.Deg2Rad * 360f / segments;
        float currentAngle = 0;
        for (int i = 1; i < vertices.Length; i++)
        {
            float cosA = Mathf.Cos(currentAngle);
            float sinA = Mathf.Sin(currentAngle);
            vertices[i] = new Vector3(cosA * radius + centerCircle.x, sinA * radius + centerCircle.y, 0);
            currentAngle += deltaAngle;
        }

Deg2Rad相當於2PI

後面就是頂點的順序了,注意,最後一個三角形的定點涉及到初始的點:

比如我們圖中 的:

如圖中所示,最後一組的時候如果使用遍歷,陣列會越界,所以我們可以最後三個單獨寫,也可以採用取模。

這裡我們的程式碼採用單獨寫的方式,程式碼如下:

//三角形
        int[] triangles = new int[segments * 3];
        for (int i = 0, j = 1; i < segments * 3 - 3; i += 3, j++)
        {
            triangles[i] = 0;
            triangles[i + 1] = j + 1;
            triangles[i + 2] = j;
        }
        triangles[segments * 3 - 3] = 0;
        triangles[segments * 3 - 2] = 1;
        triangles[segments * 3 - 1] = segments;

這樣我們的頂點和三角形都確定了,關於順時針和逆時針,看你攝像頭看的哪一面哈

完整的畫圓程式碼如下:

#region 畫圓
    /// <summary>
    /// 畫圓
    /// </summary>
    /// <param name="radius">圓的半徑</param>
    /// <param name="segments">圓的分割數</param>
    /// <param name="centerCircle">圓心得位置</param>
    void DrawCircle(float radius, int segments, Vector3 centerCircle)
    {
        gameObject.AddComponent<MeshFilter>();
        gameObject.AddComponent<MeshRenderer>();
        gameObject.GetComponent<MeshRenderer>().material = mat;
 
        //頂點
        Vector3[] vertices = new Vector3[segments + 1];
        vertices[0] = centerCircle;
        float deltaAngle = Mathf.Deg2Rad * 360f / segments;
        float currentAngle = 0;
        for (int i = 1; i < vertices.Length; i++)
        {
            float cosA = Mathf.Cos(currentAngle);
            float sinA = Mathf.Sin(currentAngle);
            vertices[i] = new Vector3(cosA * radius + centerCircle.x, sinA * radius + centerCircle.y, 0);
            currentAngle += deltaAngle;
        }
 
        //三角形
        int[] triangles = new int[segments * 3];
        for (int i = 0, j = 1; i < segments * 3 - 3; i += 3, j++)
        {
            triangles[i] = 0;
            triangles[i + 1] = j + 1;
            triangles[i + 2] = j;
        }
        triangles[segments * 3 - 3] = 0;
        triangles[segments * 3 - 2] = 1;
        triangles[segments * 3 - 1] = segments;
 
 
        Mesh mesh = GetComponent<MeshFilter>().mesh;
        mesh.Clear();
 
        mesh.vertices = vertices;
        mesh.triangles = triangles;
    }
    #endregion

當然你還可以做點小變動,畫成這樣:

上面的毀了,這樣的就自然能畫出來,自己試下哈。

四.畫圓環

既然,上面的圓畫出來了,圓環也就在此基礎上,只不過有好多小梯形組成,梯形由兩個三角形組成。

示意圖如下:

當分成很多等份時,就類似圓環了。

同理,我們先列頂點,這一次我們比上面多要一個引數,內圓半徑: 頂點程式碼如下:

//頂點
        Vector3[] vertices = new Vector3[segments * 2];
        float deltaAngle = Mathf.Deg2Rad * 360f / segments;
        float currentAngle = 0;
        for (int i = 0; i < vertices.Length; i += 2)
        {
            float cosA = Mathf.Cos(currentAngle);
            float sinA = Mathf.Sin(currentAngle);
            vertices[i] = new Vector3(cosA * innerRadius + centerCircle.x, sinA * innerRadius + centerCircle.y, 0);
            vertices[i + 1] = new Vector3(cosA * radius + centerCircle.x, sinA * radius + centerCircle.y, 0);
            currentAngle += deltaAngle;
        }

同理,再列出三角形:

//三角形
        int[] triangles = new int[segments * 6];
        for (int i = 0, j = 0; i < segments * 6; i += 6, j += 2)
        {
            triangles[i] = j;
            triangles[i + 1] = (j + 1) % vertices.Length;
            triangles[i + 2] = (j + 3) % vertices.Length;
 
            triangles[i + 3] = j;
            triangles[i + 4] = (j + 3) % vertices.Length;
            triangles[i + 5] = (j + 2) % vertices.Length;
        }

最終結果如圖:

完整的程式碼如下:

#region 畫圓環
    /// <summary>
    /// 畫圓環
    /// </summary>
    /// <param name="radius">圓半徑</param>
    /// <param name="innerRadius">內圓半徑</param>
    /// <param name="segments">圓的分個數</param>
    /// <param name="centerCircle">圓心座標</param>
    void DrawRing(float radius, float innerRadius, int segments, Vector3 centerCircle)
    {
        gameObject.AddComponent<MeshFilter>();
        gameObject.AddComponent<MeshRenderer>();
        gameObject.GetComponent<MeshRenderer>().material = mat;
 
        //頂點
        Vector3[] vertices = new Vector3[segments * 2];
        float deltaAngle = Mathf.Deg2Rad * 360f / segments;
        float currentAngle = 0;
        for (int i = 0; i < vertices.Length; i += 2)
        {
            float cosA = Mathf.Cos(currentAngle);
            float sinA = Mathf.Sin(currentAngle);
            vertices[i] = new Vector3(cosA * innerRadius + centerCircle.x, sinA * innerRadius + centerCircle.y, 0);
            vertices[i + 1] = new Vector3(cosA * radius + centerCircle.x, sinA * radius + centerCircle.y, 0);
            currentAngle += deltaAngle;
        }
 
        //三角形
        int[] triangles = new int[segments * 6];
        for (int i = 0, j = 0; i < segments * 6; i += 6, j += 2)
        {
            triangles[i] = j;
            triangles[i + 1] = (j + 1) % vertices.Length;
            triangles[i + 2] = (j + 3) % vertices.Length;
 
            triangles[i + 3] = j;
            triangles[i + 4] = (j + 3) % vertices.Length;
            triangles[i + 5] = (j + 2) % vertices.Length;
        }
 
        Mesh mesh = GetComponent<MeshFilter>().mesh;
        mesh.Clear();
 
        mesh.vertices = vertices;
        mesh.triangles = triangles;
    }
    #endregion

一樣,程式碼做點小的改動就能產生太陽和鋸齒的圖片,如下:

怎麼改的上面看明白的一眼就看出來了,哈哈,你們自己寫吧。

五:完整程式碼

本篇部落格涉及的指令碼的完整程式碼如下:  

using UnityEngine;
using System.Collections;
 
public enum PlaneState
{
    Triangle,
    Square,
    Circle,
    Ring
}
 
public class Test : MonoBehaviour
{
 
    public Material mat;
 
    public PlaneState planeState;
 
    // Use this for initialization
    void Start()
    {
 
        switch (planeState)
        {
            case PlaneState.Triangle:
                DrawTriangle();
                break;
            case PlaneState.Square:
                DrawSquare();
                break;
            case PlaneState.Circle:
                DrawCircle(2, 50, Vector3.zero);
                break;
            case PlaneState.Ring:
                DrawRing(2, 3, 50, Vector3.zero);
                break;
        }
 
 
 
    }
 
    #region 畫三角形
    void DrawTriangle()
    {
        gameObject.AddComponent<MeshFilter>();
        gameObject.AddComponent<MeshRenderer>();
        gameObject.GetComponent<MeshRenderer>().material = mat;
 
        Mesh mesh = GetComponent<MeshFilter>().mesh;
        mesh.Clear();
 
        //設定頂點
        mesh.vertices = new Vector3[] { new Vector3(0, 0, 0), new Vector3(0, 1, 0), new Vector3(1, 1, 0) };
        //設定三角形頂點順序,順時針設定
        mesh.triangles = new int[] { 0, 1, 2 };
    }
    #endregion
 
    #region 畫正方形
    void DrawSquare()
    {
        gameObject.AddComponent<MeshFilter>();
        gameObject.AddComponent<MeshRenderer>();
        gameObject.GetComponent<MeshRenderer>().material = mat;
 
        Mesh mesh = GetComponent<MeshFilter>().mesh;
        mesh.Clear();
 
        mesh.vertices = new Vector3[] { new Vector3(0, 0, 0), new Vector3(0, 1, 0), new Vector3(1, 1, 0), new Vector3(1, 0, 0) };
        mesh.triangles = new int[]
        { 0, 1, 2,
          0, 2, 3
        };
    }
    #endregion
 
    #region 畫圓
    /// <summary>
    /// 畫圓
    /// </summary>
    /// <param name="radius">圓的半徑</param>
    /// <param name="segments">圓的分割數</param>
    /// <param name="centerCircle">圓心得位置</param>
    void DrawCircle(float radius, int segments, Vector3 centerCircle)
    {
        gameObject.AddComponent<MeshFilter>();
        gameObject.AddComponent<MeshRenderer>();
        gameObject.GetComponent<MeshRenderer>().material = mat;
 
        //頂點
        Vector3[] vertices = new Vector3[segments + 1];
        vertices[0] = centerCircle;
        float deltaAngle = Mathf.Deg2Rad * 360f / segments;
        float currentAngle = 0;
        for (int i = 1; i < vertices.Length; i++)
        {
            float cosA = Mathf.Cos(currentAngle);
            float sinA = Mathf.Sin(currentAngle);
            vertices[i] = new Vector3(cosA * radius + centerCircle.x, sinA * radius + centerCircle.y, 0);
            currentAngle += deltaAngle;
        }
 
        //三角形
        int[] triangles = new int[segments * 3];
        for (int i = 0, j = 1; i < segments * 3 - 3; i += 3, j++)
        {
            triangles[i] = 0;
            triangles[i + 1] = j + 1;
            triangles[i + 2] = j;
        }
        triangles[segments * 3 - 3] = 0;
        triangles[segments * 3 - 2] = 1;
        triangles[segments * 3 - 1] = segments;
 
 
        Mesh mesh = GetComponent<MeshFilter>().mesh;
        mesh.Clear();
 
        mesh.vertices = vertices;
        mesh.triangles = triangles;
    }
    #endregion
 
    #region 畫圓環
    /// <summary>
    /// 畫圓環
    /// </summary>
    /// <param name="radius">圓半徑</param>
    /// <param name="innerRadius">內圓半徑</param>
    /// <param name="segments">圓的分個數</param>
    /// <param name="centerCircle">圓心座標</param>
    void DrawRing(float radius, float innerRadius, int segments, Vector3 centerCircle)
    {
        gameObject.AddComponent<MeshFilter>();
        gameObject.AddComponent<MeshRenderer>();
        gameObject.GetComponent<MeshRenderer>().material = mat;
 
        //頂點
        Vector3[] vertices = new Vector3[segments * 2];
        float deltaAngle = Mathf.Deg2Rad * 360f / segments;
        float currentAngle = 0;
        for (int i = 0; i < vertices.Length; i += 2)
        {
            float cosA = Mathf.Cos(currentAngle);
            float sinA = Mathf.Sin(currentAngle);
            vertices[i] = new Vector3(cosA * innerRadius + centerCircle.x, sinA * innerRadius + centerCircle.y, 0);
            vertices[i + 1] = new Vector3(cosA * radius + centerCircle.x, sinA * radius + centerCircle.y, 0);
            currentAngle += deltaAngle;
        }
 
        //三角形
        int[] triangles = new int[segments * 6];
        for (int i = 0, j = 0; i < segments * 6; i += 6, j += 2)
        {
            triangles[i] = j;
            triangles[i + 1] = (j + 1) % vertices.Length;
            triangles[i + 2] = (j + 3) % vertices.Length;
 
            triangles[i + 3] = j;
            triangles[i + 4] = (j + 3) % vertices.Length;
            triangles[i + 5] = (j + 2) % vertices.Length;
        }
 
        Mesh mesh = GetComponent<MeshFilter>().mesh;
        mesh.Clear();
 
        mesh.vertices = vertices;
        mesh.triangles = triangles;
    }
    #endregion
}