ELBE
電話:021-58780503 微信:18017854633 郵箱:sales_fullyear@126.com 地址:上海市浦東新區城南路168弄3號峰匯商務廣場B座911室四元數應用——轉矩陣、Slerp插值與萬向節
四元數應用——順序無關的旋轉混合
—————————————————————————————————————————
今天說一些關于四元數的相關實例,較前兩篇可能有些零碎,算是對于前兩章的補充說明。具體來說,我們接下來會討論三個問題,第一個是四元數與矩陣的轉換,其次是四元數的插值問題,最后說一下萬向節死鎖問題。話不多說,開始正題。
1.四元數的矩陣形式目前對于大多數底層的圖形API,其對于空間坐標的轉換還是基于矩陣。所以當我們使用四元數對旋轉進行操作,最終傳遞給頂點著色器的數據還是要以矩陣的形式。不過,從應用層的角度來說,我們只要滿足如下的公式就可以實現轉換。
我相信大多數人并不滿足于背公式,推導該公式的方法主要有兩種。其中一種就是從代數的角度進行求解,說白了就是硬算。我們在《四元數和旋轉(二)》中提到一個公式:
我們分別求出各項,可以得到三個矩陣,然后相加就是上面那個轉換公式。這里不做推導,有興趣的可以自己算一算。下面介紹一種比較靈性的一種證明方法。當給定下面兩個四元數:
我們令他們相乘,其實可以寫成矩陣與向量相乘的形式,如下圖:
可以這么說,兩個四元數相乘轉變成矩陣L右乘四元數q。發散一下思維,我們還可以將該行為寫成矩陣R左乘四元數q,具體形式如下圖:
最體看L和R括號里面的四元數下標,由于四元數不滿足交換律,所以順序很重要,而括號里面的下標其實是不一樣的,這個地方一定要注意。基礎知識講完了,下面就直接進行應用。根據旋轉公式和以上的定義,我們很容易得到如下公式:
然后將L和R帶入上述的矩陣中,我們可以得到:
證畢!
2.四元數的Slerp插值其實插值問題一直都算是圖形學中比較經典的問題,一般來說線性插值可以滿足大多數的情況,但是對于旋轉來說,線性插值肯定效果不好,我們來看下圖:
從圖中很明顯看出,左圖(線插)要遜于右圖(球插)。一種從動畫的角度解釋是,為了保證每幀的旋轉都是均勻變化的,線性插值得到的旋轉結果一定是不均勻的,這主要考慮的是旋轉角度。那我們從代數的角度去思考,如果兩個單位四元數之間進行插值,如左圖的線性插值,得到的四元數一定不是單位四元數,我們期望對于旋轉的插值應該是不改變長度的,所以顯然右圖球面(Slerp)插值更為合理。
關于四元數的球面插值證明就很多了,Wiki上面就有很詳細的證明以及實現的Code。主體思想其實就是施密特正交,先根據 和 解算出兩個正 交的四元數,然后通過加權算出最終的 。下圖能很好的說明白這個事。
下面主要討論的是這個問題,上圖中給出了球面插值公式的一種形式,我們暫且稱為加法形式。由于四元數旋轉是相乘的形式,我們上述的公式亦可以寫成:
鑒于刨根問底的精神,首先先說說四元數的差(Difference),這個比較好理解,類似于矩陣,A和B的差,可以理解成先旋轉A逆然后再旋轉B,得到A和B之間的差值,表示為 。然后我們如果去t倍的差或者直接說差乘以一個t因子,這里就要引用了我們在《四元數與旋轉(一)》中所述的四元數指數形式。對于 ,我們來看看 和 的情況,具體如下:
最后我們令 以及 ,根據下面公式重新審視一下球面插值:
可以看出,兩種表現形式之間是可以互相轉化的。
3.萬向節死鎖其實這個問題不能算的上四元數的應用,萬向節死鎖早期是用來處理機械臂在旋轉時自由度缺失的問題,由于當時機械臂的關節都是單自由度的,所以在模擬人體某些球形關節(自由度為3的關節)的時候,會采用三組相互正交的機械關節進行模擬。
如圖所示,機械關節1-3共同模擬了手腕的活動,這里會導致一個問題,當關節2旋轉90°后,關節1和關節3會重合,這樣無論旋轉關節1還是旋轉關節3都只會沿著 軸進行旋轉,這就是萬向節死鎖。值得一提的是,當你旋轉關節1,關節2和關節3都會隨著一起動,而當你旋轉關節3,無論怎么旋轉也不會影響關節2和關節1,所以只有關節2旋轉90°會產生萬向節死鎖。
當早期計算機動畫將機器人那套東西搬過來的時候,最簡單的做法就是用歐拉角直接模擬旋轉。這就導致了萬向節死鎖。那怎么去理解計算機動畫里面的這個問題呢,畢竟動畫里面也沒有機械關節。
我們假定三個歐拉角的旋轉順序如下
當 的時候, 和 就會重合,如右圖,這樣就會產生萬向節死鎖。
所以為了避免這個問題,圖形學旋轉開始使用軸角,因為軸角可以講三個歐拉角等效成一個繞著特定軸旋轉的角度。低版本的OpenGL有個函數glRotate函數,實現的方法就是使用軸角。當然,并不是軸角不存在萬向節死鎖,當存在三個相互正交的軸角按一定順序進行旋轉,依然會產生萬向節死鎖,不過這種情況很難發生。
那么軸角已經解決這個問題,為什么我們要用四元數?
4.四元數總結最后點個題,呼應一下前文,具體說說四元數的好處:
解決萬向節死鎖(Gimbal Lock)問題。(不要去用四元數模擬歐拉角!)僅需存儲4個浮點數,相比矩陣更加輕量。比如矩陣至少要用9個float進行表示旋轉信息,即便加上旋轉縮放,也會比矩陣少存2-6個float,對于在PC上開發的游戲可能并不顯著,畢竟現在內存都大,但在家用機(特別是上世代)上,內存比較吃緊的情況下就相當有利了。四元數無論是求逆、串聯等操作,相比矩陣更加高效。比如取反就等同于求逆,即便是正交矩陣,轉置的操作代價也比取反要高得多,更何況大多數情況由于存在縮放,求逆的操作會更加復雜。但是,使用四元數需要考慮將四元數與矩陣之間轉換的成本,不過綜合考慮,還是四元數操作成本比較低。基本上四元數在我這也就告一段落了,之后會有請人 @Obsver Anonym 續一篇具體應用的文章,請大家敬請期待!