四元數左乘右乘 四元數的建立

2021-10-16 16:34:26 字數 4502 閱讀 5865

在了解了上述知識後,我們就不需要那麼懼怕四元數了,實際上它和矩陣類似,不同的只是它的表示方式以及運算方式。那麼在unity裡如何利用四元數進行旋轉呢?unity裡提供了非常多的方式來建立乙個四元數。例如quaternion.angleaxis(float

angle, vector3

axis),它可以返回乙個繞軸線axis旋轉angle角度的四元數變換。我們可以乙個vector3和它進行左乘,就將得到旋轉後的vector3。在unity裡只需要用乙個「

」操作符就可以進行四元數對向量的變換操作,相當於我們上述講到的p′=qpq−1操作。如果我們想要進行多個旋轉變換,只需要左乘其他四元數變換即可。例如下面這樣:

1. vector3 newvector = quaternion.angleaxis(90, vector3.up) * quaternion.lookrotation(somedirection) * somevector;

儘管尤拉角更容易我們理解,但四元數比尤拉角要強大很多。unity提供了這兩種方式供我們選擇,我們可以選擇最合適的變換。

例如,如果我們需要對旋轉進行插值,我們可以首先使用quaternion.eulerangles來得到尤拉角度,然後使用mathf.clamp對其進行插值運算。

最後更新quaternion.eulerangles或者使用quaternion.euler(yourangles)來建立乙個新的四元數。

又例如,如果你想要組合旋轉,比如讓人物的腦袋向下看或者旋轉身體,兩種方法其實都可以,但一旦這些旋轉不是以世界座標軸為旋轉軸,比如人物扭動脖子向下看等,那麼四元數是乙個更合適的選擇。unity還提供了transform.forward,

transform.right and

transform.up 這些非常有用的軸,這些軸可以和quaternion.angleaxis組合起來,來建立非常有用的旋轉組合。例如,下面的**讓物體執行低頭的動作:

1. transform.rotation = quaternion.angleaxis(degrees, transform.right) * transform.rotation;

關於quaternion的其他函式,後面再補充吧,原理類似~

補充:尤拉旋轉

尤拉旋轉是怎麼運作的

尤拉旋轉是我們最容易理解的一種旋轉方式。以我們生活中為例,乙個舞蹈老師告訴我們,完成某個舞蹈動作需要先向你的左邊轉30°,再向左側彎腰60°,再起身向後彎腰90°(如果你能辦到的話)。上面這樣乙個旋轉的過程其實和我們在三維中進行尤拉旋轉很類似,即我們是通過指明繞三個軸旋轉的角度來進行旋轉的,不同的是,日常生活中我們更願意叫這些軸為前後左右上下。而這也意味著我們需要指明乙個旋轉順序。這是因為,先繞x軸旋轉90°、再繞y軸30°和先繞y軸旋轉90°、再繞x軸30°得到的是不同的結果。

在unity裡,尤拉旋轉的旋轉順序是z、x、y,這在相關的api文件中都有說明,例如transform.rotate。其實文件中說得不是非常詳細,還有乙個細節我們需要明白。如果你仔細想想,就會發現有乙個非常重要的東西我們沒有說明白,那就是旋轉時使用的座標系。給定乙個旋轉順序(例如這裡的z、x、y),以及它們對應的旋轉角度(α,β,r),有兩種座標系可以選擇:

繞座標系e下的z軸旋轉α,繞座標系e下的y軸旋轉β,繞座標系e下的x軸旋轉r,即進行一次旋轉時不一起旋轉當前座標系;

繞座標系e下的z軸旋轉α,繞座標系e在繞z軸旋轉α後的新座標系e'下的y軸旋轉β,繞座標系e'在繞y軸旋轉β後的新座標系e''下的x軸旋轉r,

即在旋轉時,把座標系一起轉動;

很容易知道,這兩種選擇的結果是不一樣的。但如果把它們的旋轉順序顛倒一下,其實結果就會一樣。說得明白點,在第一種情況下、按zxy順序旋轉和在第二種情況下、按yxz順序旋轉是一樣的。證明方法可以看下這篇文章。而unity文件中說明的旋轉順序指的是在第一種情況下的順序。

如果你還是不懂這意味著什麼,可以試著呼叫下這個函式。例如,你認為下面**的結果是什麼:

1. transform.rotate(new vector3(0, 30, 90));

原模型的方向和執行結果如下:

而我們可以再分別執行下面的**:

1. // first case

2. transform.rotate(new vector3(0, 30, 0));

3. transform.rotate(new vector3(0, 0, 90));

4.5. // second case

6. // transform.rotate(new vector3(0, 0, 90));

7. // transform.rotate(new vector3(0, 30, 0));

兩種情況的結果分別是:

可以發現,呼叫transform.rotate(new vector3(0, 30, 90));是和第一種情況中的**是一樣的結果,即先旋轉y、再旋轉z。進一步實驗,我們會發現transform.rotate(new vector3(30, 90, -40));的結果是和transform.rotate(new vector3(0, 90, 0));transform.rotate(new vector3(30, 0, 0));transform.rotate(new vector3(0, 0, -40));的結果一樣的。你會問了,文件中不是明明說了旋轉順序是z、x、y嗎?怎麼現在完全反過來了呢?原因就是我們之前說的兩種座標系的選擇。在一次呼叫transform.rotate的過程中,座標軸是不隨每次單個座標軸的旋轉而旋轉的。而在呼叫transform.rotate後,這個旋轉座標系才會變化。也就是說,transform.rotate(new vector3(30, 90, -40));執行時使用的是第一種情況,而transform.rotate(new vector3(0, 90, 0));transform.rotate(new vector3(30, 0, 0));transform.rotate(new vector3(0, 0, -40));每一句則是分別使用了上一句執行後的座標系,即第二種座標系情況。因此,我們看起來順序好像是完全是反了,但結果是一樣的。

數學模型

尤拉旋轉的數學實現就是使用矩陣。而最常見的表示方法就是3*3的矩陣。在wiki裡我們可以找到這種矩陣的表示形式,以下以按xyz的旋轉順序為例,三個矩陣分別表示了:

在計算時,我們將原來的旋轉矩陣右乘(這裡使用的是列向量)上面的矩陣。從這裡我們也可以證明上面所說的兩種座標系選擇是一樣的結果,它們之間的不同從這裡來看其實就是矩陣相乘時的順序不同。第一種座標系情況,指的是在計算時,先從左到右直接計算r中3個矩陣的結果矩陣,最後再和原旋轉矩陣相乘,因此順序是xyz;而第二種座標系情況,指的是在計算時,從右往左依次相乘,因此順序是反過來的,zyx。你可以驗證r左乘和右乘的結果表示式,就可以相信這個結論了!

萬向節鎖

如果你還是不明白,我們來做個試驗。還是使用之前的模型,這次我們直接在面板中把它的尤拉角中的x值設為90°,其他先保持不變:

此時模型是臉朝下(下圖你看到的只是乙個頭頂):

現在,如果我讓你不動x軸,只設定y和z的值,把這個模型的臉轉上來,讓它向側面看,你可以辦到嗎?你可以發現,這時候無論你怎麼設定y和z的值,模型始終是臉朝下、在同一平面旋轉,看起來就是y和z控制的是同乙個軸的旋轉,下面是我擷取的任意兩種情況:

這就是一種萬向節鎖的情況。這裡我們先設定x軸為90°也是有原因的,這是因為unity中尤拉角的旋轉順序是zxy,即x軸是第二個旋轉軸。當我們在面板中設定任意旋轉值時,unity實際是按照固定的zxy順序依次旋轉特定角度的。

在**裡,我們同樣可以重現萬向節鎖現象。

1. transform.rotate(new vector3(0, 0, 40));

2. transform.rotate(new vector3(0, 90, 0));

3. transform.rotate(new vector3(80, 0, 0));

我們只需要固定中間一句**,即使y軸的旋轉角度始終為90°,那麼你會發現無論你怎麼調整第一句和最後一句中的x或z值,它會像乙個鐘錶的表針一樣總是在同乙個平面上運動。

萬向節鎖中的「鎖」,其實是給人一種誤導,這可能也是讓很多人覺得難以理解的乙個原因。實際上,實際上它並沒有鎖住任何乙個旋轉軸,只是說我們會在這種旋轉情況下會感覺喪失了乙個維度。以上面的例子來說,儘管固定了第二個旋轉軸的角度為90°,但我們原以為依靠改變其他兩個軸的旋轉角度是可以得到任意旋轉位置的(因為按我們理解,兩個軸應該控制的是兩個空間維度),而事實是它被「鎖」在了乙個平面,即只有乙個維度了,缺失了乙個維度。而只要第二個旋轉軸不是±90°,我們就可以依靠改變其他兩個軸的旋轉角度來得到任意旋轉位置。

數學解釋

我們從最簡單的矩陣來理解。還是使用xyz的旋轉順序。當y軸的旋轉角度為90°時,我們會得到下面的旋轉矩陣:

我們對上述矩陣進行左乘可以得到下面的結果:

可以發現,此時當我們改變第一次和第三次的旋轉角度時,是同樣的效果,而不會改變第一行和第三列的任何數值,從而缺失了乙個維度。

我們再嘗試著理解下它的本質。wiki上寫,萬向節鎖出現的本質原因,是因為從尤拉角到旋轉的對映並不是乙個覆蓋對映,即它並不是在每個點處都是區域性同胚的。不懂吧。。。恩,我們再來通俗一下解釋,這意味著,從尤拉角到旋轉是乙個多對一的對映(即不同的尤拉角可以表示同乙個旋轉方向),而且並不是每乙個旋轉變化都可以用尤拉角來表示。其他更多的大家去參考wiki吧。

四元數左乘右乘 四元數 旋轉

四元數系列 首先很感謝各位的支援,本來我也就是說寫個自己看的筆記啥的,沒想到那麼多人點贊。本篇主要介紹旋轉相關的知識,其中會盡量把我認為精彩的部分說細一點,更像教程的方式去敘述,但是基礎性的公式證明應該還是不會提,畢竟篇幅有限。0.胡爾韋茲定理 上篇四元數定義中,為了完整性,我提到了三元數或五元數理...

四元數左乘右乘 四元數 尤拉角學習筆記 個人理解

一 背景知識 點乘 叉乘 複數的點乘 ai bj ck xi yj zk ax by cz 複數的叉乘 ai bj ck xi yj zk ax i i ay i j az i k bx j i by j j bz j k cx k i cy k j cz k k ijk三軸定義如上圖所示。滿足右手...

四元數左乘右乘 關於四元數的一些理解第二部分

p 是乙個沒有實部的單位四元數,表述為 0,v p 的模為1 p qpq好了,到了這裡細心地讀者已經發現一點問題了。雖然這裡,向量的表 示換成了沒有實部的四元數 例如pp 但是在這裡我們發現,在變換向量的時候不但用q 左乘向量 p同時也用 q右乘。到這裡筆者又要 囉嗦些關於 四元數的性質 盡可能詳細...