1.Mesh、MeshFilter、MeshRenderer關系整理
在Unity3D中創建一個Cube,在Inspector可以看到其中含有MeshFilter、MeshRenderer組件。
MeshFilter含有一個Public成員 Mesh。
在Mesh中存儲着三維模型的數據:vertices(頂點數據數組Vector3[])、triangles(三角形頂點索引數組,int[])、normals(法線向量數組,Vector3[])、uv(紋理坐標數組,Vector2[])。
2.使用Mesh創建一個Cube
創建一個腳本dyn3d.cs,成為Main Camera的組件,點擊運行即可看到動態生成的Cube

1 using UnityEngine; 2 using System.Collections; 3 4 public class dyn3d : MonoBehaviour { 5 6 // Use this for initialization 7 void Start () { 8 9 CreateCube(); 10 } 11 12 // Update is called once per frame 13 void Update () { 14 15 } 16 17 void CreateCube() 18 { 19 20 GameObject obj=new GameObject("cube"); 21 MeshFilter mf=obj.AddComponent<MeshFilter>(); 22 MeshRenderer mr=obj.AddComponent<MeshRenderer>(); 23 24 25 Vector3[] vertices=new Vector3[24]; 26 int[] triangles=new int[36]; 27 28 //forward 29 vertices[0].Set(0.5f,-0.5f,0.5f); 30 vertices[1].Set(-0.5f,-0.5f,0.5f); 31 vertices[2].Set(0.5f,0.5f,0.5f); 32 vertices[3].Set(-0.5f,0.5f,0.5f); 33 //back 34 vertices[4].Set(vertices[2].x,vertices[2].y,-0.5f); 35 vertices[5].Set(vertices[3].x,vertices[3].y,-0.5f); 36 vertices[6].Set(vertices[0].x,vertices[0].y,-0.5f); 37 vertices[7].Set(vertices[1].x,vertices[1].y,-0.5f); 38 //up 39 vertices[8]=vertices[2]; 40 vertices[9]=vertices[3]; 41 vertices[10]=vertices[4]; 42 vertices[11]=vertices[5]; 43 //down 44 vertices[12].Set(vertices[10].x,-0.5f,vertices[10].z); 45 vertices[13].Set(vertices[11].x,-0.5f,vertices[11].z); 46 vertices[14].Set(vertices[8].x,-0.5f,vertices[8].z); 47 vertices[15].Set(vertices[9].x,-0.5f,vertices[9].z); 48 //right 49 vertices[16]=vertices[6]; 50 vertices[17]=vertices[0]; 51 vertices[18]=vertices[4]; 52 vertices[19]=vertices[2]; 53 //left 54 vertices[20].Set(-0.5f,vertices[18].y,vertices[18].z); 55 vertices[21].Set(-0.5f,vertices[19].y,vertices[19].z); 56 vertices[22].Set(-0.5f,vertices[16].y,vertices[16].z); 57 vertices[23].Set(-0.5f,vertices[17].y,vertices[17].z); 58 59 int currentCount=0; 60 for(int i=0;i<24;i=i+4) 61 { 62 triangles[currentCount++]=i; 63 triangles[currentCount++]=i+3; 64 triangles[currentCount++]=i+1; 65 66 triangles[currentCount++]=i; 67 triangles[currentCount++]=i+2; 68 triangles[currentCount++]=i+3; 69 70 } 71 72 mf.mesh.vertices=vertices; 73 mf.mesh.triangles=triangles; 74 75 } 76 }
在這里定義vertices數組存儲頂點坐標信息,定義triangles數組存儲三角形頂點索引。但是這個Mesh不包含normals和uv信息,所以顯示出來的正方體是無紋理貼圖,並且不能反應環境光照的。
3.冗余的頂點坐標
正方體6個面,每個面由2個三角形組成,所以共需要36個三角形頂點索引。但是正方體只有8個頂點,為什么需要24個頂點坐標數據呢?
答案是:Unity3D的Mesh.triangles是三角形索引數組,不僅依靠這個索引值索引三角形頂點坐標,而且索引紋理坐標,索引法線向量。即正方體的每個頂點都參與了3個平面,而這3個平面的法線向量是不同的,該頂點在渲染這3個平面的時候需要索引到不同的法線向量。而由於頂點坐標和法線向量是由同一個索引值triangles[Index]取得的,例如,根據triangles[0],triangles[14],triangles[17]在vertices中索引到的頂點都為(0.5,-0.5,0.5),但是在normals中索引到的法向量值各不相同。這就決定了在正方體中一個頂點,需要有3份存儲。(如果你需要創建其它模型,需要根據實際情況決定頂點坐標的冗余度。實質上頂點坐標的冗余正是方便了法線坐標、紋理坐標的存取。)
4.三角形的渲染
准則:三角形有兩面,正面可見,背面不可見。三角形的渲染順序與三角形的正面法線呈左手螺旋定則。
這就決定了,如果我們需要渲染如下一個正方形面,那么就需要保證組成這個正方形的兩個小三角形的正面法線都是指向屏幕外的。

我在程序中的頂點順序為,三角形1: 0->3->1,三角形2: 0->2->3 。
1 int currentCount=0; 2 for(int i=0;i<24;i=i+4) 3 { 4 //三角形1 5 triangles[currentCount++]=i; 6 triangles[currentCount++]=i+3; 7 triangles[currentCount++]=i+1; 8 //三角形2 9 triangles[currentCount++]=i; 10 triangles[currentCount++]=i+2; 11 triangles[currentCount++]=i+3; 12 }
這段代碼保證了正方體的6個面,12個三角形的都正確被渲染(正面法線朝外)。
