前往
大廳
主題

讀書日記11/02:Quaternions 學習筆記

%%鼠 拒收病婿 | 2024-11-02 20:23:53 | 巴幣 3228 | 人氣 252

前言
上一篇講旋轉,這篇用四元數來取代Lookat函數的使用。

四元數特性與定義

來源
  • 四元數由一實數與三虛數組成 : q=w+xi+yj+zk
  • 四元數虛數之間相互乘法不具有交換性:
    • i2=j2=k2=−1
    • ij=k, ji=−k
    • jk=i, kj=−i
    • ki=j, ik=−j
  • 四元數逆運算等於共軛值
    • q∗=w−xi−yi−zk
    • q−1=q∗ if|q|=1
  • 四元數乘法並不具備交換性,改變順序將會導致結果改變。

補充 酉矩陣(unitary matrix): 逆矩陣=共軛矩陣

  • 對於單位矩陣(即模長為1的矩陣),其逆矩陣等於其共軛轉置矩陣。這類矩陣稱為酉矩陣(unitary matrix)
  • 酉矩陣是可對角化的,即 U=VDV,其中V是酉矩陣、D是對角矩陣。
酉矩陣和正交矩陣之間有一些重要的區別和相似之處:

  1. 定義
    • [酉矩陣(Unitary Matrix):是一個複數矩陣,其列(或行)構成複數空間 ( Cn ) 的正交基。酉矩陣 ( U ) 滿足 ( U∗U=UU∗=I),其中 ( U^* ) 是 ( U ) 的共軛轉置矩陣。
    • [正交矩陣(Orthogonal Matrix):是一個實數矩陣,其列(或行)構成實數空間 ( Rn ) 的正交基。正交矩陣 ( P ) 滿足 ( P^TP=PP^T=I ),其中 ( P^T ) 是 ( P ) 的轉置矩陣。
  2. 元素
    • 酉矩陣的元素可以是複數。
    • 正交矩陣的元素只能是實數。
  3. 性質
    • 酉矩陣的逆矩陣等於其共軛轉置矩陣,即 ( U^−1=U∗ )。
    • 正交矩陣的逆矩陣等於其轉置矩陣,即 ( P^−1=P^T )。
      總結來說,酉矩陣可以看作是複數空間中的正交矩陣,而正交矩陣是實數空間中的特例。

使用範例



  • 虛數部分 i,j,k為想要旋轉的軸
  • 實數部分用來控制旋轉角度大小。
  • 旋轉公式: q⋅p⋅q^−1,實際旋轉角度要/2,因為使用q旋轉時會造成位移,需要 q^−1抵銷位移,而它本身也會旋轉。

程式範例

四元數 = (s, vec3)

inline void Quaternion::set(const Vector3& axis, float angle)
{
    // use only half angle because of double multiplication, qpq*,
    // q at the front and its conjugate at the back
    Vector3 v = axis;
    v.normalize();                  // convert to unit vector
    float sine = sinf(angle);       // angle is radian
    s = cosf(angle);
    x = v.x * sine;
    y = v.y * sine;
    z = v.z * sine;
}

給2個vector,得到旋轉的q

// find quaternion for rotating from v1 to v2
inline Quaternion Quaternion::getQuaternion(const Vector3& v1, const Vector3& v2)
{
    const float EPSILON = 0.001f;
    const float HALF_PI = acos(-1) * 0.5f;

    Vector3 u1 = v1;                    // convert to normal vector
    Vector3 u2 = v2;
    u1.normalize();
    u2.normalize();

    Vector3 v = u1.cross(u2);           // compute rotation axis
    float angle = acosf(u1.dot(u2));    // rotation angle
    return Quaternion(v, angle * 0.5f); // half angle
}


算共軛

inline Quaternion& Quaternion::conjugate()
{
    x = -x;  y = -y;  z = -z;
    return *this;
}

inline Quaternion& Quaternion::invert()
{
    const float EPSILON = 0.00001f;
    float d = s*s + x*x + y*y + z*z;
    if(d < EPSILON)
        return *this; // do nothing if it is zero

    Quaternion q = *this;
    *this = q.conjugate() * (1.0f / d); // q* / |q||q|
    return *this;
}

換算旋轉矩陣

inline Matrix4 Quaternion::getMatrix() const
{
    // NOTE: assume the quaternion is unit length
    // compute common values
    float x2  = x + x;
    float y2  = y + y;
    float z2  = z + z;
    float xx2 = x * x2;
    float xy2 = x * y2;
    float xz2 = x * z2;
    float yy2 = y * y2;
    float yz2 = y * z2;
    float zz2 = z * z2;
    float sx2 = s * x2;
    float sy2 = s * y2;
    float sz2 = s * z2;

    // build 4x4 matrix (column-major) and return
    return Matrix4(1 - (yy2 + zz2),  xy2 + sz2,        xz2 - sy2,        0, // column 0
                   xy2 - sz2,        1 - (xx2 + zz2),  yz2 + sx2,        0, // column 1
                   xz2 + sy2,        yz2 - sx2,        1 - (xx2 + yy2),  0, // column 2
                   0,                0,                0,                1);// column 3

    // for non-unit quaternion
    // ss+xx-yy-zz, 2xy+2sz,     2xz-2sy,     0
    // 2xy-2sz,     ss-xx+yy-zz, 2yz-2sx,     0
    // 2xz+2sy,     2yz+2sx,     ss-xx-yy+zz, 0
    // 0,           0,           0,           1
}

使用範例

glPushMatrix();

// tramsform camera  (取代lookAt function)
Matrix4 mat = quat.getMatrix(); // view matrix  --> Camera的視角旋轉
mat.translate(0, 0, -cameraDistance); //---->位移camera
glMultMatrixf(mat.get());

draw(....);


參考
其他讀物

送禮物贊助創作者 !
0
留言

1則留言

2024-11-02 23:18:12
這東西我從開始就沒懂過,原來還跟虛數有關嗎 🤔🤔
2024-11-03 01:02:00
直覺上是3個假想軸,為什麼是虛數可能要看他推導

相關創作

更多創作