天天看點

圖形學 旋轉與投影矩陣—2

game101 第二次作業; webgl 實作

目錄

圖形學 旋轉與投影矩陣—2

前文簡介

三維變換

視圖矩陣

規範立方體

投影矩陣

透視矩陣參數

結論

使用 THREEJS 作為基礎架構,建構各類矩陣,自定義矩陣運算,最終完成

正确構模組化型矩陣

正确建構透視投影矩陣

看到變換後的三角形

按 A 和 D 三角形能夠進行旋轉

按 Q 和 E 三角形能夠繞任意過原點的向量進行旋轉

最終效果
圖形學 旋轉與投影矩陣—2

在旋轉與投影矩陣第一篇中,以二維坐标系舉例,詳細解釋了三種基礎變換的矩陣形式,其中包括縮放變換,旋轉變換和平移變換。平移變換比較特殊,由于 2*2 的矩陣無法表示平移變換,增加一個次元表示平移變換能獲得很多好處,是以後續均采用 3*3 的矩陣表示基礎變換。

補充:繞原點旋轉的矩陣已經在前文推斷出來,如果想繞指定點進行旋轉,此時應該如何處理?這裡轉個彎,先将指定點和物體同時移動相同距離直至指定點到原點,再應用繞原點旋轉的矩陣,最後再還原移動,恢複開始移動的距離。具體流程如圖一所示。

圖形學 旋轉與投影矩陣—2

圖一:繞任意點旋轉

在三維中的變換和在二維中的變換是類似的,可以采用相同的推斷,3*3 的矩陣可以表示縮放和旋轉,無法表示平移變換,是以需要引入第四個次元,使用 4*4 的矩陣統一描述縮放、旋轉和平移的變換。

縮放變換數值全在對角線上

\[\left[

\begin{matrix}

x' \\ y' \\ z'

\end{matrix}

\right]

=

\left[

S_x & 0 & 0 \\ 0 & S_y & 0 \\ 0 & 0 & S_z

\times

x \\ y \\ z

\\

表示在\: x,y,z\: 上分别縮放\: S_x,S_y,S_z \:倍

\]

剛剛也談到要用四維坐标表示,四維坐标擴充很容易,擴充位除了(3, 3)位全是 0,(3, 3)位是 1

\[縮放矩陣=

S_x & 0 & 0 & 0 \\ 0 & S_y & 0 & 0 \\ 0 & 0 & S_z & 0 \\ 0 & 0 & 0 & 1

平移變換比較簡單,數值處于第四列

\[平移矩陣=

1 & 0 & 0 & T_x \\ 0 & 1 & 0 & T_y \\ 0 & 0 & 1 & T_z \\ 0 & 0 & 0 & 1

\right] \\

表示在\: x,y,z\: 上分别移動 \: T_x, T_y,T_z \: 個機關長度

旋轉矩陣稍微特殊一點,推導方式與二維一緻

一個立方體,繞原點旋轉 θ 角度,選中點進行代入計算,最終算出矩陣每個元素的值,三維旋轉可以分成繞 X 軸旋轉,繞 Y 軸旋轉和繞 Z 軸旋轉,可以想象一下繞這三種旋轉最終得到的圖形。經過代入計算可得

\[R_x(\theta)=

1 & 0 & 0 & 0 \\ 0 & \cos(\theta) & -\sin(\theta) & 0 \\

0 & \sin(\theta) & \cos(\theta) & 0 \\ 0 & 0 & 0 & 1

R_z(\theta)=

\cos(\theta) & -\sin(\theta) & 0 & 0 \\

\sin(\theta) & \cos(\theta) & 0 & 0 \\

0 & 0 & 1 & 0 \\

0 & 0 & 0 & 1

R_y(\theta)=

\cos(\theta) & 0 & \sin(\theta) & 0 \\

0 & 1 & 0 & 0 \\

-\sin(\theta) & 0 & \cos(\theta) & 0 \\

這個旋轉矩陣和二維旋轉是非常類似的矩陣

\[二維旋轉矩陣=

\cos(\theta) & -\sin(\theta) \\ \sin(\theta) & \cos(\theta)

Ry(θ) 稍有不同,Rx 和 Rz 相當于是在機關矩陣上固定相應軸的值,在進行二維旋轉。Ry 的特殊性在于

\[\overrightarrow{x} \times \overrightarrow{y}

= \overrightarrow{z} \\

\overrightarrow{y} \times \overrightarrow{z}

= \overrightarrow{x} \\

特殊處:

\overrightarrow{x} \times \overrightarrow{z}

= -\overrightarrow{y} \\

依圖所示加上右手定則,向量叉乘可得出,是以繞 y 軸的旋轉矩陣會特殊一點

圖形學 旋轉與投影矩陣—2

描述了繞 x,y,z 軸的旋轉矩陣,實際上還有一種,繞原點任意方向進行旋轉,這個方程在程式中也會被用到,設向量為 n,旋轉角度為 θ

\[R(n, \theta) =

\cos(\theta) \times I +

(1-\cos(\theta)) \times n \times n^T +

\sin(\theta) \times

0 & -n_z & n_y \\ n_z & 0 & -n_x \\ -n_y & n_x & 0

n_x, n_y, n_z \: 分别是向量\: \overrightarrow{n} \: 的x,y,z值

該式該需要轉換為 4*4 适配整套計算,方法很簡單,[3, 3] 位置為 1, 其餘位置補充為0。這裡提及的是繞過原點的 n 向量旋轉,那想求過任意點的 n 向量旋轉該怎麼做呢?方法之前也提到過,先将任意點移動到原點,旋轉後在糾正回去即可。

因為旋轉矩陣運算不适合插值計算,是以需要四元數處理旋轉,在計算時更加友善和高效。

之前的各種三維變換,把他們組合在一起,就形成了模型矩陣,也就是說,模型矩陣是物體的三維變換的矩陣乘積。模型的位置基本确定,接下來得确定相機的位置。相機預設在原點處,up 向上方向是 y 軸正方向,lookAt 方向位 z 軸負方向,如果相機不在,那麼就得矯正,美名曰規範化。

規範化分為兩步,第一步,将相機移動到原點,第二步,将相機的 up 和 lookAt 方向規範

圖形學 旋轉與投影矩陣—2

規範化的相機視角

假設現在相機移動,旋轉後,如果複原呢?

圖形學 旋轉與投影矩陣—2

複原過程

分步驟計算

第一步:轉換位置到原點。由于目前相機位置是 e,對應的坐标為(xe, ye, ze),容易寫出平移矩陣 Tview,如下所示

\[T_{view} =

1 & 0 & 0 & -x_e \\

0 & 1 & 0 & -y_e \\

0 & 0 & 1 & -z_e \\

第二步:轉換 up 和 looAt 方向。向着複原過程求解不太容易,轉換為求從标準狀态轉換為目前狀态更好了解。也就是說,現在可以求規範化的相機如何旋轉到目前的方向,然後對這個方向求逆矩陣。還是代入計算

\[R_{view}^{-1} \times

0 \\ 0 \\ 1 \\ 0

x_{-g} \\ y_{-g} \\ z_{-g} \\ 0

lookAt 方向計算

R_{view}^{-1} \times

0 \\ 1 \\ 0 \\ 0

x_{t} \\ y_{t} \\ z_{t} \\ 0

up方向計算

得到 lookAt 方向和 up 方向後,x 軸方向為 lookAt \times up

R_{view}^{-1} =

x_{g\times t} & x_t & x_{-g} & 0 \\

y_{g\times t} & y_t & y_{-g} & 0 \\

z_{g\times t} & z_t & z_{-g} & 0 \\

= R^T \\

得到 \\

R =

x_{g\times t} & y_{g\times t} & z_{g\times t} & 0 \\

x_t & y_t & z_t & 0 \\

x_{-g} & y_{-g} & z_{-g} & 0 \\

第三步,求得視圖矩陣 Mview = Rview * Tview

給出一個立方體,用 top, bottom, left, right, near, far,六個面切割形成一個四棱柱,正交矩陣的作用是将這個四棱柱規範化,将中心置為原點處,長寬高分别為2,形成 [-1, -1, -1] 到 [1, 1, 1] 的規範立方體。

這個過程也是分為兩步,第一步,将中心置于原點處,第二步,将圖形壓縮成規範立方體,由此可得正交矩陣,先設 top, bottom, left, right, near, far 值分别為 t, b, l, r, n, f

\[M_{ortho}= 旋轉矩陣 * 平移矩陣

M_{ortho}=

\frac2{r-l} & 0 & 0 & 0 \\

0 & \frac2{t-b} & 0 & 0 \\

0 & 0 & \frac2{n-f} & 0 \\

1 & 0 & 0 & -\frac{r+l}{2} \\

0 & 1 & 0 & -\frac{t+b}{2} \\

0 & 0 & 1 & -\frac{n+f}{2} \\

注意:先操作的矩陣在右邊,後操作的矩陣在左邊,這是因為元素坐标是 4*1 的,需要左乘矩陣。這也代表元素最先相乘的是所有變換矩陣的右側,案例見下列算式

\[gl\_Position = M_{persp} \times M_{view} \times M_{model} \times position

由此,正交矩陣便已經解析出來了

投影相機看到的視角和人眼看到的視角可以保持一緻,是以,在三維世界中采用的一般是投影相機,加入運算的便是投影矩陣,如果直接求解投影矩陣是比較麻煩的,可以将過程轉換為,先把投影矩陣轉換為正交矩陣再進行計算

\[M_{persep} =M_{ortho} \times M_{persp \rightarrow ortho}

因為正交矩陣上文已經求解出來了,現在隻需要求解投影到正交的轉換矩陣。現在有一個點的坐标是(x, y, z),經過轉換後投影再相機的近平面上,經過轉換後的點的坐标為 (x', y', z'),轉換過程如下圖所示

圖形學 旋轉與投影矩陣—2

從投影到正交的轉換過程中,我們可以得到一些等式進而解出這個轉換方程式,具體如下

\[y' = \frac n z \times y \\

x' = \frac n z \times x \\

x' \\ y' \\ z' \\ 1

\Rightarrow

\frac n z x \\ \frac n z y \\ ? \\ 1

\ n x \\ n y \\ ? \\ z

這時,我們得到了轉換後點的坐标 [x', y', z', 1] = [nx, ny, ?, z],為啥可以同時乘 z ,前文中也提到,最後一個參數最後總會歸一化成 1,在之前無論怎麼變換,最後,x,y,z 都會同時 /w ,是以在計算時,可以 x, y, z, w 同時乘上一個數,意義不變。

已知轉換前後點的坐标,再列方程式

\[M_{persp \rightarrow ortho} \times

x \\ y \\ z \\ 1

\Downarrow

M_{persp \rightarrow ortho} =

\ n & 0 & 0 & 0 \\ 0 & n & 0 & 0 \\ ? & ? & ? & ?\\ 0 & 0 & 1 & 0

注意轉換過程中有兩個性質

近平面所有坐标不變,遠平面進行壓縮

近平面與遠平面的 z 值不變

遠平面中心坐标不變

是以可以代入兩個點的變換

\[1: \:

x \\ y \\ n \\ 1

x' \\ y' \\ n \\ 1

\right] =

nx' \\ ny' \\ n^2 \\ n

2: \:

x \\ y \\ f \\ 1

x' \\ y' \\ f \\ 1

fx' \\ fy' \\ f^2 \\ f

可得

? & ? & ? & ?

\right] \times

x \\ y\\ n \\ 1

n^2

x \\ y\\ f \\ 1

f^2

因為得出的結果與x, y沒有關系,是以可以推斷出前兩個問号為0,設第三和第四個問号為A,B

0 & 0 & A & B

\left\{

\begin{array}{}

A \times n + B = n^2 \\

A \times f + B = f^2 \\

\end{array}

\right.

\rightarrow

A = n + f \\

B = -n \times f \\

由此可得到投影轉換矩陣的具體内容

\[M_{persp \rightarrow ortho} =

\ n & 0 & 0 & 0 \\ 0 & n & 0 & 0 \\ 0 & 0 & n+f & -nf\\ 0 & 0 & 1 & 0

最終的投影矩陣的表達式為

正交矩陣需要的參數是 n, f, l, r, t, b,分别表示 near, far, left, right, top, bottom 透視矩陣也需要這麼多,但是很多參數都是可以推導的,這裡添加兩個概念,寬高比,aspect, 視角 fov。

寬高比比較好了解,字如其意,aspect = 寬/高;視角分為兩種,一種叫 fovY,另外一種叫 fovX, 在 THREEJS 中,fov 代表的就是 fovY,表示如下圖所示

圖形學 旋轉與投影矩陣—2

可以寫出下面兩個式子

\[aspect = \frac r t = \frac {2r}{2t} = \frac 寬 高

tan{\frac {fovY} 2} = \frac t {|n|}

由于相機是朝z軸負方向看,是以 n 和 f 是負數,這裡需要加個絕對值。n 和 f 都是必須要知道的,已知 n 和 fovY,就能求出 t, t 和 f 互為相反數,是以可以得到 f, 知道 aspect 和 t,就能知道 r, r 和 l 互為相反數。

是以,知道了 fovY, aspect,n 和 f 就能求出所有需要的值

在三維世界中,有三個重要的矩陣,模型矩陣,視圖矩陣和投影矩陣,隻有知道這三個矩陣才能将元素的元素坐标轉換為規範立方體内的坐标

目前,每個矩陣均已經求解完畢,隻要提供 position,就能知道最終坐标。

旋轉與投影矩陣分為了三篇,第一篇描述了二維坐标下的矩陣變換,第二篇即本篇描述了三維坐标系下的基礎概念,和相應的轉換公式,基于這些轉換公式便可以開始進行實驗,第三篇以代碼為主,主要講實作文章開頭的五個需求,建構一個三維世界出來

希望讀者在看完後能提出意見, 點個贊, 鼓勵一下, 我們一起進步. 加油 !!

繼續閱讀