1. 程式人生 > 其它 >3D數學:尤拉角、萬向鎖、四元數

3D數學:尤拉角、萬向鎖、四元數

左手系、右手系

尤拉角

尤拉角用來在3D世界中表示物體的朝向,通常我們將朝向定義為將某一個正朝向旋轉至當前朝向所進行的變換。當我們表示物體的朝向時,實際上指的是對物體所進行的旋轉變換。

3D世界中的任何一個旋轉都可以拆分為沿著物體自身的三個正交座標軸的旋轉,而尤拉角規定了這三次旋轉的角度,根據繞軸不同我們分別稱它們為偏航角yaw(繞X軸)、俯仰角pitch(繞Y軸)和翻滾角roll(繞Z軸),下圖是一個右手系的yaw-pitch-roll表示圖:

對於一個旋轉變換,我們可以將其用如下三個旋轉矩陣相乘的形式表示:

\[E(yaw,pitch,roll)=R_z(yaw)R_y(roll)R_x(pitch) \]

\(R_z\)

\(R_y\)\(R_x\)分別是繞Z軸、繞Y軸、繞X軸旋轉的旋轉矩陣:

\[R_z(\theta) = \begin{pmatrix} cos\theta & -sin\theta & 0 & 0 \\ sin\theta& cos\theta & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix} \]\[R_y(\theta) = \begin{pmatrix} cos\theta & 0 & sin\theta & 0 \\ 0 & 1 & 0 & 0 \\ -sin\theta& 0 & cos\theta & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix} \]\[R_x(\theta) = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & cos\theta & -sin\theta & 0 \\ 0 & sin\theta & cos\theta & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix} \]

由於矩陣乘法的本質是將左側矩陣表示的變換資訊應用於右運算元(向量/矩陣),而多個線性變換間一般是不可交換的,即矩陣乘法不滿足交換律。所以三次旋轉的順序非常重要,在Unity、UE4、3dsMax等軟體中,以尤拉角形式

調整旋轉時一般會將旋轉順序固定,而這正是導致萬向鎖(Gimbol Lock)即萬向節死鎖的原因。

萬向鎖

網上很多資料的說法都是繞固定旋轉順序的中間軸旋轉90°後使得哪兩個軸重合或哪兩個萬向節共面了從而丟失一個維度上的自由度,或者以一個使用萬向節的陀螺儀模型來進行演示,這就讓人很摸不著頭腦。在最初的設想裡物體總是以自身物體座標系為參照進行旋轉,怎麼可能使得哪兩個軸重合;而陀螺儀雖然演示清楚了,但為什麼在Unity等軟體和3D數學上會出現萬向鎖問題,感覺在本質問題上還是沒有說明清楚。

Unity中的萬向鎖問題

在Unity3D中固定使用Z->X->Y這套旋轉順序,即\(E(yaw,pitch,roll)=R_y(yaw)R_x(roll)R_z(pitch)\)

,每一次乘上旋轉矩陣,即進行一次旋轉變換,我們認為就有一個萬向節Gimbal來控制這個變換過程。無論給定旋轉如何,都以這個固定的旋轉順序來處理。

在Unity3D Scene檢視中進行旋轉操作時,紅色圈為X旋轉軸,綠色圈為Y旋轉軸,藍色圈為Z旋轉軸,這些圈即Gimbal。

首先說明一下幾個座標系的概念:

  • 世界座標系:表示物體相對於世界原點的絕對座標。
  • 物體座標系:表示物體相對於父物體的相對座標。
  • 慣性座標系:與物體位於同一位置,但軸向平行於世界座標系的座標系。

由於使用尤拉角更直觀,在Unity Inspector上使用尤拉角表示旋轉,而在底層使用四元數表示旋轉以避免萬向鎖問題。Unity使用左手Y-up座標系,因此Inspector上用尤拉角表示時X軸、Z軸旋轉是繞當前物體的區域性座標系的X軸、Z軸進行旋轉,而Y軸旋轉是繞當前物體的慣性座標系的Y軸進行旋轉,這正是造成萬向鎖問題在Unity中理解不直觀的原因:Inspector上的Y軸旋轉並不是繞物體座標系旋轉

Inspector Y軸預設繞慣性座標系旋轉

在網上大多數資料中,Unity中的萬向鎖問題被表述為,當物體繞中間軸X軸轉動到達90°或-90°附近時,此時物體座標系下的Z軸與慣性座標系下的Y軸負向或正向重合,導致此時Y軸和Z軸旋轉等價,物體的旋轉丟失了一個維度上的自由度

Unity中的萬向鎖問題

在不同的三維軟體/遊戲引擎中,由於各個軟體底層規定的旋轉順序不同,萬向鎖的產生條件有些許不同,如UE4中使用左手系Z-up座標系,按Z->Y->X的旋轉順序,固定Z軸旋轉為繞慣性座標系旋轉,因此在物體繞中間軸Y軸到達90°或-90°附近時會發生萬向鎖問題。

總而言之,Unity中的萬向鎖問題的產生實質上是Y-up座標系的設計原因與固定的旋轉順序導致的,這與3D數學上的萬向鎖問題有些不同,但旋轉後的Z座標軸和原來的Y座標軸重合,使得旋轉後的Z軸旋轉可以由旋轉前的Y軸旋轉代替,這一點和3D數學上的萬向鎖問題是一致的。

3D數學上的萬向鎖問題

參考資料:Gimbal Lock

我們在表示尤拉角時將其寫成矩陣乘法的形式,現在我們以X->Y->Z的固定旋轉順序,從數學角度上來看產生萬向鎖的過程:

\[E(yaw,pitch,roll)=R_z(yaw)R_y(roll)R_x(pitch) \]

以下表示座標系均為右手座標系,首先沿x軸旋轉任意度數:

接下來,沿y軸旋轉\(\pi/2\)弧度:

注意到,經過這一次的變換後,我們將z軸變換到原來x軸方向,而x軸變換到原來-z軸方向。

這個變換執行完成後,我們僅剩最後z軸上的旋轉矩陣。然而,當前的z軸與原來的x軸重合,最後z軸的旋轉與x軸的旋轉可以等價,也就是說最後z軸的旋轉可以由最開始x軸上的旋轉所替代。從整個三維空間的世界座標系來看,三次旋轉變換僅覆蓋了兩個軸的旋轉,丟失了一個軸上的自由度,這就是3D數學上的萬向鎖。

上面這個過程以矩陣乘法形式寫出如下:

\[\begin{aligned} E(\alpha,\pi/2,\beta) &= R_z(\beta)R_y(\pi/2)R_x(\alpha) \\ &= \begin{bmatrix} cos\beta & -sin\beta & 0 \\ sin\beta & cos\beta & 0 \\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} 0 & 0 & 1 \\ 0 & 1 & 0 \\-1 & 0 & 0 \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 \\ 0 & cos\alpha & -sin\alpha \\ 0 & sin\alpha & cos\alpha \end{bmatrix} \\ &= \begin{bmatrix} 0 & sin(\alpha-\beta) & cos(\alpha-\beta) \\ 0 & cos(\alpha-\beta) & -sin(\alpha-\beta) \\ -1& 0 & 0 \end{bmatrix} \\ &= \begin{bmatrix} 0 & 0 & 1 \\ 0 & 1 & 0 \\-1 & 0 & 0 \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 \\ 0 & cos(\alpha-\beta) & -sin(\alpha-\beta) \\ 0 & sin(\alpha-\beta) & cos(\alpha-\beta) \end{bmatrix} \\ &= R_y(\pi/2)R_x(\alpha-\beta) \end{aligned} \]

利用三角恆等變換,原本三個旋轉矩陣所組成的變換化簡成了兩個變換矩陣。也就是說即使我們分別對x-y-z三軸進行了旋轉,只要y軸上的變換角使得當前z軸與原來x軸對齊,我們就沒有任何辦法對最初的z軸進行旋轉了。

萬向鎖問題在動態尤拉角旋轉中都不可避免,故而使用四元數來規避萬向鎖問題是涉及三維旋轉的很重要的一環。

為什麼尤拉角會導致萬向鎖問題而四元數不會?嚴謹表述如下:

In formal language, gimbal lock occurs because the map from Euler angles to rotations (topologically, from the 3-torus T3 to the real projective space RP3 which is the same as the space of 3d rotations SO3) is not a local homeomorphism at every point, and thus at some points the rank (degrees of freedom) must drop below 3, at which point gimbal lock occurs. Euler angles provide a means for giving a numerical description of any rotation in three-dimensional space using three numbers, but not only is this description not unique, but there are some points where not every change in the target space (rotations) can be realized by a change in the source space (Euler angles). This is a topological constraint – there is no covering map from the 3-torus to the 3-dimensional real projective space; the only (non-trivial) covering map is from the 3-sphere, as in the use of quaternions.

https://en.wikipedia.org/wiki/Gimbal_lock

萬向鎖所導致的問題

尤拉角與萬向鎖 這篇文章中有大量動圖,展示了在發生了萬向鎖的情況下仍使用動態尤拉角旋轉到想要的位置,必須同時旋轉三個軸向所導致的卷繞現象

四元數

參考資料:

複數

複數是一種複合的數字,\(C_{複數} = a + b \cdot i\) ,其中 a、b 為實數,\(i\) 為虛數,\(i^2 = -1\)

  • 複數通過 實部 a 和 虛部 b 構成的二維虛平面,將一維的數擴充套件到二維平面

  • \(i\) 只是區分 實部 a 和 虛部 b 的標記,這樣可以把複數用二維的向量表示

    加法:\((a + bi) + (c + di) = (a + c) + (b+d)i\)

    乘法:\((a + bi) *(c + di) = (ac - bd) + (bc+ad)i\)

  • 複數實際上就是對於\(\{1,i\}\)這個(Basis)的線性組合(Linear Combination),通俗點來說就是對將1和i這兩個基乘上標量後再相加的形式

  • 複數乘以 \(i\) 的幾何意義,在二維平面上逆時針旋轉 90 度 \((a + b \cdot i) * i = a*i + b*i^2 = -b + a \cdot i\)

三維空間中的旋轉——羅德里格旋轉公式

上面已經探討過使用尤拉角表示三維空間的旋轉雖然直觀卻會導致萬向鎖問題,因而四元數在表示三維空間旋轉的方式時採用軸角式(Axis-angle)的旋轉。

v繞u旋轉θ得到v',軸角式旋轉示意圖如下:

在軸角的定義中,\(\vec{u}\)為過原點的旋轉軸,在實現中由於並不需要其模長而只需要其方向,一般將其約束為一個單位向量\(\vec{u}=(x,y,z),|\vec{u}|=1\)\(\theta\)為旋轉角度。

有了軸和角的定義,我們就可以看如何表示旋轉:

  1. 將v分解為平行於旋轉軸u以及正交於u的兩個分量

    \[\begin{aligned} v &= v_{||} + v_{\bot}\\ v_{||} &= proj_u(v) = {u \cdot v \over ||u||} \cdot {u \over ||u||} = {(u \cdot v)u \over ||u||^2} = (u \cdot v)u\\ v_{\bot} &= v - v_{||} = v - (u \cdot v)u \end{aligned} \]
  2. 將旋轉後的v'也分解為平行與正交兩個向量。構造一個同時正交於u和\(v_{\bot}\)的向量w,用於表示v'的垂直向量

    \[\begin{aligned} w &= u \times v_{\bot}\\ ||w|| &= ||u \times v_{\bot}|| \\ &= ||u|| \cdot ||v_{\bot}|| \cdot sin{\pi \over 2}\\ &= ||v_{\bot}|| \\\\ v_{\bot}' &= v_v' + v_w'\\ &= v_{\bot} \cdot cos\theta + w \cdot sin\theta \\ &= v_{\bot} \cdot cos\theta + (u \times v_{\bot})\cdot sin\theta \\ v_{||}' &= v_{||}= (u \cdot v)u \end{aligned} \]
  3. 結合1,2可得向量型的3D旋轉公式

    \[\begin{aligned} v'&=v_{||}' + v_\bot' \\ &=(u \cdot v)u + v_\bot \cdot cos\theta + (u \times v_\bot)sin\theta \\ &=v \cdot cos\theta + (u\cdot v)u(1 - cos\theta)+(u \times v)sin\theta \end{aligned} \]

    也叫做羅德里格旋轉公式(Rodrigues' rotation Formula)。

四元數

四元數本質上就是一個三維複數,用於解決三維空間的旋轉變化問題,帶有三個虛部和一個實部,形式如下:

\[q=a+bi+cj+dk\quad(a,b,c,d∈\mathbb{R}) \]

其中,

\[i^2=j^2=k^2=ijk=-1 \]

並以此推出其迴圈對稱性的其它性質,如下圖(順序:行*列):

與複數類似,四元數其實就是對於\(\{1,i,j,k\}\)線性組合,也可以表示成四維向量\(q=\pmatrix{a\\b\\c\\d}\),我們通常也將其實部和虛部拆開,寫為標量和向量的有序對形式:

\[q=[s,\vec{v}].\quad(\vec{v}=\begin{bmatrix} x\\y\\z \end{bmatrix},s,x,y,z∈\mathbb{R}) \]

四元數矩陣乘法表示

\(q_1={\pmatrix{a\\b\\c\\d},q_2=\pmatrix{e\\f\\g\\h}}\),四元數相乘根據多項式乘法可以寫作矩陣形式:

\[q_1q_2=\begin{bmatrix} a & -b & -c & -d \\ b & a & -d & c \\ c & d & a & -b \\ d & -c & b & a \end{bmatrix} \begin{bmatrix} e \\ f \\ g \\ h \end{bmatrix} \]

該變換等價於左乘\(q_1\),由於四元數相乘不滿足交換律,所以右乘\(q_1\)的變換是一個不同的矩陣:

\[q_2q_1=\begin{bmatrix} a & -b & -c & -d \\ b & a & d & -c \\ c & -d & a & b \\ d & c & -b & a \end{bmatrix} \begin{bmatrix} e \\ f \\ g \\ h \end{bmatrix} \]

形式類似,可以看作右下角3x3矩陣作了轉置。

四元數乘法

由乘積結果:

\[q_1q_2=(ae-(bf+cg+dh))+(be+af+ch-dg)i\\+(ce+ag+df-bh)j+(de+ah+bg-cf)k \]

若令\(\vec{v}=\begin{bmatrix} b\\c\\d\end{bmatrix}\)\(\vec{u}=\begin{bmatrix} f\\g\\h\end{bmatrix}\),那麼:

\[\begin{aligned} \vec{v} \cdot \vec{u} &= bf+cg+dh \\ \vec{v} \times \vec{u} &= \left| \begin{matrix} i & j & k \\ b & c & d \\ f & g & h \end{matrix} \right| \\ &=(ch-dg)i-(bh-df)j+(bg-cf)k \end{aligned} \]

對乘積結果由以上兩式進行替換,可得以下定理:

\[對於任意四元數q_1=[s,\vec{v}],q_2=[t,\vec{u}],q_1q_2的結果是 \\ q_1q_2=[st-\vec{v} \cdot \vec{u}, s\vec{u}+t\vec{v}+\vec{v}\times\vec{u}] \]

該結果也叫格拉斯曼積(Grassmann Product),該結果實際上即為多項式相乘結果寫為標量向量有序對形式即可。

純四元數

僅有虛部,或者說實部為0的四元數。

\[v=[0,\vec{v}],u=[0,\vec{u}] \\ vu=[0-\vec{v} \cdot \vec{u},0+\vec{v} \times \vec{u}]=[-\vec{v} \cdot \vec{u}, \vec{v} \times \vec{u}] \]

逆和共軛

類似於複數的共軛,一個四元數\(q=a+bi+cj+dk\)共軛\(q^*=a-bi-cj-dk\)

四元數的,我們的目標就是找到\(q^{-1}\)使得\(qq^{-1}=1\),利用共軛性質\(q^*q=||q||^2\)易推

\[qq^{-1}=1 \\ q^*qq^{-1}=q^* \\ ||q||^2q^{-1}=q^*\\ q^{-1}=\frac{q^*}{||q||^2} \]

如果\(||q||=1\),即\(q\)是一個單位四元數,那麼\(q^{-1}=q^*\)

四元數與3D旋轉

回顧一下上面的軸角式旋轉,現在開始將四元數與3D旋轉關聯起來。首先我們將一個向量v沿著一個用單位向量所定義的旋轉軸u旋轉θ度,我們將v拆分成正交與旋轉軸的\(v_\bot\)以及平行於旋轉軸的\(v_{||}\)。對著兩個向量分別進行旋轉,獲得\(v_\bot'\)\(v_{||}'\),相加即得到旋轉後結果\(v'\)

我們將這些向量都定義為純四元數:

\[\begin{aligned} v&=[0,\vec{v}] &v'=[0,\vec{v'}] \\ v_\bot&=[0,\vec{v_\bot}] & v_\bot'=[0,\vec{v_\bot'}] \\ v_{||}&=[0,\vec{v_{||}}] & v_{||}'=[0,v_{||}'] \\ u &= [0,\vec{u}] \end{aligned} \]

按之前推導的:

\[\vec{v_\bot'}=cos\theta \vec{v_\bot} + sin\theta(\vec{u} \times \vec{v_\bot})\\ \vec{v_{||}'}=\vec{v_{||}}\\ \vec{v'}=\vec{v_{||}'}+\vec{v_\bot'} \]

首先,需要將向量叉乘形式\(\vec{u} \times \vec{v_\bot}\)寫成四元數乘法形式\(uv_\bot\) ,然後繼續化簡如下:

\[\begin{aligned} v_\bot' &= cos\theta v_\bot + sin\theta (uv_\bot) \\ &= (cos\theta+sin\theta u)v_\bot \quad(注意順序,四元數乘法不遵守交換律)\\ \end{aligned} \]

此處,我們可以將\((cos\theta+usin\theta)\)寫成四元數形式\(q=[cos\theta,sin\theta \vec{u}]\) ,即得到正交分量的四元數型3D旋轉公式:

\[當\vec{v_{\bot}}正交於旋轉軸\vec{u}時,旋轉\theta角度之後的v_{\bot}'的四元數型表示:\\ 令v_{\bot}=[0,\vec{v_{\bot}}],q=[cos\theta,sin\theta \vec{u}],則v_{\bot}'=qv_{\bot} \]

而由\(\vec{v_{||}'}=\vec{v_{||}}\)可知平行分量的四元數型3D旋轉公式:

\[v_{||}'=v_{||} \]

可得:

\[v'=v'_{||}+v'_{\bot}=v_{||}+qv{_\bot} \]

雖然可以像上面推向量型的3D旋轉公式一樣將\(v_{||},v_{\bot}\)利用幾何關係用\(v\)\(u\)表示出來,但這裡用另外的辦法來化簡:

  1. 引入一個新四元數\(p=[cos(\frac{1}{2}\theta),sin(\frac{1}{2}\theta)\vec{u}]\)\(q=p^2=[cos\theta,sin\theta\vec{u}]\)\(p^2\)為兩個旋轉的疊加,易證)

  2. 由於\(p,q\)均為單位四元數,即\(p^{-1}=p^*\),可得:

    \[\begin{aligned} v'&=v_{||}+qv_{\bot} \\ &= 1 \cdot v_{||}+qv_{\bot} \\ &= pp^{-1}v_{||}+p^2v_{\bot} \\ &=pp^*v_{||}+p^2v_{\bot} \end{aligned} \]
  3. 接下來需證以下兩個性質 ①\(qv_{||}=v_{||}q\)\(qv_{\bot}=v_{\bot}q^*\) ,由格拉斯曼積的公式可知影響四元數左乘右乘的關鍵因素在於向量部分的叉乘,由\(\vec{u} \times \vec{v_{||}} = \vec{v_{||}} \times \vec{u}= 0,\quad \vec{u} \times \vec{v_{\bot}} = \vec{v_{\bot}} \times (-\vec{u})\) 易證①②

    利用性質①②可作以下變形:

    \[\begin{equation} \nonumber \begin{aligned} v' &= pp^*v_{||}+ppv_{\bot} \\ &= pv_{||}p^*+pv_{\bot}p^* \\ &= p(v_{||}+v_{\bot})p^* \\ &= pvp^* \end{aligned} \end{equation} \]

四元數型3D旋轉公式

\[任意向量\vec{v}沿著以單位向量定義的旋轉軸\vec{u}旋轉\theta度之後的v'的四元數型表示:\\ 令v=[0,\vec{v}],q=[cos(\frac{1}{2}\theta),sin(\frac{1}{2}\theta)\vec{u}],則v'=qvq^*=qvq^{-1} \]

事實上,該等式也完全等價於之前所推的羅德里格旋轉公式:

\[qvq^*=[0,cos\theta\vec{v}+(1-cos\theta)(\vec{u} \cdot \vec{v})\vec{u} + sin\theta(\vec{u} \times \vec{v})] \]

至此,我們得到用四元數表示一次三維空間旋轉的基本公式。

四元數旋轉的複合

假設\(q_1,q_2\)分別表示沿著不同軸,不同角度旋轉的四元數。我們進行\(q_1\)的變換如下:

\[v'=q_1vq_1^* \]

接下來對\(v'\)\(q_2\)變換:

\[\begin{equation} \nonumber \begin{aligned} v''&=q_2v'q_2^* \\ &=q_2q_1vq_1^*q_2^* \end{aligned} \end{equation} \]

由引理\(q_1^*q_2^*=(q_2q_1)^*\)(可自行證明)可得:

\[\begin{equation} \nonumber \begin{aligned} v''&=q_2q_1vq_1^*q_2^*\\ &=(q_2q_1)v(q_2q_1)^* \\ &=q_{net}vq_{net}^* \end{aligned} \end{equation} \]

可以得到一個複合旋轉\(q_{net}\),但對於該複合旋轉的理解並不是按\(q_1,q_2\)進行變換的兩次旋轉,而是一個僅旋轉結果相同的等價旋轉

雙倍覆蓋(Double Cover)

  • 對任意單位四元數q,q與-q代表的是同一個旋轉。若q表示的是沿著旋轉軸\(\vec{u}\)旋轉θ度,那麼-q代表的是沿著相反的旋轉軸\(-\vec{u}\)旋轉\((2\pi-\theta)\)度。
  • 對於這種性質,我們常稱單位四元數雙倍覆蓋(Double Cover)了3D旋轉,或者說單位四元數與3D旋轉之間有2對1滿射同態關係。所有的單位四元數都對應一個3D旋轉。

其它

關於四元數插值、四元數,尤拉角,矩陣三種形式間的轉換等等一部分其它內容,暫時先留個坑,隨緣填。