年代久遠,圖片連接失效了,這裏從新放一個騰訊學院的版本,裏面有圖片數組
http://gad.qq.com/article/detail/33543ide
By:克森函數
在這篇文章中,咱們將會學到幾個概念:平移矩陣、旋轉矩陣、縮放矩陣。在學這幾個基本概念的同時,咱們會用到 Mesh(網格)、數學運算、4x4矩陣的一些簡單的操做。但因爲克森也是新手,文章的嚴謹性可能不是很高,還請大神們多多指教。工具
首先建立一個Unity工程,克森把他命名爲「Matrix of China」(中國的矩陣),基本配置以下圖所示:學習
爲了便於查找,讓咱們在 Assets 目錄下新建三個文件夾,分別命名爲「Scripts」、「Shader」、「Materials」,這個不用解釋,大夥們都看得懂吧。以下圖所示:測試
接下來再 Scripts 文件夾裏建立一個 C# 腳本,命名爲「Triangle」,該腳本用於建立一個簡單的三角形。而後在 Hierarchy 面板下建立一個空物體,命名爲「Triangle」。而後爲該物體添加以前建立的「Triangle」腳本,且爲該物體添加 Mesh 相關的兩個組件,以下圖所示:ui
好,接下來讓咱們開始碼了個碼。this
Triangle.cs spa
首先讓咱們看一看完整的代碼,而後再一步一步的分析:code
代碼解析
相信這段代碼對於大夥來講都不是很難吧。建立一個網格的步驟通常都是按這個順便來建立的:
1.爲頂點數組賦值
2.爲三角形數組賦值
在代碼中的「vertices」就是所謂的頂點數組、」triangles「就是所謂的三角形數組,它的做用其實就是對應頂點的索引。通常一個三角形是由三個頂點組成的。
好,讓咱們回到 Inspector 面板修改一下「Triangle」腳本的屬性,以下圖所示:
PS:三角形數組索引必須從0開始,按順序而後自增 1。且再次強調,三個頂點才能構成一個三角形。
好,如今讓咱們點擊 Play 進行測試一下:
Okey,如今咱們的三角形算是完成了,接下來開始玩弄它了。
首先建立一個 C# 腳本,命名爲「MyTransform」,併爲咱們的「Triangle」物體添加此腳本。代碼以下:
代碼解析
這段代碼很簡單,就是聲明一個 4x4 的矩陣,而後調用該 4x4 矩陣的 SetTRS 函數(T 表明 Translate(平移)、R 表明 Rotation(旋轉)、S 表明 Scale(縮放))。該函數用來設置一個平移、旋轉、縮放矩陣。在代碼中,咱們傳入的是該物體的 position、rotation、localScale,這樣作是爲了便於觀察相應的變換矩陣。
1平移矩陣
這個就是平移矩陣,其中 (Tx,Ty,Tz) 爲平移的方向向量,有些書上是把 Tx、Ty、Tz 放在第四行,當通過克森的測試,Unity的平移矩陣式這樣子的。下面咱們就作一個簡單的測試:
1.修改「Triangle」的 Position 爲(1,2,3)
2.點擊 Play 按鈕,觀察一下 matrix 屬性的變化:
圖中畫紅線的「E03」、「E13」、「E23」正好就是對應上面平移矩陣圖中的「Tx」、「Ty」、「Tz」,這說明Unity使用的正是這種方式的平移矩陣。
接下來,咱們利用平移矩陣作個簡單的平移,讓咱們回到「MyTransform」腳本中添加一些代碼:
代碼解析
以前在 Start 函數裏的代碼註釋掉,由於文章的後面還要用到。在代碼中,新添加了一個 Vector4 類型的變量,這是由於 4x4 的矩陣不能與三維向量相乘。
以後再 Start 函數中初始化了向量和矩陣,變量「v」存放的是當前物體的位置,而當前的矩陣爲單位矩陣(對於矩陣的乘法和單位矩陣我就不想講了,請大夥自行百度學習)。
而後找到矩陣中對應的平移的方向「Tx」、「Ty」、「Tz」,在代碼中,我讓物體向 X 軸方向平移3個單位、Y 軸方向平移4個單位、Z 軸方向平移5個單位。
以後執行矩陣變換的操做,矩陣的操做以下圖所示:
最後將計算的結果傳給物體的 Position。而後在 Start 函數裏調用一下該函數:
PS:記得將「Triangle」物體的 Position 設置爲 (0,0,0)。如今讓咱們點擊 Play 查看一下結果對不對:
好了,值是正確的。你們也能夠修改一下參數玩玩。至此,平移矩陣大致講完了,仍是有點懵的夥計能夠給克森說說。
這個就是縮放矩陣,其中「Sx」、「Sy」、「Sz」就是各個軸上的縮放因子。縮放矩陣是矩陣表現物體大小變換的矩陣。若是縮放因子小於1,表現爲物體縮小;若是大於1,則表現爲物體擴大,若是等於1則不發生變化。
接下來咱們作個簡單的測試,把取消以前 Start 函數裏的代碼,而後修改「Triangle」物體的 Scale 屬性爲(1,2,3),點擊 Play 查看一下結果:
找到對應的各個軸的縮放因子,目前來講結果是正確的了。
接下來,咱們利用縮放矩陣作個簡單的操做,讓咱們回到「MyTransform」腳本中添加一些代碼:
代碼解析
這段代碼和以前平移的代碼差不到哪裏去。代碼裏也給了註釋。主要就是矩陣的縮放操做不同,下面弄張圖就搞定了,縮放操做相對來講仍是蠻簡單的。
所以就有:
最後修改一下 Start 函數的代碼便可:
如今點擊 Play 按鈕查看一下結果是否正確:
Okey,看來結果是正確的。
PS:當各個軸上的縮放因子相等時,即:Sx=Sy=Sz 時,則爲均勻縮放。
上圖就是所謂的旋轉矩陣。在咱們的實踐中,我就使用沿 x- 軸進行旋轉作實踐便可。
首先仍是作個簡單的測試,讓咱們修改一下腳本,而後將物體的 Rotation參數設置爲 (45,0,0),最後點擊 Play 按鈕查看結果,以下圖所示:
在這裏我選擇了45°角,由於 sin45°和cos45° 的值是相等的(雖然在上圖中他們的值不相等,但其實是相等的,大夥們能夠用個 if 語句判斷一下),讓咱們看看結果對不對:
Okey,看來是正確的。
接下來,咱們利用旋轉矩陣作個簡單的操做,讓咱們回到「MyTransform」腳本中添加一些代碼:
因爲圖片是拼接的,全部有點彆扭
代碼解析
首先聲明瞭一個 float 類型的變量「angle」用於輸入須要旋轉的角度,以後又聲明瞭一個 emun(枚舉) 類型的變量「Axle」,用於選擇旋轉的方式。
接下在「MyRotation」函數中初始化了矩陣。接下來的判斷語句就是對應各個軸上的旋轉(能夠與上面那張旋轉矩陣進行對比,相信你們都能懂吧),在判斷語句中主要用到了三個函數:Mathf.Sin()、Mathf.Cos()、Mathf.Deg2Rad()。前面兩個函數你們都知道是什麼了吧,後面那個函數用於弧度轉角度,由於前面兩個函數接受的是一個弧度制的值。
接下來的代碼就是作矩陣轉爲四元數的操做,具體請看下圖中的公式:
最後將計算好的值傳給物體的 Rotation 便可
All right. 如今讓咱們回到物體的 Inspector 面板中修改「Angle」參數 和 Axle 選項,而後點擊 Play 按鈕進行測試便可(在這裏克森選擇的是,繞 X 軸旋轉45°):
Perfect. 和咱們預期的效果同樣,大夥們能夠自行修改參數進行測試一番。
最後給你們送上一個小工具,只需傳入一個變換矩陣便可幫你完成平移、旋轉、縮放的工做,而後把值傳給物體的 Position、Rotation、Scale:
接下來用一個例子來演示這個小工具怎麼使用。
回到咱們的場景中,找到「Triangle」物體,在 Inspector 面板中修改「MyTransform」腳本的「Matrix」屬性,以下圖所示:
紅色箭頭表明平移、綠色箭頭表明縮放、黃色箭頭表明旋轉,這個變換矩陣表示的是:物體在X軸上平移3個單位、Y軸上平移4個單位、Z軸上平移5個單位(position (3,4,5));物體繞着X軸旋轉90° (Rotation(90,0,0));物體沒有縮放 (1,1,1) 。
而後回到「MyTransform」腳本的Start函數中調用工具類裏的方法完成變換矩陣的各項操做:
最後點擊 Play 按鈕查看結果:
Perfect. 看來和咱們預期的效果如出一轍,大夥們能夠自行修改參數進行測試。
好了,這篇文章就到這裏了。這部份內容也是克森最近剛剛學的,也算是學習筆記吧,若是有什麼錯誤的地方還請大神們指教指教。
附上代碼:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Tringle : MonoBehaviour { private Mesh mesh; public Vector3[] vertices; public int[] triangle; // Use this for initialization void Start () { mesh = new Mesh (); mesh.vertices = vertices; mesh.triangles = triangle; var meshRender = GetComponent<MeshRenderer> (); if (meshRender == null) meshRender = this.gameObject.AddComponent<MeshRenderer> (); var meshFilter = GetComponent<MeshFilter> (); if (meshFilter == null) meshFilter = this.gameObject.AddComponent<MeshFilter> (); meshFilter.mesh = mesh; } // Update is called once per frame void Update () { } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public enum Axle { X, Y, Z, } public class MyTransform : MonoBehaviour { public Axle axle; public Vector4 v4; public Matrix4x4 matrix; // Use this for initialization void Start () { //matrix.SetTRS ( // transform.position, // transform.rotation, // transform.localScale //); } void MyTranslate (float x, float y, float z) { v4 = new Vector4 ( transform.position.x, transform.position.y, transform.position.z, 1 ); /* identity * 1 0 0 0 * 0 1 0 0 * 0 0 1 0 * 0 0 0 1 */ matrix = Matrix4x4.identity; // pos matrix.m03 = x; matrix.m13 = y; matrix.m23 = z; /* pos transform * 1 0 0 x * pos.x 1 * pos.x + 0 * pos.x + 0 * pos.x + x * pos.x x * pos.x * 0 1 0 y * pos.y == ... == y * pos.y * 0 0 1 z * pos.z ... z * pos.z * 0 0 0 1 * 1 ... 1 */ v4 = matrix * v4; transform.position = new Vector3 (v4.x, v4.y, v4.z); } void MyScale(float x, float y, float z) { v4 = new Vector4 ( transform.localScale.x, transform.localScale.y, transform.localScale.z, 1 ); /* identity * 1 0 0 0 * 0 1 0 0 * 0 0 1 0 * 0 0 0 1 */ matrix = Matrix4x4.identity; matrix.m00 = x; matrix.m11 = y; matrix.m22 = z; v4 = matrix * v4; transform.localScale = new Vector3 (v4.x, v4.y, v4.z); } void MyRotation(Axle axle, float angle) { matrix = Matrix4x4.identity; // set matrix if (axle == Axle.X) { matrix.m11 = Mathf.Cos (angle * Mathf.Deg2Rad); matrix.m22 = -Mathf.Sin (angle * Mathf.Deg2Rad); matrix.m21 = Mathf.Sin (angle * Mathf.Deg2Rad); matrix.m22 = Mathf.Cos (angle * Mathf.Deg2Rad); } else if (axle == Axle.Y) { matrix.m00 = Mathf.Cos (angle * Mathf.Deg2Rad); matrix.m02 = Mathf.Sin (angle * Mathf.Deg2Rad); matrix.m20 = -Mathf.Sin (angle * Mathf.Deg2Rad); matrix.m22 = Mathf.Cos (angle * Mathf.Deg2Rad); } else if (axle == Axle.Z) { matrix.m00 = Mathf.Cos (angle * Mathf.Deg2Rad); matrix.m01 = -Mathf.Sin (angle * Mathf.Deg2Rad); matrix.m10 = Mathf.Sin (angle * Mathf.Deg2Rad); matrix.m11 = Mathf.Cos (angle * Mathf.Deg2Rad); } // to quaternion float qw = Mathf.Sqrt(1f + matrix.m00 + matrix.m11, matrix.m22) / 2; float w = 4 * qw; float qx = (matrix.m21 - matrix.m12) / w; float qy = (matrix.m02 - matrix.m20) / w; float qz = (matrix.m10 - matrix.m101) / w; transform.rotation = new Quaternion (qx, qy, qz, qw); } }