天天看點

對Unity中的歐拉角的了解

【前言】

歐拉角對人來說是十分直覺的,很适合人機互動中,但不适用于插值和疊代。

在說到歐拉角時有兩點非常重要:旋轉方式和旋轉順序

【旋轉方式】

首先要區分每次旋轉是繞固定軸旋轉的,還是繞旋轉之後的軸旋轉的。

繞固定軸旋轉就是旋轉過程中XYZ軸不變,繞旋轉之後的軸旋轉表示每次旋轉時XYZ改變了。

在Unity中繞固定軸旋轉可以看做是繞世界坐标系旋轉。看下圖中的鲨魚的Transform中,面闆上顯示的Rotation為(0,0,0)。在場景中由于我們選擇的是Global,相當于繞固定軸旋轉。(這是鲨魚的初始圖)

對Unity中的歐拉角的了解
對Unity中的歐拉角的了解

現在我們把鲨魚的Rotation改為(0,90,0),顯然我們的意思是繞Y軸正方向逆時針旋轉了90°。(這裡要注意旋轉正負角度時是如何旋轉的,一般來說逆時針旋轉為正值,順時針旋轉為負值。)

注意看鲨魚身上的坐标軸沒有變。

對Unity中的歐拉角的了解

現在把Global改為Local,再看鲨魚身上的坐标軸,藍色的Z軸和紅色的X軸變了。這就是繞旋轉之後的坐标軸旋轉,下次再旋轉時以這個新的坐标軸為準。

對Unity中的歐拉角的了解

【旋轉順序】

繞固定軸旋轉時,分别繞X、Y、Z旋轉90°(左圖)和分别繞Z、Y、X旋轉90°(右圖)所得結果不同。(鲨魚的初始圖看上面)

對Unity中的歐拉角的了解
對Unity中的歐拉角的了解

繞旋轉之後的軸旋轉時,同樣地,分别繞X、Y、Z軸旋轉90°(左圖)和分别繞Z、Y、X旋轉90°(右圖)所得結果仍然不同。

對Unity中的歐拉角的了解
對Unity中的歐拉角的了解

因而,在用歐拉角表示旋轉時,需要先聲明旋轉順序,否則,按照不同的旋轉順序得到的結果不同。

【Unity中的旋轉方式和旋轉順序】

transform.Rotate (Vector3 eulers, Space relativeTo= Space.Self);

在Unity中旋轉物體時,我們通常會用到Rotate,官網文檔說的是繞固定軸按照ZXY順序旋轉。固定軸有兩個選項,世界空間的軸向,模型自身的軸向。這意味着:

代碼A       transform.Rotate(new Vector3(60, 45, 90),Space.Self);

代碼B        transform.Rotate(new Vector3(0, 0, 90), Space.Self);

                 transform.Rotate(new Vector3(45, 0, 0), Space.Self);

                 transform.Rotate(new Vector3(0, 60, 0), Space.Self);

這兩者所得結果不同,在A中是按照目前模型的軸向先繞Z軸旋轉90°,再繞X軸旋轉45°,再繞Y軸旋轉60°。在B中,先按照目前模型的軸向旋轉90°,此時模型自身的軸向改變了;之後以改變了的軸向再旋轉,繞X軸旋轉45°,旋轉後,模型自身的軸向又改變了;最後,繞又改變的軸向繞Y軸旋轉60°。

代碼C:   transform.Rotate(new Vector3(60, 45, 90),Space.World);

代碼D:   transform.Rotate(new Vector3(0, 0, 90), Space.World);

                transform.Rotate(new Vector3(45, 0, 0), Space.World);

                transform.Rotate(new Vector3(0, 60, 0), Space.World);

這兩種所得結果相同,因為每次都是按照世界空間的軸向來旋轉。(注:D中的順序不能改變,否則得到的結果也不一樣,因為順序改變了相當于你改變了旋轉順序,雖然Unity在執行每個Rotate時都按照ZXY的順序來執行的。)

【面闆中的Rotation】

對Unity中的歐拉角的了解

我們都知道面闆這裡的Rotaton表示歐拉角,X的值表示繞X旋轉多少度,Y的值表示繞Y旋轉多少度,Z的值表示繞Z旋轉多少度。在這個面闆中,對于(60,45,90)這個歐拉角來說,無論你按照XYZ、ZXY、ZYX等任何順序輸入,你會看到模型的結果都是一樣的。為什麼會這樣?上文不是說不同的旋轉順序會導緻不同的結果嗎?

這是因為Unity内部,對于目前面闆上的歐拉角,其都是先從(0,0,0)開始按照ZXY的順序旋轉(計算)得到的。也就相當于模型初始的歐拉角的(0,0,0),然後執行了  transform.Rotate(new Vector3(60, 45, 90),Space.Self)。

(如果模型在(0,0,0)時的坐标系與世界坐标系相同,那麼按照Space.Self和Space.World旋轉的結果是一樣的。否則會出現差别,是以在做模型時要求模型坐标系與Unity世界坐标系相同。)

當你按照XYZ順序輸入的時候,你隻能一個個地輸入。先輸入X,此時面闆上為(60,0,0),Unity按照ZXY的順序從(0,0,0)開始計算得到一個結果。然後輸入Y,此時面闆上為(60,45,0),Unity按照ZXY的順序從(0,0,0)開始計算得到一個結果,而不是從(60,0,0)開始計算。然後輸入Z····

是以,到這裡你就可以了解為什麼輸入順序不同最後結果都一樣了吧。

這是你輸入的情況,當你左右滑動連續改變X、Y、Z的值的時候,實際上也都是從(0,0,0)開始計算得到的結果的。因為算得足夠快,是以你在場景中看到模型也是連續旋轉的。

也許多數時候,你滑動X或Y或Z的值,模型确實是在自身坐标系下繞X(或Y或Z)的情況來旋轉的,但有時候就不是這樣。

例如,先設定Local

對Unity中的歐拉角的了解

,確定模型的Rotation在(0,0,0)時模型坐标系與世界坐标系一緻。之後将Rotation設定為(0,0,90)。此時,你再滑動X,你會看到模型不是繞X軸旋轉的;你滑動Y,你會看到模型不是繞Y軸旋轉的。

這是為什麼呢?為什麼模型沒有按照你想象的方式旋轉呢?

因為模型的Rotation是從(0,0,0)開始計算的,因為算得足夠快,是以在人眼看來模型就是跟着你滑動的X或Y或Z連續變化的。

這會導緻萬向鎖的問題。

【歐拉角的萬向鎖】

實際上無論是繞固定軸還是繞旋轉之後的軸旋轉,無論你怎麼旋轉,都不會導緻萬向鎖的問題。是以,你不用奇怪,你感覺無論怎麼旋轉都不會導緻萬向鎖是正确的。

你之是以會觀察到萬向鎖的現象是由于Unity計算歐拉角和人習慣計算歐拉角的方式不同所導緻的。模型目前的歐拉角為(60,45,0),要變為(60,45,90)時。Unity會從(0,0,0)變到(60,45,90);而人從(60,45,0)變到(60,45,90)。兩者的計算方式不同,而你在Unity中看見的結果是按照Unity自身的方式計算得到的,不是按照你想向的方式計算得到的,是以你會看見讓你難以了解的萬向鎖的問題。

下圖展示了萬向鎖的問題,你會發現無論怎樣滑動Y、Z,鲨魚始終是在世界坐标系的XZ平面。按照人的計算方式,滑動Y時鲨魚的尾巴應該會朝上的,但沒有。

對Unity中的歐拉角的了解

由于Unity是按照固定軸按照ZXY的順序來旋轉的,是以按照Unity的計算方式,總是最後再繞Y軸旋轉。是以,當你滑動Y,連續改變歐拉角時,看來像是再繞着世界坐标系的Y軸旋轉,而不是繞模型的Y軸來旋轉。是以你在Unity中,無論XZ的值時怎樣的,隻要你滑動Y,Unity計算歐拉角的方式給你呈現的視覺效果就是像圍繞世界坐标系的Y軸來旋轉一樣。

而當你滑動Z時,由于Unity總是先旋轉繞Z軸旋轉的,是以給你呈現的視覺效果是滑動Z時在場景中看到模型真的在繞模型的Z軸旋轉。而有時你滑動X呢,你會發現模型既不繞世界坐标系的X軸旋轉,也不繞模型坐标系的X軸旋轉。

因而,當模型的X為90時,使得模型坐标系的Z軸和世界坐标系的Y軸在同一條線上,是以你無論怎樣滑動Y都看不到鲨魚尾巴立起來的視覺效果。

那麼為什麼計算歐拉角時都要從(0,0,0)開始算呢?這個問題還沒有搞明白,以後在補充。

【參考】

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