在計算機圖形學的學習中,幾何變換(Transformations)是一塊重要的內容,我們使用齊次座標(Homogeneous coordinates)描述點和向量,使用變換矩陣描述平移、旋轉等變換。
而在平移、旋轉、縮放這幾種變換中,又以旋轉的情況最為複雜。實際上,計算機圖形學中三維空間的旋轉不僅僅有旋轉矩陣一種表達形式,歐拉角(Euler angles)和四元數(Quaternions)也是常用的方法。
旋轉矩陣
三維空間中的一個點 ,我們用齊次座標表示:
我們首先考慮分別繞 X 軸、Y 軸、Z 軸旋轉一定角度的情況。
設 繞 X 軸、Y 軸、Z 軸的旋轉角度分別為 、 和 。
我們使用右手座標系,旋轉角度的正向由右手定則確定。
點繞座標軸旋轉可以考慮點在相應座標平面上投影的旋轉。比如繞 Y 軸旋轉,那麼考慮點 在 X-Z 平面上的投影的旋轉,如下圖所示:
假設點 在 X-Z 平面上的投影點與座標原點連成的向量長度為 L ,那麼根據簡單的平面幾何知識,我們可以得到:
用齊次座標表示繞Y軸的旋轉為:
同理可分別得到繞X軸與繞Y軸的情況。
繞X軸旋轉:
繞Z軸旋轉:
我們可以將繞X、Y和Z座標軸的旋轉矩陣分別記為 ,則有:
旋轉矩陣可以通過其他旋轉矩陣複合得到(矩陣乘法)。
歐拉角
上面討論了繞三條座標軸旋轉的旋轉矩陣,旋轉矩陣的一般形式(這裡沒有用齊次座標)為:
物體在三維空間中的旋轉可以從座標系的旋轉來考慮(三維空間中座標軸,即三維線性空間中基的變換)。那麼矩陣 的三個列向量實際對應著原座標系三個座標軸方向的單位向量在旋轉後的新座標系下的座標。
我們知道直角座標系的三個座標軸方向的單位向量實際上是一組標準正交基,於是矩陣 是一個正交矩陣。所以旋轉矩陣表面上看起來依賴於 9 個參數,實際上只有三個是獨立的。
為了更直接地指出這三個獨立參數,歐拉(Euler)證明瞭如下事實:任何一個旋轉都可以由連續施行的三次繞軸旋轉來實現,這三次繞軸旋轉的旋轉角就是三個獨立參數,稱為歐拉角。
根據繞軸旋轉的順序不同,歐拉角的表示也不同。常見的歐拉角表示有 Yaw-Pitch-Roll (Y-X-Z順序),通過下面的圖片可以形象地進行理解。
偏航(Yaw):
仰俯(Pitch):
側偏(Roll):
設 Yaw 、Pitch 、Roll 三個角度分別為 ,那麼利用歐拉角進行旋轉對應的旋轉變換矩陣為:
實際上 Yaw 、Pitch 、Roll 的旋轉就分別對應著前面我們給出的旋轉矩陣 ,上面的矩陣就是這三個矩陣的複合。
歐拉角的好處是簡單、容易理解,但使用它作為旋轉的工具有嚴重的缺陷—萬向節死鎖(Gimbal Lock)。
萬向節死鎖是指物體的兩個旋轉軸指向同一個方向。實際上,當兩個旋轉軸平行時,我們就說萬向節鎖現象發生了,換句話說,繞一個軸旋轉可能會覆蓋住另一個軸的旋轉,從而失去一維自由度。
例如,三維空間中有一個平行於 X 軸的向量,我們將它繞 Y 軸旋轉直到它平行於 Z 軸,這時,我們會發現任何繞 Z 軸的旋轉都改變不了該向量的方向,即出現了萬向節死鎖。
由於萬向節死鎖的存在,使用歐拉角也無法很好地處理旋轉的插值(以實現“平滑”旋轉)。
四元數
從前面的討論我們發現三角度系統(three-angle system)無法很好地處理旋轉的插值。下面介紹四元數(Quaternions)以及如何利用四元數描述旋轉。
四元數的定義
四元數是由數學家 William Rowan Hamilton 於1843年所發明的數學概念,是複數的推廣,可以說是“三維的複數”,形式為 ,其中 的關係如下:
假設有兩個四元數:
四元數的加法定義如下:
四元數的乘法定義,利用簡單的分配律定義如下:
為了方便表示,我們將四元數記為:
注意,這裡四元數的表示形式和“齊次座標”長得一樣,但是它們之間沒什麼關係!
四元數常常用來表示旋轉,很多人將其理解為“w表示旋轉角度,v表示旋轉軸”,也是錯誤的!
正確的理解應為:“w與旋轉角度有關,v與旋轉軸有關”。
四元數的模(norm)定義為
模為1的四元數稱為單位四元數(Unit quaternions)。
四元數的共軛(conjugate)定義為:
四元數的倒數定義為:
四元數與旋轉
這裡直接給出結論:如果把單位四元數表示為:
的形式,那麼該單位四元數可以表示繞軸
進行 角的旋轉。
該單位四元數對應的旋轉矩陣為
這裡的推導用到了軸-角旋轉表示中的Rodrigues’ rotation formula,具體證明這裡不展開了,有興趣的可以查閱相關資料。
我們發現用四元數描述旋轉需要的存儲空間很小,更為關鍵的是可以使用被稱為球面線性插值(Slerp Algorithm)的方法對四元數進行插值運算,從而解決了平滑旋轉的插值問題。
在 OpenGL 或者 DirectX 中我們通常使用模型視圖矩陣來進行幾何變換,當我們希望實現光滑旋轉、對旋轉進行插值時,就可以利用四元數這一工具。處理過程為:
- 模型視圖矩陣 -> 四元數
- 使用四元數進行運算
- 四元數 -> 模型視圖矩陣