大家應該知道3D世界中任何的面都是由三角形繪制完成的,因為任何無規則的集合圖形都可以由三角形來組成。比如四邊形,無論是正四邊形還是無規則四邊形都可以由兩個三角形拼接而成。
結合本文的標題大家仔細想想,如果需要繪制一個動態無規則面其實只需要得到動態的兩個軌跡點即可,那么結合下面的圖片大家仔細在想想。

暫時我們先忽略Z軸(這樣在平面中看得更清楚),假設Z軸坐標都為0。假設游戲中有兩個軌跡點在動態的增加與改變,最后將這兩個點改變的軌跡拼接起來就是它們生成的面。如上圖所示,第一個點的軌跡是“ 3,4,5,6,7” 第二個點的軌跡是“2,1,10,9,8” 。這兩個點的長度是可變的,前提是他們兩個的數量必需完全一樣。接著,如下圖所示,我們將這些點兩兩相連起來,目前一共形成了8個三角形面(可根據兩個動態點的數量而確定整個網格面三角形面的數量)。最后我們將這8個三角形填充上同樣的顏色,就可以實現一個完整的立體網格面。

原理很簡單,就是這樣的我相信大家看到這里大家都能明白,接著我們就學習如何使用代碼來實現它。首先創建Unity工程,接著創建一個空的游戲對象,然后給該游戲對象綁定Mesh Filter組件 與 Mesh Renderer組件。
Mesh Filter組件:表示網格面,這個網格面是由我們使用代碼將所有三角形拼接起來生成的面。
Mesh Renderer組件:表示表示網格的渲染,可設置一個渲染的材質,它包括貼圖與顏色。
如下圖所示,我說說里面比較重要的屬性。Mesh Renderer中,Materials下拉列表中可設置網格模型的材質,此時我們設置了一個紅色的材質。 Mesh Filter:目前為None,也不用再編輯器中為它賦值,因為這個網格模型我們會在代碼中生成并且賦值。在下面就是方剛我們設置紅色的材質資源,Shader中設置了貼圖的屬性,目前是GUI/ TextShader。它表示這個材質的渲染級別在GUI上,就是優先級是最一層的。舉個例子無論在這個網格模型的前面繪制多少模型,它永遠都會在最前面顯示。就這個例子而言它的存在并不是必需的,其實Shader的選項還有很多,可透明、不可透明、鏡面、反射等等,后期我會向大家詳細道來。

OK,現在資源文件都已經準備完畢,下面我們學習如何來繪制一個三角形,從簡單的開始。。把下面的代碼綁定在攝像機對象當中。
[代碼]java代碼:
02 |
using System.Collections.Generic; |
05 |
public class Test : MonoBehaviour { |
09 |
//得到MeshFilter對象,目前是空的。 |
10 |
MeshFilter meshFilter = (MeshFilter)GameObject.Find("face").GetComponent(typeof(MeshFilter)); |
12 |
Mesh mesh = meshFilter.mesh; |
15 |
Vector3[] vertices = new Vector3[3]; |
17 |
int[] triangles = new int[3]; |
19 |
//三角形三個定點坐標,為了顯示清楚忽略Z軸 |
20 |
vertices[0] = new Vector3(0,0,0); |
21 |
vertices[1] = new Vector3(0,1,0); |
22 |
vertices[2] = new Vector3(1,0,0); |
30 |
mesh.vertices = vertices; |
32 |
mesh.triangles = triangles; |
代碼中有兩個非常重要的概念,就是三角形頂點數組與坐標數組。先說說坐標數組,假設需要繪制一個四邊形,此時三角形坐標數組的長度應當是4,它保存著四邊形四個頂點的坐標。然后是頂點數組,四邊形是由兩個三角形組成,然而一個三角形是由3個頂點組成,兩個三角形就應當是6個頂點組成,無論多少個三角形它們的結構都應當是以此類推。
注解1:這里是將模型的頂點數組與坐標數組賦值給網格模型,還記得剛剛在創建Mesh Filter時,當時沒有在編輯器中給網格模型賦值,實際上代碼走到這里就會重新為網格模型MeshFilter賦值,接著我們在代碼中繪制的三角形就會顯示在屏幕當中。
如圖所示,三角形已經繪制在屏幕當中。 圖中數組 0 1 2 表示該三角形的三個頂點的ID。這個ID對應代碼中對應vertices數組索引頂點的坐標。

下面我們修改一下代碼,讓屏幕中一共繪制4個三角形。
[代碼]java代碼:
02 |
using System.Collections.Generic; |
05 |
public class Test : MonoBehaviour { |
08 |
private int VERTICES_COUNT = 6; |
12 |
//得到MeshFilter對象,目前是空的。 |
13 |
MeshFilter meshFilter = (MeshFilter)GameObject.Find("face").GetComponent(typeof(MeshFilter)); |
15 |
Mesh mesh = meshFilter.mesh; |
18 |
Vector3[] vertices = new Vector3[VERTICES_COUNT]; |
21 |
int triangles_count = VERTICES_COUNT - 2; |
24 |
int[] triangles = new int[triangles_count *3]; |
26 |
//三角形三個定點坐標,為了顯示清楚忽略Z軸 |
27 |
vertices[0] = new Vector3(0,0,0); |
28 |
vertices[1] = new Vector3(0,1,0); |
29 |
vertices[2] = new Vector3(1,0,0); |
30 |
vertices[3] = new Vector3(1,1,0); |
31 |
vertices[4] = new Vector3(2,0,0); |
32 |
vertices[5] = new Vector3(2,1,0); |
51 |
mesh.vertices = vertices; |
53 |
mesh.triangles = triangles; |
已知模型的頂點數量,頂點數量減去2就是三角形的數量,三角形的數量在乘以3就是三角形頂點的數量。根據這個公式計算得知,上述代碼中_共繪制4個三角形,頂點坐標數組應當是6,頂點ID數組應當是12。多個三角形在頂點ID數組中排列方式比較特殊,大家需要仔細記錄一下不然無法繪制出正確的三角形。如下圖所示,由于我這邊沒有合適的3D坐標點,就用正三角形拼接出一個正四邊形,這個四邊形是由6個頂點4個小三角形組成 ,看到這里思路清晰的朋友應當明了無規則四邊形的繪制原理和它完全一樣。只需要傳入適當的3D坐標點即可。

根據上面的邏輯,我們修改一下算法。假設三角形的頂點坐標為任意數量,我們需要更根據頂點坐標數量來計算對應頂點ID的數組內容。在for循環中 start =0 與end =3的含義是繪制從頂點坐標數組中索引為0的頂點開始繪制到數組索引為3的頂點,也就說是這里從0到3繪制了3個三角形。
[代碼]java代碼:
02 |
using System.Collections.Generic; |
05 |
public class Test : MonoBehaviour { |
08 |
private int VERTICES_COUNT = 6; |
12 |
//得到MeshFilter對象,目前是空的。 |
13 |
MeshFilter meshFilter = (MeshFilter)GameObject.Find("face").GetComponent(typeof(MeshFilter)); |
15 |
Mesh mesh = meshFilter.mesh; |
18 |
Vector3[] vertices = new Vector3[VERTICES_COUNT]; |
21 |
int triangles_count = VERTICES_COUNT - 2; |
24 |
int[] triangles = new int[triangles_count *3]; |
26 |
//三角形三個定點坐標,為了顯示清楚忽略Z軸 |
27 |
vertices[0] = new Vector3(0,0,0); |
28 |
vertices[1] = new Vector3(0,1,0); |
29 |
vertices[2] = new Vector3(1,0,0); |
30 |
vertices[3] = new Vector3(1,1,0); |
31 |
vertices[4] = new Vector3(2,0,0); |
32 |
vertices[5] = new Vector3(2,1,0); |
35 |
mesh.vertices = vertices; |
45 |
for(int j = 0; j < 3; j++) |
49 |
triangles[3*i + j] = i +j; |
52 |
triangles[3*i + j] = i + 2-j; |
58 |
mesh.triangles = triangles; |
如下圖所示,根據上面的邏輯算法,共繪制了3個三角形,并且頂點坐標ID是由 0 到3 。 說到這里請大家仔細想想本文的標題內容,其實兩個動態軌跡的點就是在維護triangles頂點坐標數組。triangles[0]、triangles[2]、triangles[4]……表示一個軌跡點的值,triangles[1]、triangles[3]、triangles[5]……就表示另一個軌跡點的值,最終將它們通過上面的算法將三角形面連接起來那么就是動態的兩個點軌跡繪制面了。

Unity3D其實非常好玩,上手雖然很簡單,但是想深入其實并沒有那么容易,今天這篇文章的思路已經寫完,如果還是沒能明白的朋友請仔細揣摩三角形與四邊形之間的區別。