歐拉角和四元數
筆記主要摘自下列博文和回答中
【Unity編程】四元數(Quaternion)與歐拉角 - Andrew的游戲世界 - CSDN博客
【Unity編程】歐拉角與萬向節(jié)死鎖(圖文版) - Andrew的游戲世界 - CSDN博客
歐拉角
歐拉角:由三個角度組成,在特定坐標系下用于描述剛體的orientation。orientation可以理解為形態(tài),用來唯一地確定定點轉動明體位置的三個一組獨立角參量,它不是一個方向或向量,如圖1的向量,無論怎么旋轉它都是不會改變的,因為它沒有orientation。
而在圖2中當你旋轉物體時,它的orientation就會發(fā)生改變。描述一個向量用兩個維度就可以(忽略長度信息),而描述orientation至少需要三個角度,即歐拉角,總結起來,歐拉角就是用來表示三維坐標系中方向和方向變換的。
下面這個圖解釋了如何通過歐拉角進行旋轉
圖中有兩組坐標,一組是xyz,它是全局坐標保持不懂,而XYZ則是局部坐標,跟著物體一起旋轉。旋轉步驟為:1.繞著全局z軸轉了角;2.繞著自己的X軸轉了
角;3.繞這自己的Z軸轉了
角。下面的圖4更加清晰地展示了旋轉的過程 (
對應
,
?對應
,
?對應
)
我們把上面的旋轉順序記為zXZ(習慣稱為zxz順規(guī)),加上對應的角度就構成了一個完整的歐拉角,表示為? zXZ—(,
,
)
萬向節(jié)
維基百科中關于平衡環(huán)架的一段描述
平衡環(huán)架(英語:Gimbal)為一具有樞紐的裝置,使得一物體能以單一軸旋轉。由彼此垂直的樞紐軸所組成的一組三只平衡環(huán)架,則可使架在最內的環(huán)架的物體維持旋轉軸不變,而應用在船上的陀螺儀、羅盤、飲料杯架等用途上,而不受船體因波浪上下震動、船身轉向的影響。
它的樣子如圖5所示
其組成如下圖所示
萬向節(jié)與歐拉角的工作方式類似,三層嵌套的圓環(huán),它們互相交叉,帶來了三個方向自由度的旋轉。如圖6所示,沿著機身右方軸(Unity中的+X)進行旋轉,稱為pitch,中文叫俯仰。 沿著機頭上方軸(Unity中的+Y)進行旋轉,稱為Yaw,中文叫偏航。 沿著機頭前方軸(Unity中的+Z)進行旋轉,稱為Roll,中文叫桶滾。
萬向節(jié)死鎖
了解了上面一些東西后,我們來了解萬向節(jié)死鎖產生和問題,為了解釋清楚問題,這里有一個簡單的陀螺儀示意圖。
把三個Gimbal環(huán)用不同的顏色做了標記,底部三個軸向,RGB分別對應XYZ。 假設現(xiàn)在這個陀螺儀被放在一艘船上,船頭的方向沿著+Z軸,也就是右前方。通過博文中的演示可知道當船體分別發(fā)生俯仰,偏航和桶滾時,平衡環(huán)架中的轉子和平衡軸都能通過自身的調節(jié)保持平衡的狀態(tài),而使移動只發(fā)生在陀螺儀內部的相對移動。
這樣看似在任何搖晃下這個簡陋的陀螺儀都能通過自身的調整使其保持穩(wěn)定的平衡,但是在我們假設船體發(fā)生了事故,船首揚起了90°(即俯仰旋轉),此時陀螺儀會呈現(xiàn)圖9這種狀態(tài)(紅色圓環(huán)俯仰轉動90°成豎直狀態(tài))
此時,船體再次發(fā)生轉動,沿著當前世界坐標的+Z軸(藍色軸,應該正指向船底)進行轉動會發(fā)生什么情況呢,如圖10所示
這中現(xiàn)象為什么會出現(xiàn)呢?
之前陀螺儀之所以能通過自身調節(jié),保持平衡,是因為存在可以相對旋轉的連接頭。在這種情況下,已經不存在可以相對旋轉的連接頭了。那么連接頭呢?去了哪里?顯然,它還是在那里,只不過是,連接頭可以旋轉的相對方向不是現(xiàn)在需要的按著+Z軸方向。從上圖中,我們清楚地看到:
紅色連接頭:可以給予一個相對俯仰的自由度。
綠色連接頭:可以給予一個相對偏航的自由度。
藍色連接頭:可以給予一個相對偏航的自由度。
三個連接頭提供的自由度只對應了俯仰和偏航兩個自由度,桶滾自由度丟失了。這就是陀螺儀上的“萬向節(jié)死鎖”問題。
而萬向節(jié)的死鎖也是歐拉角在應用時的一大缺點,為解決這個問題,可以引入四元數來對旋轉變換進行描述。
四元數
歐拉旋轉定理
由下圖可以看出,當長度為1時,矢量落在長度為1的圓形上,此時實數軸上的a = cos(φ),虛數軸上的b = sin(φ),其中φ為旋轉角度。此時的表示形式為?e = cos(φ) + sin(φ)i
當圓上的一個矢量進行了連續(xù)的旋轉時時,假設先旋轉φ,再旋轉θ,則結果應該是兩個旋轉的角的和的復數形式,即 e = cos(φ+θ)+sin(φ+θ)i。假設:e1= cos(φ) + sin(φ)i (表示旋轉了φ角度),e2= cos(θ) + sin(θ)i (表示旋轉了θ角度),根據公式演算可得e和e1、e2的關系為 e = e1*e2,也就是說,連續(xù)的旋轉(例如這里旋轉φ再旋轉θ),可以使用兩個復數的乘積進行表示,這就是歐拉定理和復數結合的作用,它能夠方便的表示出二維矢量的旋轉變化。
四元數定義
四元數的定義一般是 q=w+xi+yj+zk,其中 w,x,y,z是實數。同時,有:
i*i=-1; j*j=-1;k*k=-1,四元數也可以表示為: q=[w,v]
其中v = (x,y,z)是矢量,w是標量,雖然v是矢量,但不能簡單的理解為3維空間的矢量,它是4維空間中的的矢量,這點比較抽象,不做深究。
通俗的講,一個四元數描述了一個旋轉軸和一個旋轉角度。當然也可以隨意指定一個角度一個旋轉軸來構造一個四元數。這個角度是相對于單位四元數而言的,也可以說是相對于物體的初始方向而言的。
有多種方式可表示旋轉,如 axis/angle、歐拉角(Euler angles)、矩陣(matrix)、四元組等。 相對于其它方法,四元數有其本身的優(yōu)點:
1.四元數不會有歐拉角存在的萬向節(jié)死鎖問題
2.四元數由4個數組成,旋轉矩陣需要9個數
3.兩個四元數之間更容易插值
4.四元數、矩陣在多次運算后會積攢誤差,需要分別對其做規(guī)范化(normalize)和正交化(orthogonalize),對四元數規(guī)范化更容易
與旋轉矩陣類似,兩個四元組相乘可表示兩次旋轉
四元數——對旋轉角表示方法
這里主要參考了【Unity技巧】四元數(Quaternion)和旋轉 - candycat - CSDN博客的文章做了一個我本人學習的總結。
我們下面使用q = ((x, y, z),w) = (v, w),其中v是向量,w是實數,這樣的式子來表示一個四元數。我們可以使用一個四元數q=((x,y,z)sinθ2,cosθ2)?來執(zhí)行一個旋轉。具體來說,如果我們想要把空間的一個點P繞著單位向量軸u = (x, y, z)表示的旋轉軸旋轉θ角度,我們首先把點P擴展到四元數空間,即四元數p = (P, 0)。那么,旋轉后新的點對應的四元數(計算得的四元數的實部為0,虛部系數就是新的坐標)為: p′=qpq?1
其中,q=(cosθ2, (x,y,z)sinθ2)?,q?1=q?N(q),由于u是單位向量,因此N(q)=1,即q?1=q*。
右邊表達式包含了四元數乘法。相關的定義如下:(其中v,v1,v2為向量)
四元數乘法:q1q2=(v1×v2+w1v2+w2v1,w1w2?v1?v2)?
共軛四元數:q*=(?v,w)
四元數的模:N(q) = √(x^2 + y^2 + z^2 +w^2),即四元數到原點的距離
四元數的逆:q^-1=q?N(q)
關于四元數各種性質的分析可參考下面這個鏈接中的內容
【Unity編程】四元數(Quaternion)與歐拉角 - Andrew的游戲世界 - CSDN博客
由于我所需要的是結果和能夠使用結果,所以不列出證明,其主要思想是構建了一個輔助向量k,它是將p繞旋轉軸旋轉θ/2得到的。證明過程嘗試證明wk?=kv?,以此證明w與v、k在同一平面內,且與v夾角為θ。
舉一個例子,把點P(1, 0, 1)繞旋轉軸u = (0, 1, 0)旋轉90°,求旋轉后的頂點坐標。首先將P擴充到四元數,即p = (P, 0)。而q = (u*sin45°, cos45°)。求p′=qpq?1的值。最后的結果p` = ((1, 0, -1), 0),即旋轉后的頂點位置是(1, 0, -1)。
如果想要得到復合旋轉,只需類似復合矩陣那樣左乘新的四元數,再進行運算即可。
我們來總結下四元數旋轉的幾個需要注意的地方:
1.用于旋轉的四元數,每個分量的范圍都在(-1,1);
2.每一次旋轉實際上需要兩個四元數的參與,即q和q*;
3.所有用于旋轉的四元數都是單位四元數,即它們的模是1;
Unity中的四元數使用
實際上,在Unity里即便不知道上述公式和變換也絲毫不妨礙我們使用四元數,但是有一點要提醒你,除非你對四元數非常了解,那么不要直接對它們進行賦值。在Unity里找到對應的函數來進行四元數變換,那么可以使用這兩個函數:Quaternion.Euler和Quaternion.eulerAngles。它們基本可以滿足絕大多數的四元數旋轉變換。
四元數和歐拉角的轉換
給定一個歐拉旋轉(X, Y, Z)(即分別繞x軸、y軸和z軸旋轉X、Y、Z度),則對應的四元數為:
x = sin(Y/2)sin(Z/2)cos(X/2)+cos(Y/2)cos(Z/2)sin(X/2)
y = sin(Y/2)cos(Z/2)cos(X/2)+cos(Y/2)sin(Z/2)sin(X/2)
z = cos(Y/2)sin(Z/2)cos(X/2)-sin(Y/2)cos(Z/2)sin(X/2)
w = cos(Y/2)cos(Z/2)cos(X/2)-sin(Y/2)sin(Z/2)sin(X/2)
四元數 q = ((x, y, z), w)。
使用四元數解決萬向節(jié)鎖
一般情況下對于給定的按照一定順規(guī)的歐拉角,將其轉換成為四元數再轉換為旋轉矩陣進行計算,即每一個歐拉角都生成一個新的四元數和新的旋轉矩陣,在使用歐拉角時這樣做是沒有問題的,但是在使用四元數的時候就會出現(xiàn)問題,因為每次輸入的繞軸旋轉有多個軸和多個角度,對于多次旋轉繞多軸沒有考慮坐標系的變化,解決辦法是分別計算用戶每一次輸入的旋轉變換矩陣,將每一次的單獨的旋轉變換矩陣點乘原來的旋轉變換矩陣,得到最新的變換矩陣。后續(xù)的每一次變換都在這個矩陣的基礎上不斷的乘,也就是說每一次都是在原來的基礎上再加一點點變化。
并且用四元數生成旋轉矩陣相乘,運算的順序對結果不會有影響。