Unity-萬向節(jié)死鎖(Gimbal Lock)問題總結(jié)

一、歐拉角

1.1 歐拉角定義

Unity API中對Transform.eulerAngles的定義是,本身是Vector3,即三維矢量,含有x、y、z三個參數(shù)。

Unity API對Transform.eulerAngles的描述??

1.以歐拉角為單位的旋轉(zhuǎn);

2.x、y、z角度分別表示先圍繞z軸旋轉(zhuǎn)z度,再圍繞x軸旋轉(zhuǎn)x度,最后圍繞y軸旋轉(zhuǎn)y度;

3.僅使用此變量讀取角度并將其設(shè)置為固定值。不要增加它們,因為當(dāng)角度超過360度時會失敗。應(yīng)使用Transform.Rotate來執(zhí)行旋轉(zhuǎn)操作。

◆此處“角度超過360度時會失敗”的理解是,Unity內(nèi)部使用四元數(shù)去執(zhí)行旋轉(zhuǎn),不會存儲歐拉角的累計值,歐拉角只代表了等值的旋轉(zhuǎn)變化結(jié)果,當(dāng)旋轉(zhuǎn)角度X超過360度時,存儲的角度為X-360,例如,361度等同于1度,722度等同于2度。

同時,Unity API提醒我們不要單獨設(shè)置一個歐拉角的參數(shù)(例如,Eulerangles.x=10;),這將導(dǎo)致錯誤的旋轉(zhuǎn),應(yīng)當(dāng)同時對x、y、z三個參數(shù)進行設(shè)置。

1.2 歐拉旋轉(zhuǎn)的旋轉(zhuǎn)軸

歐拉旋轉(zhuǎn)中,總是沿著初始的固定軸向在進行按z、x、y順序的旋轉(zhuǎn)。例如,指定歐拉旋轉(zhuǎn)(90,90,90),它會先繞Z軸旋轉(zhuǎn)90度,再繞X軸旋轉(zhuǎn)90度,再繞Y軸旋轉(zhuǎn)90度,但是繞Z旋轉(zhuǎn)后,再繞X軸旋轉(zhuǎn)時,依然是繞著初始的X軸旋轉(zhuǎn),繞Y軸旋轉(zhuǎn)時同理。

正是由于歐拉旋轉(zhuǎn)沿Z、X、Y順規(guī)執(zhí)行和旋轉(zhuǎn)軸軸向的定義,導(dǎo)致了“萬向節(jié)死鎖”的發(fā)生。


二、萬向節(jié)死鎖

2.1萬向節(jié)定義和陀螺儀原理

萬向節(jié),也叫平衡環(huán)架(Gimbal),具有樞紐的裝置,使得一物體能以單一軸旋轉(zhuǎn)。由彼此垂直的樞紐軸所組成的一組三只平衡環(huán)架,則可使架在最內(nèi)的環(huán)架的物體維持旋轉(zhuǎn)軸不變。常常應(yīng)用于船上的陀螺儀、羅盤、飲料杯架等。

陀螺儀

在飛行器的航行中,進行XYZ三個方向旋轉(zhuǎn)的旋轉(zhuǎn)有專業(yè)的術(shù)語,見下圖:

飛行器旋轉(zhuǎn)示意圖

沿著機身右方軸(Unity中的+X)進行旋轉(zhuǎn),稱為pitch,中文叫俯仰。?

沿著機頭上方軸(Unity中的+Y)進行旋轉(zhuǎn),稱為Yaw,中文叫偏航。?

沿著機頭前方軸(Unity中的+Z)進行旋轉(zhuǎn),稱為Roll,中文叫桶滾。

當(dāng)飛行器或者船體發(fā)生桶滾、俯仰和偏航時,陀螺儀中的轉(zhuǎn)子和旋轉(zhuǎn)軸具有較大的慣性,會保持原來的姿態(tài),而其余的環(huán)則會發(fā)生旋轉(zhuǎn),最終保證軒子和旋轉(zhuǎn)軸的平衡,如圖所示:

初始狀態(tài)
俯仰
偏航
桶滾

2.2 萬向節(jié)死鎖

當(dāng)飛行器和船體仰起90度時,陀螺儀狀態(tài)如下:

仰起90度時狀態(tài)

此時沿藍色軸轉(zhuǎn)動,則轉(zhuǎn)子和旋轉(zhuǎn)軸將無法保持平衡。

此時沿藍色軸轉(zhuǎn)動

現(xiàn)在,

紅色連接頭:提供一個相對俯仰的自由度。

綠色連接頭:提供一個相對偏航的自由度。

藍色連接頭:提供一個相對偏航的自由度。

3個連接頭只提供了兩個自由度,桶滾的自由度丟失了,這種現(xiàn)象被稱為“萬向節(jié)死鎖”。

更加進一步地分析原因,歐拉角的X軸轉(zhuǎn)動造成最后的變化結(jié)果,受到到了預(yù)先執(zhí)行的Z軸轉(zhuǎn)動的影響,它仍然會造成某個相對自身的軸向的變化,但是結(jié)果不唯一;同樣,歐拉角的Y軸轉(zhuǎn)動,則受到了Z軸和X軸的影響,結(jié)果更加不唯一。

由于沿XYZ軸的轉(zhuǎn)動遵循Unity中歐拉旋轉(zhuǎn)的順規(guī)和軸向定義,有些情況下會造成某個軸向自由度的丟失。

再追究其本質(zhì),從歐拉角到旋轉(zhuǎn)是一個多對一的映射(即不同的歐拉角可以表示同一個旋轉(zhuǎn)方向),而且并不是每一個旋轉(zhuǎn)變化都可以用歐拉角來表示。


三、萬向節(jié)死鎖的避免

3.1 四元數(shù)介紹

利用四元數(shù)(Quaternion)來進行旋轉(zhuǎn)。

四元數(shù)本質(zhì)上是一種高階復(fù)數(shù),它的虛部包含了三個虛數(shù)單位,i、j、k,即一個四元數(shù)可以表示為x = a + bi + cj + dk。Unity中,Transform.rotation存儲四元數(shù)信息,我們可以使用一個四元數(shù)來執(zhí)行一個旋轉(zhuǎn)。

舉例說,把點P(1, 0, 1)繞旋轉(zhuǎn)軸u = (0, 1, 0)旋轉(zhuǎn)90°,求旋轉(zhuǎn)后的頂點坐標。首先將P擴充到四元數(shù),即p = (P, 0)。而q = (u*sin45°, cos45°)。求p′=qpq?1的值。最后的結(jié)果p'= ((1, 0, -1), 0),即旋轉(zhuǎn)后的頂點位置是(1, 0, -1)。

Unity內(nèi)部使用四元數(shù)表示所有旋轉(zhuǎn)。Unity API中并未對四元數(shù)進行詳細的定義,僅是提供了常見的若干四元數(shù)函數(shù),比如Quaternion.LookRotation, Quaternion.Angle,Quaternion.Eule,Quaternion.Slerp, Quaternion.FromToRotation和Quaternion.identity等。

在Unity中,使用四元數(shù)進行旋轉(zhuǎn),比歐拉旋轉(zhuǎn)更強大,能夠進行增量旋轉(zhuǎn),能夠避免萬向鎖,還能進行球面差值。

3.2 簡單的例子

使用四元數(shù)來實現(xiàn)一定角度的平滑旋轉(zhuǎn)的簡單示例如下:

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class rotate : MonoBehaviour

{

? ? [SerializeField]

? ? float rotateSpeed = 2f;

? ? bool isClick = false;

? ? Quaternion targetAngles;

? ? private void Start()

? ? {

? ? ? ? // Quaternion.Slerp()第二個參數(shù)需要的是四元數(shù),所以這里需要將目標的角度轉(zhuǎn)成四元數(shù)去計算

? ? ? ? targetAngles = Quaternion.Euler(0, 90f, 0);

? ? }

? ? // Update is called once per frame

? ? void Update()

? ? {

? ? ? ? // 用 slerp 進行插值平滑的旋轉(zhuǎn)

? ? ? ? transform.rotation = Quaternion.Slerp(transform.rotation, targetAngles, rotateSpeed * Time.deltaTime);

? ? ? ? // 當(dāng)初始角度跟目標角度小于1,將目標角度賦值給初始角度,讓旋轉(zhuǎn)角度是我們需要的角度

? ? ? ? if (Quaternion.Angle(targetAngles, transform.rotation) < 1)

? ? ? ? {

? ? ? ? ? ? transform.rotation = targetAngles;

? ? ? ? }?

? ? }

}

參考文章:

https://docs.unity3d.com/ScriptReference/Quaternion.html

https://www.cnblogs.com/driftingclouds/p/6626183.html

https://www.cnblogs.com/w-wfy/p/7616165.html

https://blog.csdn.net/fengya1/article/details/50721768

https://blog.csdn.net/andrewfan/article/details/60981437

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容