天天看點

Unity複雜的旋轉-歐拉角和四元數

學了那麼久 其實對Unity的歐拉角和四元數并沒有很深刻的認識…是以就此開篇稍微介紹一下
  • 我們首先知道的是,在Unity中有兩種方式表示旋轉。一種是歐拉角,還有一種就是四元數,那其中的差別有哪些呢?我們先分别介紹一下。

一.歐拉角

歐拉角最容易表示,用三個變量X,Y,Z可以直覺的表示繞着某個軸的旋轉角度。

在Unity裡就是Transform元件的Rotation裡的X Y Z三個變量代表了歐拉角

Unity複雜的旋轉-歐拉角和四元數

二.四元數

四元數相比于歐拉角就比較複雜了,由四個變量組成(在Unity中稱為X,Y,Z,W),但是這些變量的值不代表旋轉角度,是以可能給你一個向量(0。7,0,0,0.7)你并不知道實際旋轉的角度,當然四元數的詳細解釋需要數學方面的深入研究,有興趣的可以自行查找有關資料

  • 因為在Unity沒有可視化界面可以調整四元數(因為真的調了也不直覺看到旋轉的角度),是以我們隻能用腳本來通路

三.腳本中内容

歐拉角如果在腳本中表示呢?

是不是想到之前圖中的那個Rotation,那你是不是自然而然的想到了通過transform.rotation通路呢?如果你是這樣想的,那就錯了!

在Unity中transform.rotation代表的是四元數!附上官網證明!

Unity複雜的旋轉-歐拉角和四元數

那到底如何表示歐拉角呢?其實表示很簡單,并附上官網解釋

transform.eulerAngles =new Vector3(20,300,40);
           
Unity複雜的旋轉-歐拉角和四元數

當我們以上述代碼運作後會發現Rotation中的Y值是-60,那是因為面闆上的Rotation中的X Y Z值範圍是在(-180,180),對于代碼中超出的部分會自動進行計算映射到範圍内

Unity複雜的旋轉-歐拉角和四元數

四元數的代碼表示就是之前的transform.rotation,那你肯定會想歐拉角和四元數之前能否轉換呢,知道其中一個的值,如果改變成對方呢?代碼如下

//歐拉角->四元數 
//通過Quaternion.Euler() 傳遞一個Vector3向量的歐拉角
transform.rotation = Quaternion.Euler(new Vector3(20, 300, 40));

//四元數->歐拉角
transform.rotation.eulerAngles;//對你沒看錯 直接可以轉換擷取
           

三.差別

歐拉角:
  • 優點:三個角度組成,直覺,容易了解
  • 優點:可以進行從一個方向到另一個方向旋轉大于180度的角度
  • 缺點:死鎖問題——萬向節死鎖 萬向節死鎖介紹
四元數
  • 優點:不存在萬向節死鎖問題
  • 優點:存儲空間小,計算效率高
  • 缺點:單個四元數不能表示在任何方向上超過180度的旋轉。
  • 缺點:數字表示不直覺

四.常用API

  • Quaternion.LookRotation() 使其轉向某個方向
    Unity複雜的旋轉-歐拉角和四元數
    函數傳遞的參數的一個Vector3的向量 這個向量表示的是要看向的向量,通常用目标的positon和自身的position進行相減求得此向量
Vector3 pos = target.transform.position - transform.position;
transform.rotation = Quaternion.LookRotation(pos);
           

是不是覺得和transform.LookAt()效果很像…

//和上面代碼得到的效果相同
transform.LookAt(target.transform);
           
  • Quaternion.Slerp() 平滑進行轉動動畫
    Unity複雜的旋轉-歐拉角和四元數

    函數傳遞的參數分别是 目前GameObject的四元數、目标要轉向的四元數 和 一個插值時間

    我們看個例子

void LookAtTarget()
    {
        if (Input.GetKey(KeyCode.Space))
        {
            Vector3 dir = target.transform.position - transform.position;
            dir.y = 0;//不讓Player有y軸上的傾角
            Quaternion target = Quaternion.LookRotation(dir);
            transform.rotation = Quaternion.Slerp(transform.rotation, target, Time.deltaTime);
        }
    }
           

我們将上述的LookAtTarget()方法放到Update()函數中進行執行

就可以看到平滑的轉動

Unity複雜的旋轉-歐拉角和四元數
  • Quaternion.Lerp() 說實話個人用起來和Slerp()差別不大
    Unity複雜的旋轉-歐拉角和四元數
    圖中紅線框出來的就是差別:使用Lerp()進行旋轉的速度較快,但是在旋轉角度較大的時候,效果會糟一點。
  • Quaternion.RotateTowards()
    Unity複雜的旋轉-歐拉角和四元數
    傳遞兩個四元數,和一個角度增量值,使第一個四元數逐漸趨近于第二個四元數并最終相等
void Update()
    {
        float step = 3 * Time.deltaTime;
        transform.rotation = Quaternion.RotateTowards(transform.rotation,target.transform.rotation,step);
    }
           

結果就是目前物體的四元數和目标的四元數相等

  • Transform.RotateAround()
    Unity複雜的旋轉-歐拉角和四元數
    傳遞一個參照點point、繞哪個軸轉axis和增量角度angle
void Update()
    {
        float step = 3 * Time.deltaTime;
        transform.RotateAround(target.transform.position,Vector3.up,step);
    }
           
Unity複雜的旋轉-歐拉角和四元數

五.總結

差不多基礎概念就這些了吧,如果要深入了解的話,建議還是看API,并且自己多動手嘗試一下資料~