歐拉角與旋轉

歐拉角是一種常用的描述方位的方法。這項技術是著名數學家Leonhard Euler(1707~1783)的名字命名的,他證明了角位移序列等價於單個角位移。想詳細瞭解的請點擊維基百科:http://zh.wikipedia.org/wiki/%E6%AC%A7%E6%8B%89%E8%A7%92#.E5.88.A5.E7.A8.AE.E9.A0.86.E5.BA.8F

1,什麼是歐拉角

      歐拉角的基本思想是將角位移分解爲繞三個互相垂直軸的三個旋轉組成的序列。這聽起來複雜,其實它是非常直觀的。之所以有“角位移”的說法正是因爲歐拉角能用來描述任意旋轉,但最有意義的是使用笛卡爾座標系並按照一定順序所組成的旋轉序列。最常用的約定,即所謂“heading-pitch-bank”約定。在這個系統中,一個方位被定義爲一個heading角,一個pitch角,和一個bank角。它的基本思想就是讓物體開始於“標準”方位——就是物體座標軸和慣性座標軸對齊。在標準方位上,讓物體作heading,pitch,bank旋轉,最後物體到達我們想要描述的方位。

     在精確定義術語“heading”“pitch”“bank”前,先讓我們簡要回顧本書中使用的座標空間約定。我們使用左手座標系,+x向右,+y向上,+z向前。

     heading爲繞y軸的旋轉量,向右旋轉爲正,旋轉正方向是順時針方向,經過heading旋轉之後,pitch爲繞x軸的旋轉量,注意是物體座標系的x軸,不是原慣性座標系的x軸,依然遵守左手法則,向下旋轉爲正。最後,經過了heading,pitch後,bank爲繞z軸的旋轉量,依然是物體座標系的z軸。

     當我們說到旋轉的順序是heading-pitch-bank時,是指從慣性座標系到物體座標系,如果從物體座標系到慣性座標系則相反。

2,關於歐拉角的其他約定

     前面曾提到過,heading-pitch-bank系統不是惟一的歐拉角系統,繞任意三個互相垂直軸的任意旋轉序列都能定義一個方位。所以,多種選擇導致了歐拉角約定的多樣性:

     1)heading-pitch-bank系統有兩個名稱,當然,不同的名字並不代表不同的約定,這其實並不重要,一組常用的術語是roll-pitch-yaw,其中的roll對應與bank,yaw對應於heading,它定義了從物體座標系到慣性座標系的旋轉順序

     2)任意三個軸都能作爲旋轉軸,不一定必須是笛卡爾軸,但是用笛卡爾軸最有意義

     3)也可以選用右手座標規則

     4)旋轉可以以不同的順序進行

3,優點:1)容易使用;2)表達簡潔;3)任意三個角都是合法的

4,缺點:1)給定方位的表達方式不唯一;2)兩個角度間求插值非常困難

採用限制歐拉角的方法來避免以上問題的出現:heading限制在+-180,pitch爲+-90。

    以上爲歐拉角的定義。旋轉的方法如下:

從歐拉角矢量轉換很容易,困難的部分是轉換回來。XNA提供了一個方法可以創建旋轉矩陣,但它並沒有提供轉換回來的方法,因此我們將不得不自己實現。

首先,我們轉換爲旋轉矩陣,Matrix.CreateFromYawPitchRoll()方法可以做到這一點。如果這裏使用歐拉角,我們需要以以下順序提供座標:

  • Yaw(偏航):歐拉角向量的y軸
  • Pitch(俯仰):歐拉角向量的x軸
  • Roll(翻滾): 歐拉角向量的z軸
想象一下飛機,yaw指水平方向的機頭指向,它繞y軸旋轉。Pitch指與水平方向的夾角,繞x軸旋轉。Roll指飛機的翻滾,繞z軸旋轉。下面的代碼演示了這一過程:

// Converts a rotation vector into a rotation matrix
Matrix Vector3ToMatrix(Vector3 Rotation)
{
    return Matrix.CreateFromYawPitchRoll(Rotation.Y, Rotation.X, Rotation.Z);
}

這種方法可以提供一個表示旋轉的矩陣。下面是最難的部分:將矩陣轉換爲歐拉角。

這個過程是將矩陣拆散:一個表示位置的Vecto3,另一個表示縮放,而四元數表示旋轉。然後,我們必須將這個四元數轉換爲一個歐拉角矢量。我不打算詳細討論代碼背後的數學原理,但如果你有興趣,可以到前面鏈接中的網址上去看看。

下面是將旋轉矩陣轉換爲歐拉角的代碼。

// Returns Euler angles that point from one point to another
Vector3 AngleTo(Vector3 from, Vector3 location)
{
    Vector3 angle = new Vector3(); 
    Vector3 v3 = Vector3.Normalize(location - from); 

    angle.X = (float)Math.Asin(v3.Y);
    angle.Y = (float)Math.Atan2((double)-v3.X, (double)-v3.Z);

    return angle;
}

// Converts a Quaternion to Euler angles (X = Yaw, Y = Pitch, Z = Roll)
Vector3 QuaternionToEulerAngleVector3(Quaternion rotation)
{
    Vector3 rotationaxes = new Vector3();
    Vector3 forward = Vector3.Transform(Vector3.Forward, rotation);
    Vector3 up = Vector3.Transform(Vector3.Up, rotation);

    rotationaxes = AngleTo(new Vector3(), forward);

    if (rotationaxes.X == MathHelper.PiOver2)
    {
        rotationaxes.Y = (float)Math.Atan2((double)up.X, (double)up.Z);
        rotationaxes.Z = 0;
    }
    else if (rotationaxes.X == -MathHelper.PiOver2)
    {
        rotationaxes.Y = (float)Math.Atan2((double)-up.X, (double)-up.Z);
        rotationaxes.Z = 0;
    }
    else
    {
        up = Vector3.Transform(up, Matrix.CreateRotationY(-rotationaxes.Y));
        up = Vector3.Transform(up, Matrix.CreateRotationX(-rotationaxes.X));

        rotationaxes.Z = (float)Math.Atan2((double)-up.Z, (double)up.Y);
    } 

    return rotationaxes;
}

// Converts a Rotation Matrix to a quaternion, then into a Vector3 containing
// Euler angles (X: Pitch, Y: Yaw, Z: Roll)
Vector3 MatrixToEulerAngleVector3(Matrix Rotation)
{
    Vector3 translation, scale;
    Quaternion rotation;

    Rotation.Decompose(out scale, out rotation, out translation);

    Vector3 eulerVec = QuaternionToEulerAngleVector3(rotation);

    return eulerVec;
}

同時,歐拉角的順序規定一共有12種,在轉化的時候一定要弄清楚規定是怎樣的。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章