文章目錄
Rotation and Orientation in Unity
官方文檔地址:Rotation and Orientation in Unity
Unity中的旋轉,通常用四元數和歐拉角來表示。它們都有優缺點。Unity內部用四元數,在Inspector中顯示歐拉角形式,因爲該方法已於理解和編輯。
歐拉角和四元數
歐拉角
歐拉角由按照順序在x,y,z軸上進行的旋轉表示,當將一個歐拉角應用到一個GameObject時,每個軸上的旋轉都會被分別應用。
- 好處:歐拉角對於人來說時可讀的,可以跟讀歐拉角在腦海建立旋轉概念。
- 好處:歐拉角可以表達超過180度的旋轉,對應的,四元數會“尋找”旋轉的最短路徑,但是有時可能邏輯上是不正確的,比如對於一個不能以360度旋轉的炮塔,從最左旋轉到最有,對端路徑會打破旋轉限制。
- 限制:歐拉角受限於萬向鎖 Gimbal Lock,當在3個軸上旋轉時,可能第一次或第二次旋轉導致第三次旋轉軸指向跟前面旋轉的軸同樣的方向,叫做“degree of freedom”(旋轉自由度)丟失,因爲第三個旋轉值無法應用到對應的軸上,也可以理解爲丟失了一個旋轉軸。
四元數
四元數可以被用來表示旋轉或對象的朝向。該數學模型,用4個數來表示(x,y,z,w),然而這些數字既不表示旋轉軸,也不表示旋轉角度,無法理解,所以我們不能直接修改xyz分量的值(w表示角度,可能會發生錯誤。除非你非常瞭解這背後的數學原理。
小祕密:軸和角度藏在四元數中。假設沿着軸(nx,ny,nz)旋轉,角度爲A度,則四元數爲:
[w, x, y, z] = [cos(A/2), sin(A/2)nx, sin(A/2)ny, sin(A/2)nz]
Vector3可以表示位置和方向(當表示方向時,時原點在000點),一個四元數可以表示朝向和旋轉,當表示旋轉時,是從identity開始的旋轉。四元數不能表達超過180度的旋轉。
- 好處:沒有萬向鎖問題
- 限制:不能表達超過180度的旋轉,四元數用-180到180來表示360度的旋轉。
- 限制:不可讀,無法直接理解值的含義。
Unity用四元數來存儲GameObject的旋轉,因爲四元數更加健壯。
但是在Inspector面板上,顯示的旋轉是用歐拉角來表示的,因爲歐拉角是可讀可編輯的。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-1KdbpY1X-1580048145871)(https://docs.unity3d.com/uploads/Main/InspectorRotationEulerAngles.png)]
所以,可以看到,如果我們可以在Inspector中設置x:0,Y:365,Z:0來設置對象的旋轉,因爲四元數無法表達該旋轉,因此,啓動遊戲後,會變成X:0,Y:5,Z:0。效果相同。
編程中
當在腳本中處理旋轉時,應該用四元數來創建或修改旋轉值。當然有些情況下,使用歐拉角也是有效的,但是要牢記,要使用四元數接口來處理歐拉角,從四元數獲取,修改,重新應用歐拉角到四元數,可能會產生錯誤的結果。
直接創建和操作四元數
Unity提供了接口,用來創建和操作四元數,而且不需要歐拉角的參與。例如
創建
操作
- Quaternion.Slerp
- Quaternion.Inverse
- Quaternion.RotateTowards
- Transform.Rotate & Transform.RotateAround
歐拉角使用注意
然而,有時我們希望在代碼中使用歐拉角,這時,要將角度存儲到自己定義的變量中,並且用這些變量更新旋轉。因爲以獲取->修改->應用歐拉角的流程寫代碼,會出錯,因爲每次取得的歐拉角,是臨時從四元數計算出來的,每次計算可能返回不同的歐拉角,可能會導致萬向鎖問題。
// 正確
float x;
void Update ()
{
x += Time.deltaTime * 10;
transform.rotation = Quaternion.Euler(x,0,0);
}
// 錯誤
void Update ()
{
var angles = transform.rotation.eulerAngles;
angles.x += Time.deltaTime * 10;
transform.rotation = Quaternion.Euler(angles);
}
動畫中
很多3D創作插件,以及Unity內部,都有自己的動畫窗口,來用歐拉角編輯動畫的旋轉。
這些旋轉,經常超過四元數表達的範圍,比如旋轉720度,歐拉角是沒問題的,但是對於四元數來說,等於沒有旋轉。
Unity 的 Animation Window
Unity內部的動畫編輯窗口,提供了設置選項,來決定如何進行插值,用四元數或歐拉角。通過指定使用歐拉角,可以告訴Unity我們想要在完整的運動範圍內插值。如果用四元數,則會限制在限定的範圍內(-180,180),並用四元數插值。
導入的動畫數據
導入的外部動畫資源,文件通常會使用歐拉角記錄旋轉。默認Unity會重新進行採樣動畫生成新的四元數動畫幀,以避免旋轉超出四元數有效範圍。
例如,想象有2幀動畫,相隔6幀。第一幀旋轉x=0,第二幀(6幀後)旋轉是270。如果直接用四元數在這兩幀之間進行插值,則動畫會沿着最短路徑旋轉,即向相反方向旋轉90度。但是通過重新採樣,將旋轉定義爲6幀,沒幀是45度,這樣在進行四元數插值時,就正確了。
有時候,通過重新採樣,也不能達到跟原始動畫完全重合,這時,可以在動畫導入設置中,關閉重新採樣選項(Resample Curves),在運行時使用歐拉角進行插值。