大家好,這是我的第一篇文章。今後自己的博客文章會不定期進行更新,大部分主題將會是我對近幾年
這一篇文章目的是向大家深入介紹四元數,主要的參考文獻是2013年
內容大綱
- 背景
- 複數
- 四元數
- 羣論觀點下的四元數
- 四元數在
Unity 中的應用
目標(將會回答以下幾個問題)
- 爲什麼是四個元?
i,j,k 是什麼?- 爲什麼旋轉的公式是
qpq−1 ?- 爲什麼是
θ/2 ?- 我們應該如何理解
4D (4D 可視化)?
那麼話不多說,先來進入第一部分。
背景
- 旋轉定義
- 旋轉矩陣
- 歐拉角
- 羅德里格旋轉公式
旋轉定義
通常將物體繞一個點或者一個軸轉動一定角度的操作稱爲旋轉。不妨先考慮
旋轉示意圖
那麼自然而言便會引申出旋轉角的概念:
旋轉角示意圖
顯然,旋轉角串聯起了旋轉前後的兩個圖形。而這種“串聯”關係,通常採用矩陣的語言進行描述。
旋轉矩陣
在線性代數裏,我們知道:
- 一個矩陣代表一種變換(並不一定是旋轉變換)。
- 一個旋轉矩陣乘以一個向量(左乘或者右乘)將使得該向量被旋轉。
其中,2維的旋轉矩陣形式如下:
通過觀察上面的旋轉角示意圖,這樣一個矩陣形式是容易理解的。通過對座標系作逆時針
對於3維的旋轉矩陣而言,其矩陣形式是與2維的旋轉矩陣類似的:均通過將座標軸上的單位向量經旋轉後的像作爲其旋轉矩陣的某一列。以繞
並且,旋轉矩陣有一個非常完美的性質:正交矩陣,即對於旋轉矩陣
-
-
-
在算旋轉矩陣的逆矩陣的時候,可以直接求其轉置矩陣,省下許多計算量。其次,其行列式爲1意味着在經過旋轉變換以後,圖形的大小和形狀都不會發生改變(比方說一個圓繞其圓心旋轉任意角度,其半徑都不會改變)。關於旋轉矩陣是正交矩陣的證明可以參見這篇文章:旋轉矩陣(Rotate Matrix)的性質分析
在正交矩陣的前提下,我們可以得到旋轉矩陣一個有趣的性質:旋轉矩陣對應特徵值1的特徵向量爲其旋轉軸。因爲旋轉矩陣爲正交矩陣,故其特徵值爲
歐拉角
歐拉這樣一位劃時代的數學大師提出的歐拉角,是一種十分簡單的表示旋轉的有力工具。
來看看
令原始座標系的三個座標軸分別爲
x,y,z ,旋轉後的座標系的三個座標軸爲X,Y,Z ,N 軸是xOy 平面與XOY 平面的交線(也可以利用外積將N 軸定義爲N=z×Z )。這樣一來,三個歐拉角可定義如下:
-α (或φ ) 是x 軸和N 軸的夾角;
-β (或θ ) 是z 軸和Z 軸的夾角;
-γ (或ψ ) 是N 軸和X 軸的夾角;
歐拉角示意圖
也就是說,歐拉角將繞一個過原點的旋轉軸旋轉
1. 繞
2. 繞
3. 繞
這樣的旋轉順序被稱爲是“
看到這裏,也許你已經想罵人了:嘿,說好的“歐拉角很簡單呢?”。別急,可能這樣將座標系旋轉來旋轉去確實會令人有些頭大(想象不出來如何旋轉的同學,可以參看歐拉角-
1. 繞
2. 繞
3. 繞
爲了證明上述兩種旋轉過程等價(即最終的旋轉結果相同),可以利用歐拉角對應的旋轉矩陣進行證明,證明過程如下:(參考自歐拉角與萬向節死鎖)
記
- 繞
- 繞
- 繞
- 繞
- 繞
- 繞
那麼問題便轉化爲求證:
證明:
顯然,
而對於
同理可得:
綜上所述有:
因此,實際上在使用歐拉角表示旋轉時,可以直接將其理解爲先繞
需要注意的是:
1. 歐拉角的旋轉順序並不一定都是“
2. 細心的同學可能會發現,在旋轉矩陣中,最先進行的旋轉操作對應的旋轉矩陣在最右側與向量相乘,旋轉矩陣按照旋轉的次序從右向左排列;而在歐拉角中,最先進行的旋轉操作(此處說的是座標系跟隨旋轉的情形)對應的旋轉矩陣在最左側與向量相乘。看到一篇文章,三維旋轉:旋轉矩陣,歐拉角,四元數,對於這個問題是解釋得不錯的:
對於前者(旋轉矩陣),我們始終是以絕對參考系爲參照來的,對於後者(歐拉角),我們每一次旋轉的刻畫都是基於剛體的座標系。比如,在歐拉角中的第2步,繞
x 軸旋轉β ,這裏的x 軸實際上是N 軸了(而不是藍色的x 軸)。
爲什麼旋轉參考系的不同會導致旋轉矩陣次序的差異呢?細想一下便知,旋轉矩陣左乘疊加用以描述三維變換效果的疊加,這本身就是基於絕對座標系的,所以旋轉矩陣一節沒有疑問;而對於歐拉角一節的這種旋轉方式,這樣考慮:
1. 如果有一個“影子座標系3”與原座標系重合,然後首先進行了第3步(繞z 軸旋轉γ );
2. 然後有一個“影子座標系2”也與原座標系重合,然後與“影子座標系3”一起(視作同一個剛體)進行了第二步;
3. 最後一個“影子座標系1”,與前兩個座標系一起進行了第一步。
此時,考察“影子座標系”1和2,他們就分別落在了歐拉角旋轉的兩個“快照”上,而“影子座標系3”就落在旋轉後的位置上(紅色的)。
而在上述過程中,“影子座標系3”就是相對於絕對座標系依次進行了第三步,第二步,和第一步。所以歐拉角的旋轉矩陣寫成那樣,也是行得通的。
說了這麼多,先停下來總結一下旋轉矩陣和歐拉角:
旋轉矩陣
- 優點:學過線性代數的都能很容易地理解;
- 缺點:和其它表示旋轉的方式相比,其空間消耗較大,一個三維的旋轉矩陣需要存儲9個元素,而且在作矩陣乘法時也會消耗較多的時間。
- 歐拉角
- 優點:表示簡單,僅需要存儲三個值,
- 缺點:在編程實現上,通常還是將其轉化爲旋轉矩陣進行計算,其空間複雜度和時間複雜度沒有太大的變化;且在使用過程當中可能會出現著名的萬向節鎖現象,直觀理解可以參考這個視頻,歐拉旋轉。
這個視頻比較形象地講解了何謂萬向節鎖,萬向節鎖大體說來便是物體繞某個座標軸旋轉了90度,使得某兩個座標軸平面重合,從而丟失了一個維度。在這種情況下,無論接下來作什麼旋轉都無法將物體旋轉到某個角度,除非打破原先定義的旋轉順序或者同時旋轉三個座標軸。這樣一個問題的產生也使得歐拉角在球面平滑插值上“力不從心”。
這樣看來,也許四元數的出現正是一個
羅德里格旋轉公式
提到歐拉角,就不得不提及羅德里格旋轉公式。羅德里格旋轉公式的出現將歐拉角從較複雜的旋轉矩陣計算“解放”了出來。該旋轉公式是這樣的:
給定旋轉軸
r⃗ ,旋轉角θ 以及一個點p⃗ ,則p⃗ 繞旋轉軸r⃗ 旋轉θ 後的點的計算公式爲:
R(r⃗ ,θ,p⃗ )=p⃗ cosθ+(r⃗ ×p⃗ )sinθ+r⃗ (r⃗ p⃗ )(1−cosθ).
該公式是由法國數學家
羅德里格旋轉公式的核心思想是向量分解:不妨先假設三維空間中待旋轉的點(向量)爲
羅德里格旋轉公式示意圖
如此一來,我們直接在一個2維平面上旋轉
有趣的是,羅德里格旋轉公式通常還有另外一種形式(先劇透一下,這與後面要介紹的四元數息息相關~):
令
a2+b2+c2+d2=1 ,其中a=cos(θ/2) ,再設r=(b,c,d)=sin(θ/2)r⃗ ,那麼羅德里格旋轉公式還可以寫成:
R(a,r,p⃗ )=2a(r×p⃗ )+2(r×(r×p⃗ ))+p⃗ .
證明:將
因此,
羅德里格旋轉公式第二種表示形式提出了可以用於創建3維旋轉的4個參數。也許對於已經學過四元數的同學,看到這裏應該會有似曾相識的感覺吧……別急,咱們繼續往下看~(^▽^)
複數
呼呼呼……終於進入第二部分嚕,談及四元數不可避免地需要提及複數。我個人始終認爲,兩者之間的聯繫是密不可分的。
複數最初來自於求解一些特定的二次方程,比如
複數便是這樣一類數字:
其中,
通常爲了便於理解,我們會用二維平面上的一點來表示一個複數,此時兩個座標軸分別爲實數軸和虛數軸:
四元數的乘法運算法則爲:
也可以寫成:
因此,一個複數也只是一個帶有特殊乘法運算的2維向量罷了。
同時,我們可以得到:
經過旋轉矩陣一節的“薰陶”以後,相信對這個形式已經不陌生了。沒錯,這就是2維旋轉的複數形式!!!
四元數
- 四元數的誕生
- 四元數的性質
- 四元數與三維旋轉的“千絲萬縷”
- 四元數與四維旋轉
- 四元數的可視化
- 四元數的插值
第二部分嘩地一下就結束了(大霧),主要是因爲上過高中的應該都學過複數,因此許多性質也就不再贅述。第二部分僅列出理解四元數需要的一些“前置技能”而已,現終於進入核心章節——四元數了(撒花(^▽^))。
四元數的誕生
愛爾蘭數學家漢密爾頓可以說是“四元數之父”了。他在回憶錄當中大概是這樣描述四元數的誕生的:有一天他在吃早餐時,他的兒子問他:“爸爸,你可以讓兩個三維向量相乘得到另外一個三維向量嗎?”他遺憾地回答:“不,我只能將兩個三維向量相加減得到另外一個三維向量。”
那麼這裏就會出現問題了,
終於在1843年,當漢密爾頓在都柏林的布魯姆橋下沿着皇家運河散步時,他突然意識到僅僅三個維度是無法定義出滿足上述條件的乘法運算,必須增加一個維度才行!四元數就此誕生!他非常興奮地將他的成果雕刻在橋上,大致內容如下:
任意一個四元數可以表示成
用乘法表即可表示成:
注意,這裏的乘法運算不再滿足交換律。如果你熟悉叉積,這可能看起來很熟悉。實際上,叉積正是來自四元數。
此外,對於上述定義的乘法運算,每一個非零向量都有其逆元。後面還會提到,這意味着當我們希望撤銷某一個旋轉時,我們只要取該旋轉操作對應的四元數的逆元即可,這是十分方便的。
講到這裏,我們現在已經可以回答前兩個問題了(可能有同學已經忘了最初的問題是什麼,這裏再貼一下):
- 爲什麼是四個元?
i,j,k 是什麼?- 爲什麼旋轉的公式是
qpq−1 ?- 爲什麼是
θ/2 ?- 我們應該如何理解
4D (4D 可視化)?
對於問題1:爲什麼是四個元?
因爲僅僅三個維度是無法定義出滿足條件的乘法運算的:
1. 兩個向量作乘法運算的結果仍舊是一個向量;
2. 該乘法運算不滿足交換律;
3. 兩個非零向量作乘法運算以後不能產生零向量。
對於問題2:
存在於四維空間的三個座標軸。
四元數的性質
某種程度上,四元數是由複數擴展而來的:
它可以表示四維平面上的一點
四元數的加減和普通的向量加減是類似的,因此這裏不再贅述。我們講講四元數的乘法。
取兩個四元數
需要注意的是,因爲包含叉積運算的緣故,故四元數之間的乘法運算一般不滿足交換律:
這樣,我們容易知道,對於四元數之間的乘法運算和任意四元數
四元數與旋轉的“千絲萬縷”
與複數類似,單位四元數(記住,這類四元數的模是1!!!)可以表示一個旋轉,後面會進行證明。
對於3維旋轉,令
\omega=cos(\theta/2),\\(x,y,z)=v=sin(\theta/2)r.
看過前面的羅德里格旋轉公式的同學,一定對此表示十分熟悉……接下來便會介紹如何利用四元數進行3維向量的旋轉。
對於單位四元數q=(\omega,v)=(cos(\theta/2),sin(\theta/2)r) 而言,我們很容易就可以知道它的逆元(自己拿筆在紙上驗證一下即可):
q^{-1}=(\omega,v)^{-1}=(cos(-\theta/2),sin(-\theta/2)r)\\=(cos(\theta/2),-sin(\theta/2)r)\\=(\omega,-v)=q^{*}.
易知,單位四元數的逆元是和其共軛相等的。再次強調一下,這個性質僅僅是對單位四元數成立。有了它,四元數的旋轉定理(自己命名的,捂臉逃走(/ω\))也就順理成章地騰空出世了~
四元數旋轉定理:
已知三維向量p 和單位四元數q ,將p 看成一個四元數(爲了方便,我依舊命名爲p ),即p=(0,p) ,則向量p 經旋轉q 操作後的結果爲:
p'=qpq^{-1}=qpq^{*}.
還可以寫成如下形式:
p'=p+2\omega(v\times p)+2(v\times(v\times p)).
(喂,這不就是羅德里格旋轉公式嗎……)
先來看第二種形式,你們的猜測是沒錯的,這其實就是羅德里格旋轉公式的“變種”,證明方法也與羅德里格旋轉公式的證明方法類似,只要先把單位四元數q 拆成\omega 和v 即可,即:
四元數
\omega=cos(\theta/2),(x,y,z)=v=sin(\theta/2)\vec r,\\p'=p+2\omega(v\times p)+2(v\times(v\times p));
羅德里格旋轉公式
a=cos(\theta/2),(b,c,d)=r=sin(\theta/2)\vec r,\\p'=p+2a(r\times p)+2(r\times(r\times p)).
不得不佩服一下,羅德里格真的是一個富有遠見的數學家……
再來看看第一種形式:p'=qpq^{-1}=qpq^{*} ,它的證明可不簡單,但我覺得還是有必要寫一下,因爲它的證明確實是蠻精彩的。(當然,沒興趣的同學就跳過吧……)證明過程參考自博客三維旋轉:旋轉矩陣,歐拉角,四元數,不過我個人感覺博主的證明寫得有些亂,因此我整理如下:
p'=qvq^{-1}=qvq^{*}.
證明:如下圖所示,u 爲旋轉軸上的單位向量,旋轉角度爲\sigma ,向量v 旋轉到w 處,旋轉到\sigma /2 處爲k ,圖中並未標出。
(圖片來自參考博客)
令四元數q=(cos(\sigma/2),sin(\sigma/2)u) ,則
q=(cos(\sigma/2),sin(\sigma/2)u)=(\frac{kv}{{{|v|^2}}},v\times k)=\frac{1}{{{|v|^2}}}(0,-k)(0,v),
爲了方便,仍舊用四元數k^* 表示(0,-k) ,四元數v 表示(0,v) ,即
q=\frac{1}{{{|v|^2}}}k^*v.
現在令
w=qvq^*,
如果能證明w 與v 的夾角是\sigma ,且v,k,w 在同一個平面上,則說明w 是v 繞旋轉軸u 旋轉\sigma 得到的,從而命題得證。
不妨來計算一下wk^* 有:
wk^*=(qvq^*)k^*=qvq^{-1}k^*\\ \ =qv(\frac{1}{{{|v|^2}}}k^*v)^{-1}k^*\\ \ \ =|v|^2qvv^{-1}(k^*)^{-1}k^*\\ \quad \quad \quad \ \ \ \ =|v|^2q=|v|^2\frac{1}{{{|v|^2}}}k^*v=k^*v,
對於上式wk^*=k^*v ,將其拆分爲四元數的\omega 部分和v 部分進行分析:\omega 部分相等表明w,k 夾角與k,v 的夾角相同,v 部分相等表明w,-k 與-k,v 所處的平面相同,這就說明w 是v 繞旋轉軸u 旋轉\sigma 得到的,從而命題得證。
顯然,我們已經解決了問題3:爲什麼旋轉的公式是qpq^{-1} ?接下來我們嘗試解決問題4:爲什麼是\theta/2 ?
幸運的是,對於這個問題,我在一篇文章Understanding \ Quaternions 裏面找到了答案。限於篇幅,我就不貼出來了,英文比較好的同學可以看一下,英文比較吃力的同學也可以看一下譯文Understanding\ Quaternions 中文翻譯《理解四元數》。
想要進行一下直觀理解的也可以參看下圖:
(圖片來自知乎問題如何形象地理解四元數?Yang\ Eninala 的回答)
上圖非常直觀地回答了問題4:爲什麼在p'=qpq^{-1} 裏的q=(cos(\sigma/2),sin(\sigma/2)r) 用的是\theta/2 而非\theta ?
直觀原因就是q,q^{-1} 做的均是一個\theta/2 的旋轉,且qp,pq^{-1} 不一定是一個純四元數(即第一個分量爲0的四元數,這是三維向量的特殊表示形式)。因此,爲了保證最終結果爲一個純四元數,我們須作兩次旋轉:第一次旋轉結果qp 跳出了原先的三維超平面,第二次旋轉結果pq^{-1} 才又回到了三維超平面的世界。
四元數與四維旋轉
說完了三維旋轉,終於可以講講四維旋轉這樣一種人腦很難想象的操作了。實際上,四元數定義的都是四維旋轉,而不是三維旋轉。三維旋轉僅僅是四維旋轉的一種特殊情形,就像二維旋轉是三維旋轉的一種特殊情形一樣。利用四元數進行三維旋轉時,其實是在一個四維空間上的某個三維超平面上進行的。
一般來說,單獨一個四元數是無法執行四維旋轉的,一個四維旋轉可以唯一地被拆分爲一個左旋轉
四元數的可視化
終於到最後一個問題了:我們都是生活在三維空間內的生物,該如何想象“生活在”在四維空間內的四元數呢?
接下來我們僅僅考慮模不超過1的四元數(容易想象一些……),將其構成的4維超球切成三塊,它們都是四維空間的半球在3維空間上的投影(在我們看來就是三維球體了),這個“切”的依據便是四元數
模不超過1的四元數構成的4維超球“切割”示意圖
經過投影切割後,我們可以得到兩個實心球(
當截面上的向量長度等於0時,你就會得到一個單位四元數(此時
四元數的插值
前面已經介紹過歐拉角的萬向節鎖問題,正是由於萬向節鎖導致歐拉角無法很好地用於三維旋轉的插值(當出現萬向節鎖現象時無法按照原定旋轉順序得到預期的旋轉,即歐拉角用於三維旋轉的插值時並不平滑)。那麼。這時候就必須要四元數站出來扛大樑了~以下部分參考文章
事實上,球面上的線性插值和一般的線性插值是有一些區別的。一般的線性插值公式爲
(圖片來自參考文章)
當
不妨設球面線性插值的計算公式爲
(圖片來自參考文章)
將
再將
聯立求解並用三角函數和差公式化簡得:
故計算向量的球面線性插值的計算公式如下所示:
(圖片來自參考文章)
注意到,在使用這個公式之前還需要計算
需要注意的是,當
四元數的球面插值示意圖
可以看到,當
此外,當
羣論觀點下的四元數
本章建議學習過一些抽象代數的同學觀看,沒有學過的就跳過吧……(丫咩蘿,也是花了一些精力在這裏的o(╥﹏╥)o)部分內容參考自文章四元數的運算。
- 四元數除環
- 羣旋轉
- 四元數的矩陣表示
Q8 羣
四元數除環
由除環的定義,四元數所構成的集合是一個除環(如果四元數還滿足交換律它就構成一個域)。
四元數除環因爲它的不可交換性導致了一個很有趣的結果:四元數的
羣旋轉
在“四元數和空間轉動”的維基百科裏提到:
非零四元數的乘法羣在R3的實部爲零的部分上的共軛作用可以實現轉動。單位四元數(絕對值爲1的四元數)若實部爲
cosθ ,它的共軛作用是一個角度爲2θ 的轉動,轉軸爲虛部的方向。四元數的優點是:
- 表達式無奇點(和例如歐拉角之類的表示相比)
- 比矩陣更簡煉(也更快速)
- 單位四元數的對可以表示四維空間中的一個轉動。
那麼在羣論觀點下,四元數是如何和三維旋轉扯上聯繫的呢?不妨看看四元數除環的四個基
又
同時,
四元數的矩陣表示
因爲單位四元數構成的三維單位球面
而
故
此時
同理,我們還可以將單位四元數構成的三維單位球面
再令
則
此時
事實上,上述兩種矩陣表示都可以認爲是四元數另外的存在形式。
既然可以用2級特殊酉羣
設
Vn 是兩個不定元x 和y 的n 次齊次多項式組成的複線性空間。考慮拓撲羣SL(2,C) 到拓撲羣GL(Vn) 的一個映射ϕn :
ϕn:SL(2,C)→GL(Vn),A↦ϕn(A),
其中
(ϕn(A)f)(x,y)=f((x,y)A)=f(a11x+a21y,a12x+a22y),
這裏f∈Vn,A=(aij) ,則SU(2) 的上述不可約復表示ϕn(n=0,1,2,……) 是SU(2) 的全部不等價的有限不可約復表示。從而SO(3) 的上述不可約復表示ϕ2m(m=0,1,2,……) 是SO(3) 的全部不等價的有限不可約復表示。
Q8 羣
因爲單位四元數構成的三維單位球面
容易驗證,它構成一個羣,我們稱之爲
若將
這對應於一個置換(1324)(5768)。這是很符合凱萊定理的:任何一個羣都同一個變換羣同構,這意味着我們能通過研究常見的置換羣去“解剖”抽象的
此外,
證明:對於
當
當
當
綜上所述,
因爲
四元數在Unity 中的應用
很多時候,我們不僅要仰望星空,還需要腳踏實地。四元數在
static function AngleAxis (angle : float, axis : Vector3) : Quaternion
//繞axis軸旋轉angle,創建一個旋轉,即返回一個四元數變換。
這是繼承自
//將待旋轉向量繞y軸旋轉30度
Vector3 newVector = Quaternion.AngleAxis(30, Vector3.up) * oldVector;
在
static function Lerp (from : Quaternion, to : Quaternion, t : float) : Quaternion
//通過t值from向to之間插值,並且規範化結果。
//這個比Slerp更快但是如果旋轉較遠看起來就比較差。
這同樣是繼承自
using UnityEngine;
using System.Collections;
public class example : MonoBehaviour {
public Transform from;
public Transform to;
public float speed = 0.1F;
void Update() {
transform.rotation = Quaternion.Lerp(from.rotation, to.rotation, Time.time * speed);
}
}
呼呼呼……終於完成這篇“吐血之作”了,希望能對大家有幫助(也不知道有木有人看2333)。這篇寫得有點長,開學以後就沒那麼多時間寫了,以後的篇幅當然會短得多,而且更新的頻率可能不高……但能肯定的是以後的每一篇博文都會用心寫。下一篇博文的主題預計會是今年