天天看點

Real-Time Rendering 翻譯 4.變換【上】4.1 基本變換4.2 特殊變換矩陣和操作

變換是一種轉換點、向量或者顔色的操作。對于計算機圖形學的先驅來說,掌握變換極度重要。有着它,可以放置、形變和運動物體、光源和相機。你可以認為所有計算都是在同一坐标系下,然後以不同的方式投影到平面上。雖然變換隻能完成一小部分操作,但是這些操作足以證明它在實時渲染中的重要地位,對所有的計算機圖形學都如此。

線性變換包含,向量相加和标量與向量相乘。例如,

f(x)+f(y)=f(x+y)(可加性)

kf(x)=f(kx)(齊次性 4.1)

例如,f(x)=5x是一個變換,它将向量x的所有元素都乘以5。這種變換是線性的,任意兩個向量乘以5再相加,等同于先将兩個向量相加然後在乘以5。标量乘以向量完全滿足線性變換的條件。這個函數稱之為縮放變換,它改變了對象的尺寸。旋轉變換也是一種線性變換,它将向量繞原點旋轉。針對3元素的線性變換可以用3x3的矩陣表示,縮放和旋轉變換也如此。

然而,3x3矩陣的次元還是不夠。例如,x是3元素的向量,函數f(x)=x+(7,2,3)就不是一個線性變換。因為如果将此函數作用于兩個向量上,最終的結果會把向量(7,2,3)相加兩次,不滿足相加性。将一個常向量加到另一個向量産生了位移變換,它将向量移動了一個常量。這種變換類型很有用,我們可以将各種操作組合起來,例如,我們可以将對象縮放到原來的一半,然後移動到另一個位置。如果使用函數的形式來表示變換非常的簡單,然而不好組合各種變換。

線性變換和位移的組合稱之為仿射變換。我們使用齊次坐标來表示4元素的向量,以此可以統一點和向量的表示方式。向量可以表示為 v=(v0,v1,v2,0)T ,點可以表示為 v=(v0,v1,v2,1)T 。本章我們會大量使用附錄A中術語。你可以現在複習目錄A.4(905頁),關于齊次坐标的内容。

所有的位移、旋轉、縮放、反射和裁剪矩陣都是仿射變換。仿射變換的主要特性是,經過變換後平行線依然平行,但是長度和角度會改變。仿射變換的任意順序組合任然是仿射變換。

我們以最重要最基本的仿射變換開始本章。由于是最基本的内容,可以認為本節是一些簡單變換的參考手冊。也會描述一些特殊的矩陣,然後讨論四元數,一種非常有用的變換工具。接下來讨論頂點融合和變形,這兩種操作雖然簡單是對對網格動畫非常有用。最後讨論投影矩陣。表4.1總結了很多矩陣的表示方式,表示函數和屬性。

變換是操作幾何體的基本工具。[2016/07/09]很多圖像API已經包含了我們本章讨論的矩陣操作。然而,了解真正的變換矩陣和API之後的具體實作是值得的。了解API調用之後如何使用變換矩陣隻是開始,真正了解每個矩陣的具體含義才能讓你走的更遠。例如,當你真正了解矩陣變換之後,你會知道正交矩陣的逆矩陣是它的轉置矩陣,讓你更快的求出它的逆矩陣。這種知識可以加速你的代碼。

符号 名稱 特點
T(t) 位移矩陣 移動一個點,仿射
Rx(ρ) 旋轉矩陣 繞x軸旋轉 ρ 弧度,同樣的可以表示對y軸和z軸的旋轉,正交和仿射
R 旋轉矩陣 任意的旋轉矩陣,正交和仿射
S(s) 縮放矩陣 根據向量s沿x,y,z軸縮放
Hij(s) 剪切矩陣 剪切,仿射變換
E(h,p,r) 歐拉變換 使用歐拉角(head,pitch,roll)的朝向矩陣,正交和仿射
Po(s) 正交投影 平行投影到平面,仿射
Pp(s) 透視投影 透視投影到平面
slerp(q,r,t) 插值變換 在四元數q和r之間使用參數t進行插值

表4.1 本章讨論的所有變換。

4.1 基本變換

本章讨論最基本的變換,例如位移、旋轉、縮放、剪切、變換連接配接、剛體變換、法線變換和他們的逆。對有經驗的肚子來說,這些内容時一份參考手冊,隊友新手而言,這是變換這個主題的引導。這些材料是接下來其他章節的背景知識。我們沖最簡單的變換開始,位移變換。[2016/07/10]

Real-Time Rendering 翻譯 4.變換【上】4.1 基本變換4.2 特殊變換矩陣和操作

圖4.1 左邊的正方形經過位移矩陣T(5,2,0)變換,向右移動5個機關,向上移動2個機關。

4.1.1 位移

從一個位置位移到另一個位置可以使用位移矩陣T來完成。這個矩陣将對象位移向量 t=(tx,ty,tz) 。矩陣T具體表示如公式4.2:

T(t)=T(tx,ty,tz)=⎛⎝⎜⎜⎜100001000010txtytz1⎞⎠⎟⎟⎟(4.2)

圖4.1展示了位移變換的效果。[2016/07/11]上述公式表示點 p=(px,py,pz,1) 和T(t)的相乘結果,産生新的點 p′=(px+tx,py+ty,pz+tz,1) 。注意向量 v=(vx,vy,vz,0) 與T(t)相乘後不變,因為方向向量不能位移(沒有位移這個概念)。相反的,點和向量都收到其他的仿射變換所影響。位移矩陣的逆矩陣 T−1(t)=T(−t) ,注意向量t取反。

4.1.2 旋轉

旋轉變換将向量(點或者方向向量)繞給點的軸(過圓心)旋轉指定的角度。同位移矩陣一樣,這是個剛體變換,點與點之間的距離保持不變,坐标系的左右手不變(不會從左手坐标系變為右手坐标系)。位移和旋轉兩種操作用來表示對象的位置和朝向。方向矩陣(orientation matrix)是一個旋轉矩陣,用于定義相機或者物體在空間中的朝向。常用的旋轉矩陣有 Rx(ϕ),Ry(ϕ)和Rz(ϕ) ,分别表示繞着x,y和z軸旋轉 ϕ 弧度。具體表示如下所示:

Rx(ϕ)=⎛⎝⎜⎜⎜10000cosϕsinϕ00−sinϕcosϕ00001⎞⎠⎟⎟⎟(4.3)

Ry(ϕ)=⎛⎝⎜⎜⎜cosϕ0−sinϕ00100sinϕ0cosϕ00001⎞⎠⎟⎟⎟(4.4)

Rz(ϕ)=⎛⎝⎜⎜⎜cosϕsinϕ00−sinϕcosϕ0000100001⎞⎠⎟⎟⎟(4.5)

對3x3的旋轉矩陣而言,表示繞任意軸旋轉 ϕ 弧度,矩陣的迹相對于軸獨立,計算如下:

tr(R)=1+2cosϕ(4.6)

旋轉矩陣的效果如圖4.4所示。旋轉矩陣 Ri(ϕ) 的特點是,所有在旋轉軸i上的點不變,其他點繞軸i旋轉 ϕ 弧度。記号R也可以表示繞任意軸旋轉。上面三種旋轉矩陣的結合可以完成繞任意軸的旋轉操作。這個過程在4.2.1讨論。直接繞任意軸旋轉的操作會在4.2.4讨論。

所有的旋轉矩陣的行列式為1,并且是正交的,可以參考附錄A中關于正交矩陣的定義來證明。任意多個旋轉矩陣的連接配接也滿足以上性質。旋轉矩陣的逆矩陣如下: R−i1(ϕ)=Ri(−ϕ) ,繞任意軸相反的方向。同樣的,旋轉矩陣的行列式為1,因為它是正交的。

例子:繞點旋轉。[2016/07/19]假設我們繞z軸旋轉 ϕ 弧度,旋轉的中心為點p。轉換矩陣是什麼呢?這一轉換過程詳見圖4.2。繞一點旋轉的效果是,中心點本身不變,其他點繞中心點旋轉。轉換由位移變換開始,我們先将坐标系的原點移動至點p(中心點),可以使用變換 T(−p) 。然後執行旋轉變換: Rz(ϕ) 。最後将坐标系原點移回原來的位置,使用位移矩陣 T(p) 。最後的變換矩陣X為:

X=T(p)Rz(ϕ)T(−p)(4.7)

Real-Time Rendering 翻譯 4.變換【上】4.1 基本變換4.2 特殊變換矩陣和操作

圖4.2 繞點p旋轉的過程

4.1.3 縮放

縮放矩陣, S(s)=S(sx,sy,sz) ,縮放因子為 sx,sy,sz ,分别為沿着x,y和z軸的縮放。意味着縮放矩陣可以放大或者縮小對象。縮放因子 si,i∈{x,y,z} 越大,在所在方向的縮放也就越大。将縮放因子s的任何部分設定為1意味着在此方向上不進行任何縮放。公式4.8為最終的縮放矩陣:

S(s)=⎛⎝⎜⎜⎜sx0000sy0000sz00001⎞⎠⎟⎟⎟(4.8)

圖4.4展示了縮放矩陣的效果。如果 sx=sy=sz 則稱之為uniform,其他稱之為nonuniform。有時候也會使用術語isotropic和anisotropic來替代uniform和nonuniform。逆矩陣 S−1(s)=S(1/sx,1/sy,1/sz) 。

使用齊次坐标,還可以容易的實作以點(3,3)為中心的縮放矩陣。齊次坐标的w分量,也可以用來實作縮放矩陣。例如,使用縮放因子5來等比縮放,縮放矩陣的(0,0),(1,1)和(2,2)位置設定為5,或者也可以将矩陣的(3,3)設定為1/5。這兩種矩陣如下所示:

S(s)=⎛⎝⎜⎜⎜5000050000500001⎞⎠⎟⎟⎟,S′=⎛⎝⎜⎜⎜1000010000100001/5⎞⎠⎟⎟⎟(4.9)

不同于縮放矩陣S,使用矩陣S’必須最後進行齊次化(就是将x,y,z除以w)。使用矩陣S’可能不會高效,因為在齊次化過程中需要将各個分量除以w,如果S’位于(3,3)的值為1就不需要進行除法。如果系統不檢測w是否為1,每次都進行齊次化,那麼使用S’不需要額外的除法。[2016/07/24]

對角線上的元素變為負數就得到一個反射矩陣,也稱之為鏡面反射矩陣。如果對角線上的兩個元素為-1,那麼相對于旋轉 π 弧度。反射矩陣一般需要特殊的對待。例如,一個逆時針定義頂點的三角形經過反射矩陣變換之後會得到一個順時針定義頂點的三角形。這種變換會導緻不正确的光照和背面剔除錯誤。驗證某一變換矩陣是否包含反射操作,計算變換矩陣的左上的3x3子矩陣的行列式。如果為負數,那麼這個矩陣包含反射操作變換。

例如:沿着一确定方向的縮放。縮放矩陣S隻能沿着x,y或者z軸縮放。如果需要沿着其他方向縮放,那麼需要一個複合變換。假設沿着一确定方向的縮放可以在一個正交的,右手坐标系完成,坐标系以 fx,fy,fz 為軸。我們可以先構造矩陣F如下:

S(s)=(fx0fy0fz001)(4.10)

基本思想是以新的軸為坐标系,然後在此坐标系中進行标準的縮放操作,然後再從新坐标系轉換到原坐标系。第一步是乘以F的轉置矩陣(正交矩陣的逆矩陣就是其轉置)。然後執行縮放操作,最後再執行返原操作。變換公式如4.11

X=FS(s)FT(4.11)

4.1.4 剪切

另一類變換操作是剪切矩陣的集合。這種變換操作應用在遊戲中來扭曲整個場景,産生迷幻的效果,或者建立模糊的反射效果。有六個基本的剪切矩陣,分别為 Hxy(s),Hxz(s),Hyx(s),Hyz(s),Hzx(s),Hzy(s) 。第一個下标表示受剪切矩陣影響的軸,第二個下标表示在此軸上進行剪切操作。公式4.12是剪切矩陣 Hxz(s) 。觀察 Hxz(s) 的下标可以找到剪切參數s的位置,下标x(位置為0)表示第0行,下标z(位置為0)表示第二列,那麼s的位置就可以輕松定位,如下公式所示:

S(s)=⎛⎝⎜⎜⎜10000100s0100001⎞⎠⎟⎟⎟(4.12)

将此矩陣乘到點p産生結果 (px+spz,py,pz)T 。圖4.3展示了機關正方形的剪切效果。 Hij(s) (在j軸上剪切i,i!=j)的逆操作就是在往相反的方向再執行剪切操作,那麼 H−1ij(s)=Hij(−s) 。

Real-Time Rendering 翻譯 4.變換【上】4.1 基本變換4.2 特殊變換矩陣和操作

圖4.3 單元正方形使用 Hxz(s) 剪切後的效果。y軸和z軸不會受到操作的影響,x是原來的x和s倍z值之和,導緻正方形傾斜。

有些計算機圖形系統中使用另一種剪切矩陣:

H−1xy(s,t)=⎛⎝⎜⎜⎜10000100st100001⎞⎠⎟⎟⎟(4.13)

上述公式中的兩個下标用來表示對象在兩個軸上分别沿着第三個軸做剪切操作。着兩個操作的組合為 H′ij(s,t)=Hik(s)Hjk(t) ,這裡k指的是i,j之外的第三個軸。等式左邊的部分更為常用,也被API所支援。

最後,任何剪切矩陣的行列式都為1, |H|=1 。

4.1.5 組合變換

由于矩陣乘法的不可交換性,矩陣相乘的順序就非常重要了。變換的組合是順序相關的。

一個順序相關的例子,兩個矩陣S和R,S(2, 0.5, 1)表示沿着x軸方向放大兩倍,沿着y軸縮小一半。[2016/08/01] Rz(π/6) 表示繞z軸逆時針旋轉 π/6 弧度。這兩個矩陣可以有兩種不同的連接配接方式,産生的結果大不相同。如圖4.4所示。

Real-Time Rendering 翻譯 4.變換【上】4.1 基本變換4.2 特殊變換矩陣和操作

圖4.4 展示了矩陣連接配接順序的不同導緻的結果不同。上面一行先進行旋轉操作 Rz(π/6) ,然後進行縮放操作 S(s),s=(2,0.5,1) 。組合矩陣為 S(s)Rz(π/6) 。下一行以相反的順序執行操作,組合矩陣為 Rz(π/6)S(s) 。産生的結果完全不相同。一般來說,對矩陣M和N,MN!=NM。

将多個矩陣組合為一個的原因是為了效率。例如,有一個擁有幾千個頂點的對象,需要縮放、旋轉和位移。這就需要對每個頂點都乘以這三個矩陣,這三個矩陣可以連接配接為一個矩陣。然後将這個新的矩陣作用到每個頂點上。最終的組合矩陣為C=TRS。需要關注矩陣的順序,首先乘以縮放矩陣S,然後從右到左順序依次相乘。這樣的順序隐含着TRSp=(T(R(Sp)))。

需要注意的是矩陣的連接配接是順序相關的,矩陣可以随意組合。例如TRSp變換可以先計算剛體變換TR。可以将這兩個矩陣組合起來,(TR)(Sp),等同于TRSp。矩陣連接配接滿足可配置設定性。

4.1.6 剛體變換

當一人抓起一個物體,例如從桌子上抓起一支筆,移動到另一個位置,比如他的口袋裡,筆的朝向和位置發生了變化,然而筆的形狀沒有發生變化。這種隻有位移和旋轉的操作稱之為剛體變換,保留原有對象的長度、角度和坐标系的屬性(左手坐标系或者右手坐标系不變)。[2016/08/05]

任何剛體變換矩陣X都可以分解為位移矩陣T(t)和旋轉矩陣R的連接配接。X為形如公式4.14的矩陣:

X=T(t)R=⎛⎝⎜⎜⎜r00r10r200r01r11r210r02r12r220txtytz1⎞⎠⎟⎟⎟(4.14)

X的逆矩陣可以這麼計算, X−1=(T(t)R)−1=R−1T(t)−1=RTT(−t) [2016/08/06]。那麼,X的逆矩陣是,先計算左上3x3的R矩陣的轉置,再計算T矩陣的逆矩陣(t取反)。然後R和T相乘最終産生X的逆矩陣。

另一種計算X的逆矩陣的方式如下,考慮R和X如下:

R¯¯¯=(r,0   r,1   r,2)=⎛⎝⎜⎜rT0rT1rT2⎞⎠⎟⎟(4.15)

X=⎛⎝⎜R¯¯¯0Tt1⎞⎠⎟()

上述公式中, 0 表示3x1的列向量,所有元素為0。經過簡單的計算,X的逆矩陣如公式4.16所示:

X−1=⎛⎝⎜⎜R¯¯¯T0−R¯¯¯T1⎞⎠⎟⎟=⎛⎝⎜⎜r00r10r20−R¯¯¯T1⎞⎠⎟⎟(4.16)

4.1.7 法線變換

上面的讨論的變換矩陣可以用于點,線,多邊形和其他幾何體的變換操作。同樣的矩陣也可以用作切向量的變換操作,切向量沿着直線或者多邊形表面的方向。然後上述的變換矩陣不能用于法線變換,即表面的法線。圖4.5展示了上述矩陣用于法線變換的結果。

Real-Time Rendering 翻譯 4.變換【上】4.1 基本變換4.2 特殊變換矩陣和操作

圖4.5 左邊是原始的幾何體,一個多邊形和其法線。中間展示了如果模型朝着x軸縮放0.5之後,再用相同的矩陣作用于法線之後的結果。右邊展示了理想的法線變換結果。

不使用原始的變換矩陣,合适的方法是使用原始變換矩陣的伴随矩陣的逆矩陣。A.3.1介紹了如何計算伴随矩陣。伴随矩陣總是存在的。記過這種操作變化的法線不一定是機關向量,需要經過标準化。

法線變換的所使用的矩陣是原始變換矩陣的轉置的逆。這種方式總是可行的。然而,有時候逆矩陣是不存在的。逆矩陣是伴随矩陣除以行列式。如果行列式為0,那麼矩陣是奇異的,逆矩陣是不存在的。

計算4x4矩陣的伴随矩陣開銷比較大,而且不是必要的。因為法線是向量,是以不受位移矩陣的影響。另外,大多數模型變換都是仿射變換。不會改變齊次坐标的w分量。這種情況下,隻需要計算左上3x3矩陣的伴随矩陣,就能得到法線變換的矩陣。[2016/08/15]

甚至伴随矩陣的計算也是可以省略的。我們知道變換矩陣是位移矩陣、旋轉矩陣和統一縮放矩陣(沒有拉伸或者壓縮)。法線不受到位移變換的影響。統一縮放操作隻會改變法線的長度。由上面旋轉矩陣可知,旋轉矩陣(正交的)的逆矩陣是它的轉置。這種情況下(位移、旋轉和統一縮放),原始的變換矩陣可以直接中用于法線。

最後,變換後的法線不一定需要标準化。如果隻有位移和旋轉,變換後的法線向量的長度不會發生變化,不需要再經過标準化操作。如果變換操作中含有統一縮放,可以直接使用縮放因子來标準化法線。例如,我們知道原始變換操作中包含統一縮放操作,将對象放大5.2倍,那麼我們可以使用原始變換作用于法線,最後再除以5.2得到标準化的法線。如果需要得結果為标準化法線的變換矩陣,可以将原始變換矩陣的左上3x3矩陣除以縮放因子,得到最終的法線變換矩陣。

注意法線變換矩陣在這裡不是什麼大問題,經過變換操作,面片的法線是從三角形資料中計算出來的(三角形變的點乘)。切線向量和法線不太相同,切線向量直接使用原始變換矩陣。

4.1.8 計算逆變換

很多情況下需要計算變換的逆,例如進行變換或者坐标系回退。依賴于原始變換的資訊,有以下三種方法來計算矩陣的逆。

  • 如果變換矩陣是一些列簡單變換矩陣的組合,那麼逆矩陣是單個簡單變換矩陣參數取反,并反序組合這些矩陣。例如 M=T(t)R(ϕ) ,那麼 M−1=R(−ϕ)T(−t) 。
  • 如果變換矩陣是正交矩陣,那麼 M−1=MT ,也就是它的轉置矩陣就是它的逆矩陣。任意多個旋轉矩陣的組合還是旋轉矩陣,任然是正交的。
  • 如果不知道變換矩陣的任何資訊,那麼可以使用鄰接矩陣、克萊默法則、LU分解或者高斯消除等方法來計算逆矩陣。克萊默法則和鄰接矩陣的方法更好,因為他們的實作中分支操作較少(也就是if比較少),現代的計算機架構中,if操作越少越好。4.1.7展示了如何使用鄰接矩陣來計算法線變換矩陣。[2016/08/18]

優化逆矩陣計算方式時,也需要考慮使用逆矩陣的目的。例如,如果逆矩陣是用來變換向量的,那麼隻需要計算變換矩陣的右上3x3子矩陣的逆。

4.2 特殊變換矩陣和操作

這節中,我們介紹一些實時渲染圖形學中必備的矩陣變換和操作。首先,我們展示歐拉變換(包括他的參數提取),這是一種直覺描述朝向的方式。然後涉及到如何從一個變換矩陣中抽取出一個個基本變換。最後,我們推導出繞任意軸旋轉的變換矩陣。

4.2.1 歐拉變換

歐拉變換是一種直覺的方式用來描述旋轉自己或者旋轉到特定的方向。名字來源于偉大的瑞士數學家歐拉。

Real-Time Rendering 翻譯 4.變換【上】4.1 基本變換4.2 特殊變換矩陣和操作

圖4.6 如圖所示,在歐拉變換中,三種操作head,pitch和roll。預設的方向如圖所示,觀察方向為-z軸,向上方向為y軸。(左上坐标系,順着旋轉軸看,順時針旋轉)

首先,需要确定預設的觀察方向。大多數觀察方向為-z軸,頭朝上方向為y軸,如圖4.6所示。歐拉變換就是三個旋轉矩陣的組合,每個矩陣命名如上圖所示。歐拉變換矩陣表示為E,如公式4.17所示:

E(h,p,r)=Rz(r)Rx(p)Ry(h)(4.17)

因為E是旋轉矩陣的組合,是以它是正交的。那麼他的逆矩陣 E−1=ET=(RzRxRy)T=RTyRTxRTz , 是以E的逆矩陣就是它的轉置.

歐拉角h, p和r分别表示旋轉的次序和沿着head,pitch和roll的旋轉角度。這種變換操作很直覺,是以可以對外行解釋清楚。例如,旋轉head角可以讓觀察者搖頭說“no”, 旋轉pitch角讓他點頭,旋轉roll角讓他向兩邊傾斜頭。我們使用head, pitch和roll來替代x,y和z軸。歐拉變換可以用在世界坐标系中或者局部坐标系中。

當你使用歐拉變換是,有時會産生萬向鎖結。當一個旋轉自由度丢失時,這種現象就會發生。例如,旋轉順序是x/y/z。考慮如下情況,繞y軸旋轉 π/2 弧度,也就是執行第二個旋轉操作。[2016/08/21]執行了這個旋轉操作之後,z軸就和x軸重合了,導緻最終的繞z軸旋轉是備援的。直覺解釋詳見https://www.youtube.com/watch?v=zc8b2Jo7mno

另一種觀察萬向鎖結的方法就是設定 p=π/2 ,然後計算歐拉旋轉矩陣 E(h,p,r) :

E(h,π/2,r)=⎛⎝⎜cosrsinr0−sinrcosr0001⎞⎠⎟⎛⎝⎜1000cos(π/2)sin(π/2)0−sin(π/2)cos(π/2)⎞⎠⎟⎛⎝⎜cosh0−sinh010−sinh0cosh⎞⎠⎟

=⎛⎝⎜cosrcosh−sinrsinhsinrcosh+cosrsinh0001cosrsinh+sinrcoshsinrsinh−cosrcosh0⎞⎠⎟=⎛⎝⎜cos(r+h)sin(r+h)0000sin(r+h)−cos(r+h)0⎞⎠⎟(4.18)

因為最終的歐拉旋轉矩陣隻依賴于角度(r+h),我們可以推導出有一個自由度已經丢失。

模型系統中,歐拉角經常以x/y/z順序出現,依次繞每個軸旋轉,其他順序也是可行的。例如,z/x/y順序經常用于動畫系統中,z/x/z可以用于動畫和實體系統中。後一種順序,z/x/z對某些應用來說很優秀。根據毛球理論,萬向鎖結不可避免,沒有一種完美的順序來避免出現萬向鎖結。

對于細小的角度或者朝向變化,歐拉角有些限制。很難結合兩組歐拉角。例如,兩組歐拉角之間的插值不能簡單的通過對每個角度的插值來完成。事實上,兩組不同的歐拉角可以表示同樣的朝向,是以會導緻插值出來的歐拉角根本不會旋轉物體。有一些替代的方法來表示朝向,例如接下來要讨論的四元數。

4.2.2 從歐拉變換中抽取參數

在有些情況下,從正交歐拉變換矩陣中抽取歐拉角h,p和r很有用。抽取方法如公式4.19所示:

F=⎛⎝⎜⎜⎜⎜f00f10f20f01f11f21f02f12f22⎞⎠⎟⎟⎟⎟=Rz(r)Rx(p)Ry(h)=E(h,p,r)(4.19)

連接配接三個旋轉矩陣的結果如公式4.19所示:

F=⎛⎝⎜⎜⎜cosr cosh−sinr sinp sinhsinr cosh+cosr sinp sinh−cosp sinh−sinr cospcosr cospsinpcosr sinh+sinr sinp coshsinr sinh−cosr sinp coshcosp cosh⎞⎠⎟⎟⎟(4.20)

由上式可知,pitch角可由 sinp=f21 計算出。同樣的, f01 除以 f11 可以得到roll角, f20 除以 f22 可以得到head角,具體計算如公式4.21所示:[2016/08/22]

f01f11=−sinrcosr=−tanr()

f20f22=−sinhcosh=−tanh(4.21)

那麼,歐拉角的三個參數h,p,r可以由atan2(y,x)函數從矩陣F中計算出來,如公式4.22所示:

h=atan2(−f20,f22)()

p=arcsin(f21)(4.22)

r=atan2(−f01,f11)()

這裡有一個特例需要處理。如果 cosp=0 ,因為 f01=f11=0 時,atan2函數不能工作。如果 cosp=0 那麼 sinp=±1 ,F可以化簡為公式4.23。

F=⎛⎝⎜⎜⎜cos(r±h)sin(r±h)000±1sin(r±h)−cos(r±h)0⎞⎠⎟⎟⎟(4.23)

如果設定h=0,那麼 cosh=1,sinh=0 ,那麼由公式4.20可得 sinr/cosr=tanr=f10/f00 ,最終可得到 r=atan2(f10,f00) 。

注意arcsin的定義, −π/2≤p≤π/2 ,這就意味着如果矩陣F的p處在 [−π/2,π/2] 之外,那麼原始的p值不能被抽取出來。那麼h,p和r等數值不是唯一的,這也就意味着多個歐拉角參數可以表示同一個變換。Shoemake’s 1994有關于歐拉變換的更多資訊。

4.2.3 矩陣分解

到此為止我們工作在這樣的假設之下,我們知道我們所用的矩陣的原始值和變換過程。這種假設不總是成立的,例如一個對象的變換矩陣可能是多個矩陣的組合。從一個組合矩陣中分離出多個基本變換矩陣的操作稱之為矩陣分解。

有很多原因需要分解組合矩陣,如下:

  • 抽取出縮放因子
  • 找到特定系統所需要的變換操作。例如VRML不能使用任意的4x4矩陣。
  • 檢查模型的變換操作是否是剛體變換(隻包含位移和旋轉)。
  • 計算動畫中關鍵幀的插值,關鍵幀中隻包含對象的變換矩陣。
  • 從旋轉矩陣中移除剪切

我們已經展示了兩種分解方式,由位移和旋轉矩陣派生出來的剛體變換,由正交矩陣派生出的歐拉變換。

正如我們所見,分解出位移矩陣非常簡單,隻需要看4x4矩陣的最後一列。也可以通過矩陣的行列式值是否為負來判斷矩陣是否包含鏡像操作。分離出旋轉、縮放和剪切需要更多努力。[2016/08/29]

幸運的是,有很多關于矩陣分解的文章,也有很多代碼。Thomas和GoldMan讨論了各種類型矩陣的分解方法。Shoemake在他們的基礎上改進了仿射矩陣的分解方法,他的方法也可以做為獨立參考,他還嘗試從變換矩陣中抽取出剛體變換操作。

4.2.4 繞任意軸旋轉

有時候需一個将對象繞任意軸旋轉某個角度的方法。假設旋轉的軸為 r ,r為标準化向量,那麼旋轉矩陣可以通過繞 r 旋轉α來定義。

為了建構這個旋轉矩陣,我們需要找到任意的另外兩個機關向量,這兩個向量之間正交,并與 r 也正交。這就構成了一個基。基本的想法就是将标準基(标準坐标系)變換到這個新的基(由兩個新的機關向量和r構成的新坐标系),然後繞x軸(就是之前的 r 軸)旋轉α弧度,最後變換回标準基。這個過程如圖4.7所示。

Real-Time Rendering 翻譯 4.變換【上】4.1 基本變換4.2 特殊變換矩陣和操作

圖4.7 繞任意軸 r 旋轉,由尋找到的正交的标準基r,s,t來完成。我們将r作為新的标準基中的x軸。然後繞x軸旋轉,最後變換回标準基。

第一步就是計算出新的标準基的軸。第一個軸為r,這就是我們圍繞他旋轉的軸。接下來專注于尋找第二個軸s,那麼第三個軸t可以通過t=r\times s計算出來。一種數值穩定的方法就是尋找到r向量的最小分量(絕對值最小),然後将其置為0。然後交換剩餘的兩個分量,并将這兩個分量中的第一個取反。數學表示如下:

\overline s=\left\{\begin{matrix}(0, -r_z, r_y),\ if\ |r_x|<|r_y|\ and\ |r_x|<|r_z|,\\ (-r_z, 0, r_x),\ if\ |r_y|<|r_x|\ and\ |r_y|<|r_z|,\\ (-r_y, r_x, 0),\ if\ |r_z|<|r_x|\ and\ |r_z|<|r_y|,\end{matrix}\right.

s=\overline s/||\overline s||, \tag{4.24}

t=r\times s

這種計算方式確定\overline s和r是正交(垂直)的,(r,s,t)是一個正交基。我們以這三個向量作為矩陣的行,得到矩陣如下:

M=\begin{pmatrix}r^T \\ s^T \\ t^T \end{pmatrix}\tag{4.25}

這個矩陣将向量r轉換為x軸(e_x),s轉換為y軸,t轉換為z軸。最後繞向量r旋轉\alpha弧度的變換為:

X=M^TR_x(\alpha)M\tag{4.26}

換而言之,我們先将r變換到x軸(使用矩陣M),然後繞x軸旋轉\alpha弧度,使用矩陣R_x{\alpha},最後使用M的逆變換回去,這裡使用M^T因為M是正交的。

另一種繞任意标準軸r旋轉\alpha弧度的表示方法由GoldMan提出。我們這裡僅僅展現他的最終結果:

R=\begin{pmatrix}cos\phi+(1-cos\phi)r_x^2 && (1-cos\phi)r_xr_y-r_zsin\phi && (1-cos\phi)r_xr_z+r_ysin\phi\\(1-cos\phi)r_xr_y+r_zsin\phi && cos\phi+(1-cos\phi)r_y^2 && (1-cos\phi)r_yr_z-r_xsin\phi \\ (1-cos\phi)r_xr_z-r_ysin\phi && (1-cos\phi)r_yr_z+r_xsin\phi && cos\phi+(1-cos\phi)r_z^2 \end{pmatrix}\tag{4.27}

4.3.2節會讨論另一種解決此問題的方法,四元數。還會讨論其他相關的高效算法,例如由一個向量旋轉到另一個向量。[2016/08/30]