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
}