【Unity Shader入門】數學基礎:矩陣

【Unity Shader入門】Unity Shader概述:渲染流水線
【Unity Shader入門】Unity Shader基礎:ShaderLab
【Unity Shader入門】數學基礎:總結目錄

矩陣

一個m×n的矩陣是一個由m行n列元素排列成的矩形陣列

矩陣的運算

特殊矩陣

方塊矩陣

方塊矩陣,簡稱方陣,是指那些行和列數目相等的矩陣。在三維渲染裏,最常使用的就是3×3和4×4的方陣
方陣的對角元素指的是行號和列號相等的元素。
如果一個矩陣除了對角元素外的所有元素都爲0,那麼這個矩陣就叫做對角矩陣
一個4×4的對角矩陣:
[3000020000100007] \begin{bmatrix} 3 & 0 & 0 & 0 \\ 0 & -2 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 7 \\ \end{bmatrix}

單位矩陣

如果一個對角矩陣的對角元素都爲1,那麼這個矩陣被稱爲單位矩陣。一個3×3的單位矩陣如下所示:
I3=[100010001] I_3= \begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \\ \end{bmatrix}
任何矩陣和單位矩陣相乘的結果都還是原來的矩陣。這就跟標量中的1一樣。
MI=IM=M MI=IM=M

轉置矩陣

轉置矩陣實際上是通過對原矩陣進行轉置運算得到的。給定一個r×c的矩陣M,它的轉置矩陣可以表示成MT,這是一個c×r的矩陣。轉置運算就是把原矩陣翻轉一下,即原矩陣的第i行變成了第j列,而第j列變成了第i行。
如果一個矩陣的轉置矩陣是其本身,則我們稱其爲對稱矩陣

公式
MijT=Mji M_{ij}^T=M_{ji}
對於行矩陣和列矩陣來說,我們可以使用轉置運算來相互轉換:
[xyz]T=[xyz] \begin{bmatrix} x & y & z \\ \end{bmatrix}^T= \begin{bmatrix} x \\ y \\ z \\ \end{bmatrix}
[xyz]T=[xyz] \begin{bmatrix} x \\ y \\ z \\ \end{bmatrix}^T= \begin{bmatrix} x & y & z \\ \end{bmatrix}

性質
矩陣轉置的轉置等於原矩陣
(MT)T=M (M^T)^T=M
矩陣的串接的轉置,等於反向串接各個矩陣的轉置。這個性質可以擴展到更多矩陣相乘的情況
(AB)T=BTAT (AB)^T = B^TA^T

逆矩陣

給定一個方陣M,它的逆矩陣用M-1來表示。逆矩陣最重要的性質就是把M和M-1相乘,那麼它們的結果將會是一個單位矩陣
只有方陣纔有逆矩陣,且並不是所有的方陣都有逆矩陣。
如何判斷一個矩陣是否可逆:如果一個矩陣的行列式不爲0,那麼它就是可逆的。
例如所有元素都爲0的方陣就沒有逆矩陣
如果一個矩陣有對應的逆矩陣,我們就說這個矩陣是可逆的或者說是非奇異的。否則這個矩陣就是不可逆的或者說是奇異的

公式
MM1=M1M=I MM^{-1} = M^{-1} M=I

性質
逆矩陣的逆矩陣是原矩陣本身
(M1)1=M (M^{-1})^{-1}=M
單位矩陣的逆矩陣是它本身
I1=I I^{-1}=I
轉置矩陣的逆矩陣是逆矩陣的轉置
(MT)1=(M1)T (M^T)^{-1}=(M^{-1})^T
矩陣串接相乘後的逆矩陣等於反向串接各個矩陣的逆矩陣。這個性質可以擴展到更多矩陣相乘的情況
(ABCD)1=D1C1B1A1 (ABCD)^{-1} = D^{-1} C^{-1} B^{-1} A^{-1}
逆矩陣是有幾何意義的,一個矩陣可以表示一個變換,而逆矩陣允許我們還原這個變換。假設,我們使用變換矩陣M對矢量進行了一次變換,然後再使用M的逆矩陣M-1進行另一次變換,那麼我們會得到原來的矢量。

正交矩陣

如果一個方陣M和它的轉置矩陣的乘積是單位矩陣的話,我們就稱這個矩陣是正交的
再結合逆矩陣的公式,我們可以知道,如果一個矩陣是正交的,那麼它的轉置矩陣和逆矩陣是一樣的

公式
MMT=MTM=I MM^T = M^T M=I
MT=M1 M^T = M^{-1}

在三維變換中,我們經常會使用逆矩陣來求解反向的變換。但逆矩陣的求解往往計算量很大,而如果我們可以確定這個矩陣是正交矩陣的話,就可以直接通過轉置矩陣得到逆矩陣。
那麼如何判斷的一個矩陣是否是正交矩陣呢,當然可以通過公式計算判斷,但這仍然需要一定的計算量,有時候我們更希望不通過計算,而根據一個矩陣的構造過程來判斷這個矩陣是否是正交矩陣
根據正交矩陣的定義可以得到:
MTM=[c1c2c3][c1c2c3] M^TM= \begin{bmatrix} -& c1 & - \\ -& c2 & - \\ -& c3 & - \\ \end{bmatrix} \begin{bmatrix} |& | & | \\ c1& c2& c3 \\ |& | & | \\ \end{bmatrix}
=[c1c1c1c2c1c3c2c1c2c2c2c3c3c1c3c2c3c3]=[100010001]=I =\begin{bmatrix} c1\sdot c1 & c1\sdot c2 & c1\sdot c3 \\ c2\sdot c1 & c2\sdot c2 & c2\sdot c3 \\ c3\sdot c1 & c3\sdot c2 & c3\sdot c3\\ \end{bmatrix}= \begin{bmatrix} 1& 0 &0 \\ 0&1& 0 \\ 0& 0& 1\\ \end{bmatrix} =I

這樣,我們就有個9個等式:
c1c1=1,c1c2=0,c1c3=0 c1\sdot c1 =1 , c1\sdot c2 =0 , c1\sdot c3 =0
c2c1=0,c2c2=1,c2c3=0 c2\sdot c1 =0 , c2\sdot c2 =1 , c2\sdot c3 =0
c3c1=0,c3c2=0,c3c3=1 c3\sdot c1 =0 , c3\sdot c2 =0 , c3\sdot c3 =1
可以得到如下結論:
1、矩陣的每一行(即c1,c2,c3)都是單位矢量,因爲它們與自己的點積爲1
2、矩陣的每一行(即c1,c2,c3)都互相垂直,因爲它們互相的點積爲0(參考點積的公式|a||b|cosθ)
3、上述的兩條結論對每一列也同樣適用。因爲M是正交矩陣的話,MT也是正交矩陣
也就說如果一個矩陣滿足上面的條件,那麼它就是一個正交矩陣。

行矩陣還是列矩陣

由於一個矢量既可以轉換成一個行矩陣也可以轉換成列矩陣,雖然它們本身是沒有區別的,但當需要把它和另一個矩陣相乘時,就會出現差異,因爲矩陣的乘法是不滿足交換律的。
假設有一個矢量v=(x,y,z),轉換成行列矩陣:
v=[vxvyvz]v=[vxvyvz] 行矩陣:v=\begin{bmatrix} v_x & v_y & v_z \\ \end{bmatrix} 列矩陣:v=\begin{bmatrix} v_x \\ v_y \\ v_z \\ \end{bmatrix}
現在,有另一個矩陣M:
M=[m11m12m13m21m22m23m31m32m33] M=\begin{bmatrix} m_{11} & m_{12} & m_{13} \\ m_{21} & m_{22} & m_{23} \\ m_{31} & m_{32} & m_{33} \\ \end{bmatrix}
行矩陣和M矩陣相乘:
vM=[xm11+ym21+zm31xm12+ym22+zm32xm13+ym23+zm33] vM=\begin{bmatrix} xm_{11} + ym_{21} + zm_{31} &xm_{12} + ym_{22} + zm_{32} & xm_{13} + ym_{23} + zm_{33} \\ \end{bmatrix}
列矩陣和M矩陣相乘:
Mv=[xm11+ym12+zm13xm21+ym22+zm23xm31+ym32+zm33] Mv=\begin{bmatrix} xm_{11} + ym_{12} + zm_{13} \\ xm_{21} + ym_{22} + zm_{23} \\ xm_{31} + ym_{32} + zm_{33} \\ \end{bmatrix}

對比就會發現,結果矩陣除了行列矩陣的區別外,裏面的元素也是不一樣的。這就意味着, 在和矩陣相乘時選擇行矩陣還是列矩陣來表示矢量是非常重要的,因爲這決定了矩陣乘法的書寫次序和結果值。

在Unity中,常規做法是把矢量放在矩陣的右側,即把矢量轉換成列矩陣來進行計算。此時我們的閱讀順序是從右到左的。即對矢量v先使用A進行變換,再使用B進行變換,最後使用C進行變換。
CBAv=(C(B(Av))) CBA_v=(C(B(A_v)))
vATBTCT=(((vAT)BT)CT) _vA^TB^TC^T=(((_vA^T)B^T)C^T)

幾何意義:變換

變換:是把一些數據(點、矢量、顏色)通過某種方式進行轉換的過程。
線性變換:是指可以保留矢量加和標量乘的變換。其數學公式是:
f(x)+f(y)=f(x+y) f(x) + f(y) = f(x+y)
kf(x)=f(kx) kf(x) = f(kx)

線性變換都包括:旋轉、縮放、錯切(Shear)、鏡像(Mirroring)、正交投影(orthographic projection)。
仿射變換(affine transform)可以合併線性變換平移變換,將仿射變換擴展到4維空間下用4x4的矩陣來表示,它就齊次座標空間

齊次座標空間

由於3×3矩陣不能表示一個平移操作,就將其擴展到了4×4的矩陣。爲此,還需要把原來的三維矢量轉換成四維座標,也就是齊次座標(齊次座標的維度可以超過四維,但本文泛指四維齊次座標)。
如何把一個三維矢量轉換成四維矢量呢:
1、對於一個點,從三維座標轉換成齊次座標就是把w分量設置爲1
2、對於方向矢量,需要把w分量設置爲0。這樣當用4×4矩陣進行變換時,平移的效果會被忽略(因爲方向矢量沒有位置)。

基礎變換矩陣

可以使用一個4x4的矩陣來表示平移、旋轉和縮放。把表示純平移、純旋轉和純縮放的變換矩陣叫做基礎變換矩陣。這些矩陣具有一些共同點,可以把一個基礎變換矩陣分解成4 個組成部分:
[M3×3t3×101×31] \begin{bmatrix} M_{3×3} & t_{3×1} \\ 0_{1×3} & 1 \\ \end{bmatrix}

平移矩陣

我們可以使用矩陣乘法來表示對一個點進行平移變換,如下所示,從結果很容易看出這個矩陣爲什麼有平移效果:點的x, y, z分量分別增加了一個位置偏移,即把點(x, y, z)在空間中平移了(tx, ty, tz)個單位。
[100tx010ty001tz0001][xyz1]=[x+txy+tyz+tz1] \begin{bmatrix} 1 & 0 & 0 & t_x \\ 0 & 1 & 0 & t_y \\ 0 & 0 & 1 & t_z \\ 0 & 0 & 0 & 1 \\ \end{bmatrix} \begin{bmatrix} x \\ y \\ z \\ 1 \\ \end{bmatrix} = \begin{bmatrix} x + t_x \\ y + t_y \\ z + t_z \\ 1 \\ \end{bmatrix}

對一個方向矢量進行平移變換,不會對其產生任何影響:
[100tx010ty001tz0001][xyz0]=[xyz0] \begin{bmatrix} 1 & 0 & 0 & t_x \\ 0 & 1 & 0 & t_y \\ 0 & 0 & 1 & t_z \\ 0 & 0 & 0 & 1 \\ \end{bmatrix} \begin{bmatrix} x \\ y \\ z \\ 0 \\ \end{bmatrix} = \begin{bmatrix} x \\ y \\ z \\ 0 \\ \end{bmatrix}

平移矩陣的逆矩陣就是反向平移得到的矩陣。可以看出平移矩陣並不是一個正交矩陣。
[100tx010ty001tz0001] \begin{bmatrix} 1 & 0 & 0 & -t_x \\ 0 & 1 & 0 & -t_y \\ 0 & 0 & 1 & -t_z \\ 0 & 0 & 0 & 1 \\ \end{bmatrix}

縮放矩陣

我們可以使用矩陣乘法來表示一個縮放變換:
[kx0000ky0000kz00001][xyz1]=[kxxkyykzz1] \begin{bmatrix} k_x & 0 & 0 & 0 \\ 0 & k_y & 0 & 0 \\ 0 & 0 & k_z & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix} \begin{bmatrix} x \\ y \\ z \\ 1 \\ \end{bmatrix} = \begin{bmatrix} k_xx \\ k_yy \\ k_zz \\ 1 \\ \end{bmatrix}
對方向矢量同樣可以進行縮放:
[kx0000ky0000kz00001][xyz0]=[kxxkyykzz0] \begin{bmatrix} k_x & 0 & 0 & 0 \\ 0 & k_y & 0 & 0 \\ 0 & 0 & k_z & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix} \begin{bmatrix} x \\ y \\ z \\ 0 \\ \end{bmatrix} = \begin{bmatrix} k_xx \\ k_yy \\ k_zz \\ 0 \\ \end{bmatrix}
如果縮放係數Kx = Ky = Kz,我們把這樣的縮放稱爲統一縮放,否則稱爲非統一縮放。從外觀上看,統一縮放是擴大整個模型,而非統一縮放會拉伸或擠壓模型。更重要的是,統一縮放不會改變角度和比例信息,而非統一縮放會改變與模型相關的角度和比例。例如在對法線進行變換時,如果存在非統一縮放,直接使用用於變換頂點的變換矩陣的話,就會得到錯誤的結果。

縮放矩陣的逆矩陣是使用原縮放矩陣係數的倒數來進行縮放,縮放矩陣一般也不是正交矩陣。

[1kx00001ky00001kz00001] \begin{bmatrix} \frac 1 { k_x} & 0 & 0 & 0 \\ 0 & \frac 1 { k_y} & 0 & 0 \\ 0 & 0 & \frac 1 { k_z} & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix}
上面的矩陣只適用於沿座標軸方向進行縮放。如果我們希望在任意方向上進行縮放,就需要使用一個複合變換。其中一種方法的主要思想就是,先將縮放軸變換成標準座標軸,然後進行沿座標軸的縮放,再使用逆變換得到原來的縮放軸朝向。

旋轉矩陣

旋轉是三種常見的變換矩陣中最複雜的一種。我們知道,旋轉操作需要指定一個旋轉軸,這個旋轉軸不一定是空間中的座標軸,但這裏旋轉就是指繞着空間中的x 軸, y 軸或z 軸進行旋轉。
如果我們需要把點繞着x 軸旋轉θ度,可以使用下面的矩陣:
Rx(θ)=[10000cosθsinθ00sinθcosθ00001] R_{x}(\theta)= \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & \cos \theta & -\sin \theta & 0 \\ 0 & \sin \theta & \cos \theta & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix}
同理,繞y 軸的旋轉如下所示:
Ry(θ)=[cosθ0sinθ00100sinθ0cosθ00001] R_{y}(\theta)= \begin{bmatrix} \cos \theta & 0 & \sin \theta & 0 \\ 0 & 1 & 0 & 0 \\ -\sin \theta & 0 & \cos \theta & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix}
繞z 軸的旋轉如下所示:
Rz(θ)=[cosθsinθ00sinθcosθ0000100001] R_{z}(\theta)= \begin{bmatrix} \cos \theta & \sin \theta & 0 & 0 \\ \sin \theta & \cos \theta & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix}

旋轉矩陣的逆矩陣是旋轉相反角度得到的變換矩陣。旋轉矩陣是正交矩陣,而且多個旋轉矩陣之間的串聯同樣是正交的。

複合變換

我們可以把平移、旋轉和縮放組合起來,來形成一個複雜的變換過程。
Pnew=MtranslationMrotationMscalθPold 複合變換公式:P_{new} = M_{translation}M_{rotation}M_{scal\theta}P_{old}
由於上面我們使用的是列矩陣,因此閱讀順序是從右到左,即先進行縮放變換,再進行旋轉變換,最後進行平移變換。需要注意的是,變換的結果是依賴於變換順序的,由於矩陣乘法不滿足交換律,因此矩陣的乘法順序很重要。想象一下,如果讓讀者向前一步然後左轉,記住此時的位置。然後回到原位,這次先左轉再向前走一步,得到的位置和上一次是不一樣的。究其本質,是因爲矩陣的乘法不滿足交換律,因此不同的乘法順序得到的結果是不一樣的
在絕大多數情況下,我們約定變換的順序就是先縮放,再旋轉,最後平移。

對比不同變換順序產生的變換矩陣的表達式。如果只考慮對y 軸的旋轉的話,按先縮放、再旋轉、最後平移這樣的順序組合3 種變換得到的變換矩陣是:
MrotationMscalθMtranslation=[cosθ0sinθ00100sinθ0cosθ00001][kx0000ky0000kz00001][100tx010ty001tz0001] M_{rotation}M_{scal\theta}M_{translation}= \begin{bmatrix} \cos \theta & 0 & \sin \theta & 0 \\ 0 & 1 & 0 & 0 \\ -\sin \theta & 0 & \cos \theta & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix} \begin{bmatrix} k_x & 0 & 0 & 0 \\ 0 & k_y & 0 & 0 \\ 0 & 0 & k_z & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 & t_x \\ 0 & 1 & 0 & t_y \\ 0 & 0 & 1 & t_z \\ 0 & 0 & 0 & 1 \\ \end{bmatrix}
=[kxcosθ0kxsinθtxkxcosθ+tzkzsinθ0ky0txkxkxsinθ0kxcosθtxkxsinθ+tzkzcosθ0001] =\begin{bmatrix} k_x\cos \theta & 0 & k_x\sin \theta & t_xk_x\cos \theta + t_zk_z\sin \theta \\ 0 & k_y & 0 & t_xk_x \\ -k_x\sin \theta & 0 & k_x\cos \theta & -t_xk_x\sin \theta + t_zk_z\cos \theta \\ 0 & 0 & 0 & 1 \\ \end{bmatrix}
而如果使用了其他變換順序,例如先平移,再縮放,最後旋轉,那麼得到的變換矩陣是:
MtranslationMrotationMscalθ=[100tx010ty001tz0001][cosθ0sinθ00100sinθ0cosθ00001][kx0000ky0000kz00001] M_{translation}M_{rotation}M_{scal\theta}= \begin{bmatrix} 1 & 0 & 0 & t_x \\ 0 & 1 & 0 & t_y \\ 0 & 0 & 1 & t_z \\ 0 & 0 & 0 & 1 \\ \end{bmatrix}\begin{bmatrix} \cos \theta & 0 & \sin \theta & 0 \\ 0 & 1 & 0 & 0 \\ -\sin \theta & 0 & \cos \theta & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix} \begin{bmatrix} k_x & 0 & 0 & 0 \\ 0 & k_y & 0 & 0 \\ 0 & 0 & k_z & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix}
=[kxcosθ0kxsinθtx0ky0tykxsinθ0kzcosθtz0001] =\begin{bmatrix} k_x\cos \theta & 0 & k_x\sin \theta & t_x \\ 0 & k_y & 0 & t_y \\ -k_x\sin \theta & 0 & k_z\cos \theta & -t_z \\ 0 & 0 & 0 & 1 \\ \end{bmatrix}
從兩個結果可以看出,得到的變換矩陣是不一樣的。
除了需要注意不同類型的變換順序外,有時還需要小心旋轉的變換順序。如果我們需要同時繞着3個軸進行旋轉,那麼應該按什麼樣的旋轉順序呢?
當直接給出( θx, θy, θz)這樣的旋轉角度時,需要定義一個旋轉順序。在Unity 中,這個旋轉順序是zxy,這在旋轉相關的API 文檔中都有說明。這意味着,當給定(θx, θy, θz)這樣的旋轉角度時,得到的組合旋轉變換矩陣是:
MrotatθzMrotatθxMrotatθy=[cosθsinθ00sinθcosθ0000100001][10000cosθsinθ00sinθcosθ00001][cosθ0sinθ00100sinθ0cosθ00001] M_{rotat\theta z}M_{rotat\theta x}M_{rotat\theta y}= \begin{bmatrix} \cos \theta & \sin \theta & 0 & 0 \\ \sin \theta & \cos \theta & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & \cos \theta & -\sin \theta & 0 \\ 0 & \sin \theta & \cos \theta & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix} \begin{bmatrix} \cos \theta & 0 & \sin \theta & 0 \\ 0 & 1 & 0 & 0 \\ -\sin \theta & 0 & \cos \theta & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix}
旋轉時使用的座標系也有以下兩種選擇:
1、繞座標系E下的z 軸旋轉θz,繞座標系E 下的y 軸旋轉θy,繞座標系E 下的x 軸旋轉θx,即進行一次旋轉時不一起旋轉當前座標系。
2、繞座標系E下的z 軸旋轉θz,在座標系E 下在繞z 軸旋轉θz 後的新座標系E’下的y 軸旋轉θy , 在座標系E’下再繞y 軸旋轉θy 後的新座標系E”下的x 軸旋轉θx,即在旋轉時,把座標系一起轉動。

很容易知道,這兩種選擇的結果是不一樣的。但如果把它們的旋轉順序顛倒一下,它們得到的結果就會是一樣的!說得明白點,在第一種情況下,按zxy 順序旋轉和在第二種情況下,按yxz順序旋轉是一樣的。而Unity 文檔中說明的旋轉順序指的是在第一種情況下的順序。
和上面不同類型的變換順序導致的問題類似,不同的旋轉順序得到的結果也可能是不一樣的。同樣可以通過對比不同旋轉順序得到的變換矩陣來理解爲什麼會出現這樣的不同。

錯切矩陣

鏡像矩陣

正交投影矩陣

透視投影矩陣

Unity中投射投影矩陣與正交投影

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章