Quaternion 掃盲

取得單一 Quaternion 的某個方向(Direction – vector)?

由於 Quaternion 是管理轉向的, 就像 Local / World Space 空間 裡所展示的
“它” Quaternion 自己就是代表一個物件的轉向 (Local space).
而它的轉向是付加在世界坐標上面的 (World space).
它就像是一個記錄了某物件的方位的轉換, 而在牑程時, 我們可以利用 Quaternion 來轉換 Local / world direction
用 Unity3D C#的方式來看的話就像這樣.

Quaternion facing = /* whatever */;
Vector3 myForward = facing * Vector3.forward;
Vector3 myRight = facing * Vector3.right;
Vector3 myUpward = facing * Vector3.up;
Vector3 myLeft = -myRight;
Vector3 myBack = -myForward;
Vector3 myBottom = -myUpward;

除了上面範例的 6 個 Local space 的 vector direction,
我們還可以把任意一支的 Vector3 丟進去取得相對應的 World space direction.
說白一點的例子就是 : 你現在可以利用 Quaternion 取得某個人物的左手到底是不是指著北方咯.

四元數的轉向疊加 (相乘)

單一個轉向可以用的地方不多, 但多層轉向的方向運算應該就非常多,
但是四元數的矩陣是沒有 “加” (+) 這一個運算符號的,
題外: 因為把 Quaterion 的四元數轉換為 matrix 的話看起來是這樣的.

在 Quaterion 裡頭要疊加其他 Quaterion 的話就只有”乘” (*)
說白一點甚麼是多層級的轉向?
我們以手臂來做例子來說明一下.

“上臂” 的轉動會帶動 “前臂”
這裡面, “前臂” 的轉向是依從 “上臂” 的轉向的.
所以 “上臂” 是父層級的轉向,
“下臂” 是子層級的轉向.

在數學概念上只要把兩個 Quaterion 相乘就是代表兩個轉向的累加.
在 Unity3D C# 中看起來是這樣的.

Quaternion upperArm = /* local downward */
Quaternion lowerArm = /* local upward */

Quaternion armRotation = upperArm * lowerArm;

我們忽略掉身體, 假設 “上臂” 的下方就是世界的下方, 而 “前臂” (lower arm) 是指向自己的上方的話
就能看到這樣的景像.

如果不明白為何是指向世界坐標”前方”的朋友要再理解一下 Local / World Space 空間 喔,
要嘗試把自己代入 “前臂” 的角式來考慮到底相對的角度是甚麼.

多層轉向消除/減法 (誤)

在運算上, 如果只有疊加的話必然希望有減法罷,但是喲 四元數就只有乘數.
所以我們怎樣以乘數來 “消除” 某個特定的轉向呢?!
答案是把 Quaternion 這個矩陣反轉 (Inverse)
註: 並不是把 x,y,z,w 反轉啊… 是把矩陣反轉.

假設 Quaternion A, B
我們相算 A – B 的話應該是寫成
Quaternion answer = A * Quaternion.Inverse(B);

相乘順序的特性

四元數轉向是有順序的 a * b 跟 b * a 的意義不相同,

簡單來說 Quaternion 的疊加次序是從右到左來看的.
而同一時間我們寫算式/程序多是從左到右的寫的很容易就犯了錯誤.
以上面手臂的舉例來說明,
“前臂”先轉向上方, 然後”上臂”才轉到下方.

我們以 C# 表現再看一下轉向的關係

Quaternion parent; // 父層轉向
Quaternion child; // 子層轉向
Quaternion combine; // 最終轉向

1) combine = parent * child;
在這裡說明的是 先轉動 child, 然後再轉動 parent

2) child == parent.Inverse() * combine;
由剛剛的答案(Combine)乘上 parent.Inverse()即是取消 parent 的意思.
因為全寫應該是 child = parent.Inverse() * parent * child;

3) parent == combine * child.Inverse();
同理要由combine 解拆 parent 的轉向就這樣.
因為全寫應該是 parent = parent * child * child.Inverse();

Reference :

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

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

*

這個網站採用 Akismet 服務減少垃圾留言。進一步瞭解 Akismet 如何處理網站訪客的留言資料