1. 程式人生 > >《Unity Shader入門精要》筆記 #第四章 學習Shader所需的數學基礎

《Unity Shader入門精要》筆記 #第四章 學習Shader所需的數學基礎

不懂數學者不得入內

1、笛卡爾座標系

旋向性

旋轉正方向

Unity採用的座標系

        模型空間及世界空間 - 左手座標系

        觀察空間 - 右手座標系

2、點和向量

點積 - 投影

叉積 - 計算垂直於一個平面、三角形的向量;判斷三角面片朝向

3、矩陣

4、矩陣變換

線性變換:縮放、旋轉、錯切、映象、正交投影,3*3

仿射變換:合併線性變換和平移變換,4*4矩陣,擴充套件到四維空間下即齊次座標空間

\begin{bmatrix} {M_{3*3}}^{} &{t_{3*1}}^{}&\\ {0_{1*3}}^{}& 1 & \end{bmatrix},M(3*3)用於旋轉縮放,t(3*1)用於表示平移,0(1*3)是零矩陣

-平移矩陣

對點:

\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}

向量平移:

\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}

平移矩陣的逆矩陣:

\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} {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_{x}}x\\ {k_{y}}y\\ {k_{z}}z\\ 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} x\\ y\\ z\\ 0 \end{bmatrix} = \begin{bmatrix} {k_{x}}x\\ {k_{y}}y\\ {k_{z}}z\\ 0\\ \end{bmatrix}

若k(x) = k(y) = k(z),則為統一縮放

-旋轉矩陣

繞軸旋轉

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}

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}

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}

-複合變換

-先縮放,再旋轉,最後平移,由於是列矩陣,從右向左讀起

p_{new} = M_{translation}M_{rotation}M_{scal\theta }p_{old}

-旋轉順序,在Unity中,旋轉順序是zxy

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}

Unity中的旋轉順序按照一種順序,所以不用從右向左讀起

5、座標空間

5.1 數學鋪墊:

問題一般化。定義座標空間需要明確原點和3個座標軸方向。這些數值相對於另一個座標空間,每個座標空間都是另一個座標空間的子空間,每個空間都有一個父座標空間。座標空間的變換是父空間和子空間之間對點和向量進行變換。

A_{p}=M_{c->p}A_{c}

B_{c}=M_{p->c}B_{p}

兩種需求,M_{p->c}

M_{c->p}的逆矩陣,求解其中一個即可

對點:

M_{c->p}的步驟:

           -從座標空間的原點開始

           -向x軸方向移動a個單位 

           -向y軸方向移動b個單位 

           -向z軸方向移動c個單位 

-從座標空間的原點開始

已知子座標空間的原點位置\overline{O_{c}}

-向x軸方向移動a個單位

已知x軸矢量表示,則 \overline{O_{c}}+a\overline{x_{c}}

-向y軸方向移動b個單位 

已知y軸矢量表示,則 \overline{O_{c}}+a\overline{x_{c}}+b\overline{y_{c}}

-向z軸方向移動c個單位 

已知z軸矢量表示,則\overline{O_{c}}+a\overline{x_{c}}+b\overline{y_{c}}+c\overline{z_{c}}

\overline{A_{p}}=\overline{O_{c}}+a\overline{x_{c}}+b\overline{y_{c}}+c\overline{z_{c}}

         =\left ( x_{oc},y_{oc},z_{oc}\right )+a\left ( x_{xc},y_{xc},z_{xc}\right )+ b\left ( x_{yc},y_{yc},z_{yc}\right )+c\left ( x_{zc},y_{zc},z_{zc}\right )

         =\left ( x_{oc},y_{oc},z_{oc}\right )+\begin{bmatrix} x_{xc}& x_{yc} & x_{zc}\\ y_{xc}& y_{yc} & y_{zc} \\ z_{xc}& z_{yc}& z_{zc} \end{bmatrix}\begin{bmatrix} a\\ b\\ c \end{bmatrix}         

         =\left ( x_{oc},y_{oc},z_{oc}\right )+\begin{bmatrix} |& | & |}\\ x_{c}& y_{c} & y_{c} \\ |& |& | \end{bmatrix}\begin{bmatrix} a\\ b\\ c \end{bmatrix}         

擴充套件到齊次座標空間,得到  

         A_{p}=( x_{oc},y_{oc},z_{oc},1)+ \begin{bmatrix} |& | & | & 0}\\ x_{c}& y_{c} & y_{c} & 0 \\ |& |& | &0\\ 0&0&0&1 \end{bmatrix} \begin{bmatrix} a\\ b\\ c \\1\end{bmatrix}     

               =\begin{bmatrix} 1& 0 & 0 & x_{Oc}}\\ 0& 1 & 0 & y_{Oc} \\ 0& 0& 1 &z_{Oc}\\ 0&0&0&1 \end{bmatrix} \begin{bmatrix} |& | & | & 0}\\ x_{c}& y_{c} & y_{c} & 0 \\ |& |& | &0\\ 0&0&0&1 \end{bmatrix} \begin{bmatrix} a\\ b\\ c \\1\end{bmatrix}       

               =\begin{bmatrix} |& | & | & x_{Oc}}\\ x_{c}& y_{c} & y_{c} & y_{Oc} \\ |& |& | &z_{Oc}\\ 0&0&0&1 \end{bmatrix} \begin{bmatrix} a\\ b\\ c \\1\end{bmatrix}     

               =\begin{bmatrix} |& | & | & |}}\\ x_{c}& y_{c} & y_{c} & O_{c} \\ |& |& | &|\\ 0&0&0&1 \end{bmatrix} \begin{bmatrix} a\\ b\\ c \\1\end{bmatrix}       

M_{c->p}=\begin{bmatrix} |& | & | & |}}\\ x_{c}& y_{c} & y_{c} & O_{c} \\ |& |& | &|\\ 0&0&0&1 \end{bmatrix}

反向思維,可以從這個式子獲取子座標空間的原點和座標軸方向。eg,已知從模型空間到世界空間的4*4變換矩陣,可以提取第一列進行歸一化後得到模型空間的x軸在世界空間下的單位矢量表示。

對向量:

M_{c->p}=\begin{bmatrix} |& | & |\\ x_{c}& y_{c} & y_{c} \\ |& |& |\end{bmatrix},對法線、光照方向進行變換

M_{p->c}不需要求逆矩陣的情況:本身是正交矩陣

驗證按行或是按列擺放:帶入計算

5.2 在渲染流水線中的一個頂點經過的座標空間變換

-模型空間

Unity的模型空間+x,+y,+z對應右、上、前,擴充到齊次座標系下

-世界空間

將頂點座標從模型空間變換到世界空間中,叫做模型變換

對點的模型變換矩陣:p_{new} = M_{translation}M_{rotation}M_{scal\theta }p_{old}

-觀察空間

+x右方,+y上方,+z後方

將頂點座標從世界空間變換到觀察空間中,叫做觀察變換

兩種方法:計算觀察空間的3個座標軸在世界空間下的表達,再求逆;平移整個觀察空間,讓攝像機原點位於世界座標原點,座標軸與世界空間座標軸重合即可。

對點的觀察變換矩陣:p_{new} = M_{rotation}M_{translation}p_{old}但由於是右手系,需要對z分量取反

M_{view} = \begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & 1 & 0 & 0\\ 0 & 0 & -1 & 0\\ 0& 0 & 0 & 0 \end{bmatrix}M_{rotation}M_{translation}

最後p_{new} = M_{view}p_{old}

-裁剪空間

用於變換的裁剪矩陣/投影矩陣。視錐體有兩種型別:正交投影和透視投影,6塊裁剪平面

投影矩陣的兩個目的:為投影做準備;對x/y/z分量進行縮放。

在裁剪空間前雖然使用齊次座標表示點和向量,點第四個分量w為1,向量第四分量為0.經過投影矩陣變換後有新含義。

透視投影

六塊裁剪平面,通過FOV和clipping plane中的near和far引數控制攝像機遠近。

近裁剪平面和遠裁剪平面高度:

                         nearClipPlaneHeight = 2*Near*tan\frac{FOV}{2}

                         farClipPlaneHeight = 2*Far*tan\frac{FOV}{2}

假設當前攝像機的橫縱比為Aspect,則

Aspect=\frac{nearClipPlaneWidth}{nearClipPlaneHeight}

Aspect=\frac{farClipPlaneWidth}{farClipPlaneHeight}

根據已知Near、Far、FOV、Aspect值確定透視投影的投影矩陣如下(觀察空間右手座標系建立),變換後z分量範圍將在[-w,w]之間:

M_{frustum}=\begin{bmatrix} \frac{cot\frac{FOV}{2}}{Aspect}&0 &0 & 0\\ 0& cot\frac{FOV}{2} & 0 & 0\\ 0& 0 & -\frac{Far+Near}{Far-Near} & \frac{2*Near*Far}{Far-Near}\\ 0& 0& -1 & 0 \end{bmatrix}

在頂點和上述矩陣相乘:p_{clip}=M_{frustum}p_{view}

        =\begin{bmatrix} \frac{cot\frac{FOV}{2}}{Aspect}&0 &0 & 0\\ 0& cot\frac{FOV}{2} & 0 & 0\\ 0& 0 & -\frac{Far+Near}{Far-Near} & \frac{2*Near*Far}{Far-Near}\\ 0& 0& -1 & 0 \end{bmatrix} \begin{bmatrix} x\\ y\\ z\\ 1 \end{bmatrix}

        =\begin{bmatrix} x\frac{cot\frac{FOV}{2}}{Aspect}\\ ycot\frac{FOV}{2}\\ -z\frac{Far+Near}{Far-Near} - \frac{2*Near*Far}{Far-Near}\\ -z \end{bmatrix}

若變換後一個頂點位於是椎體內,則座標必須滿足x, y,z\in [-w,w],且裁剪矩陣改變空間旋向性,空間從右手座標系變換到了左手座標系,離攝像機越遠,z值越大。

正交投影

六個裁剪平面,是由Camera組建中的引數和Game檢視的橫縱比共同決定。

正交投影的視錐體是一個長方體,因此計算上相比透視投影更簡單。

                        nearClipPlaneHeight = 2*Size

                        farClipPlaneHeight = nearClipPlaneHeight

攝像機橫縱比Aspect:

                        nearClipPlaneWidth = Aspect*nearClipPlaneHeight

                        farClipPlaneWidth = nearClipPlaneWidth

根據已知的Near、Far、Size和Aspect確定正交投影的裁剪矩陣:

M_{ortho}=\begin{bmatrix} \frac{1}{Aspect*Size}&0 &0 & 0\\ 0& \frac{1}{Size} & 0 & 0\\ 0& 0 & -\frac{2}{Far-Near} & -\frac{Far+Near}{Far-Near}\\ 0& 0& 0 & 1 \end{bmatrix}

則一個頂點和上述投影矩陣相乘的結果:

p_{clip}=M_{ortho}p_{view}

        =\begin{bmatrix} \frac{1}{Aspect*Size}&0 &0 & 0\\ 0& \frac{1}{Size} & 0 & 0\\ 0& 0 & -\frac{2}{Far-Near} & -\frac{Far+Near}{Far-Near}\\ 0& 0& 0 & 1 \end{bmatrix}\begin{bmatrix} x\\ y\\ z\\ 1 \end{bmatrix}

        =\begin{bmatrix} \frac{x}{Aspect*Size}\\ \frac{y}{Size}\\ -\frac{2z}{Far-Near} -\frac{Far+Near}{Far-Near}\\ 1 \end{bmatrix}\begin{bmatrix} x\\ y\\ z\\ 1 \end{bmatrix}

正交投影的投影矩陣對頂點進行變換後,其w分量仍為1,由於投影矩陣最後一行不同。判斷變換後頂點是否在視錐體內的不等式和透視投影一樣。裁剪矩陣改變了空間的旋向性。

-螢幕空間

齊次/透視除法,用齊次座標系的w分量除以x/y/z分量,得到的座標叫做歸一化的裝置座標。將座標從齊次裁剪座標空間轉換到NDC中,經透視投影變換後的裁剪空間經過齊次除法會變換到立方體內,x, y,z\in [-1,1].

而對於正交投影而言由於w=1,齊次除法不會對頂點產生影響。

根據變換後的x、y對映輸出視窗對應畫素座標。螢幕空間左下角畫素(0,0),右上角畫素座標(pixelWidth, pixelHeight),當前x, y\in [-1,1]

screen_{x}=\frac{clip_{x}*pixelWidth}{2*clip_{w}}+\frac{pixelWidth}{2}screen_{y}=\frac{clip_{y}*pixelHeight}{2*clip_{w}}+\frac{pixelHeight}{2}

z分量用於深度緩衝。

從裁剪空間到螢幕空間轉換由Unity完成,頂點著色器只需要把頂點由模型空間轉換到裁剪空間即可。

切線空間用於法線對映

6、法線變換

頂點攜帶發現資訊,有時候不僅要變換頂點,還要變換頂點法線,以便在後續處理(如片元著色器)中計算光照。

法線變更的原因:切線是由兩個頂點間插值計算得到,可以直接使用用於變換頂點的3*3變換矩陣變換切線因為切線和法線均為向量,變換矩陣M_{A->B}變換頂點

切線變更T_{B}=M_{A->B}T_{A},在進行非統一縮放時,法線與平面不一定垂直。

由於法線和切線滿足垂直條件,\vec{T_{A}}*\vec{N_{A}}=0,需要找到矩陣\vec{G}變換法線\vec{N_{A}},使得其仍然垂直,即:

\vec{T_{B}}*\vec{N_{B}}=(\vec{M_{A->B}}\vec{T{A}})*{\vec{G}\vec{N_{A}}}=(\vec{M_{A->B}}\vec{T_{A}})^{T}({\vec{G}\vec{N_{A}}})=\vec{T_{A}^{T}}\vec{M_{A-B}^{T}}\vec{G}\vec{N_{A}}=\vec{T_{A}^{T}}(\vec{M_{A->B}^{T}\vec{G}})\vec{N_{A}}=0

\vec{M_{A->B}^{T}\vec{G}}=I,即\vec{G}=(\vec{M_{A->B}}^{T})^{-1}=(\vec{M_{A->B}}^{-1})^{T}

而若變換矩陣M_{A->B}是正交矩陣,(\vec{M_{A->B}}^{T})^{-1}=(\vec{M_{A->B}}^{-1})^{T},則(\vec{M_{A->B}}^{T})^{-1}=(\vec{M_{A->B}})。如果變換隻包含旋轉變換,則變換矩陣為正交矩陣;若變換隻包含旋轉和統一縮放(不包含非統一縮放),則利用統一縮放係數k得到M_{A->B}的逆轉置矩陣(\vec{M_{A->B}}^{T})^{-1}=\frac{1}{k}(\vec{M_{A->B}})

7、Unity Shader的內建變數

7.1 變換矩陣

均為4*4大小

變數名 描述
UNITY_MATRIX_MVP 模型*觀察*投影矩陣,將頂點/方向向量從模型空間變換到裁剪空間
UNITY_MATRIX_MV 模型*觀察矩陣,將頂點/方向向量從模型空間變換到觀察空間
UNITY_MATRIX_V 觀察矩陣,將頂點/方向向量從世界空間變換到觀察空間
UNITY_MATRIX_P 投影矩陣,將頂點/方向向量從觀察空間變換到裁剪空間

UNITY_MATRIX_VP

觀察*投影矩陣,將頂點/方向向量從世界空間變換到裁剪空間
UNITY_MATRIX_T_MV UNITY_MATRIX_MV的轉置矩陣,若為*正交矩陣,則可以將頂點/方向向量從觀察空間變換到模型空間
UNITY_MATRIX_IT_MV UNITY_MATRIX_MV的逆轉置矩陣,將法線從模型空間變換到觀察空間,也可用於得到UNITY_MATRIX_MV的逆矩陣
_Object2World 模型矩陣,將頂點/方向向量從模型空間變換到世界空間
_World2Object _Object2World的逆矩陣,將頂點/方向向量從模型空間變換到世界空間

PS:

1)提取座標空間的座標軸(轉換矩陣的前三列)

2)*幾乎為正交矩陣條件:旋轉和統一比例縮放(排除除旋轉、縮放、平移的其餘變換);若只考慮向量,就不用考慮有無平移變換,提取UNITY_MATRIC_T_MV的前三行三列將觀察空間變換到模型空間;同時可以對方向向量進行歸一化處理消除統一縮放的影響。

3)得到UNITY_MATRIX_MV的逆矩陣可以利用UNITY_MATRIX_IT_MV再求轉置

觀察空間到模型空間程式碼如下,本質一樣,利用公式檢視是等價

//方法一:對UNITY_MATRIX_IT_MV進行轉置,得到逆矩陣後進行列矩陣乘法
float4 modelPos = mul(transpose(UNITY_MATRIX_IT_MV), viewPose);

//方法二:交換mul引數的位置使用行矩陣乘法
float4 modelPos = mul(viewPose, UNITY_MATRIX_IT_MV);

7.2 攝像機和螢幕引數

變數名 型別 描述
_WorldSpaceCameraPos float3 該攝像機在世界空間中的位置
_ProjectionParams float4 x=1.0(或-1.0,如果正在使用一個翻轉的投影矩陣進行渲染),y=Near, z=Far, w=1.0+1.0/Far,Near和Far分別為近裁剪平面和遠裁剪平面和攝像機的距離
_ScreenParams float4 x=width, y=height, z=1.0+1.0/width, w=1.0+1.0/height,其中width和height分別是該攝像機的渲染目標的畫素寬度和高度
_ZBufferParams float4 x=1-Far/Near, y=Far/Near, z=x/Far, w=y/Far,該變數用於線性化Z快取中的深度值
unity_OrthoParams float x=width, y=height, z無定義, w=1.0(攝像機是正交攝像機)或w=0.0(攝像機是透視攝像機),width和height是正交投影攝像機的寬度和高度
unity_CameraProjection float4*4 該攝像機的投影矩陣
unity_CameraInvProjection float4*4 該攝像機的投影矩陣的逆矩陣
unity_CameraWorldClipPlanes[6] float4 該攝像機的6個裁剪平面在世界空間下的等式,左、右、下、上、近、遠裁剪平面

8、答疑

8.1 3*3 or 4*4

8.2 CG中向量和矩陣型別

8.3 Unity中的螢幕座標:ComputeScreenPos/VPOS/WPOS

VPOS-HLSL,WPOS-CG

VPOS/WPOS語義定義的輸入是一個float4型別的變數。若螢幕解析度400*300,則x\in [0.5,400.5], y\in[0.5,300.5],Unity中VPOS/WPOS的z分量範圍是[0,1],攝像機近裁剪平面處z=0,元裁剪平面處z=1。對於透視投影,w\in[\frac{1}{Near},\frac{1}{Far}],正交投影w=1。