四元數特性與定義
來源- 四元數由一實數與三虛數組成 : 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是對角矩陣。
- 定義:
- [酉矩陣(Unitary Matrix):是一個複數矩陣,其列(或行)構成複數空間 ( Cn ) 的正交基。酉矩陣 ( U ) 滿足 ( U∗U=UU∗=I),其中 ( U^* ) 是 ( U ) 的共軛轉置矩陣。
- [正交矩陣(Orthogonal Matrix):是一個實數矩陣,其列(或行)構成實數空間 ( Rn ) 的正交基。正交矩陣 ( P ) 滿足 ( P^TP=PP^T=I ),其中 ( P^T ) 是 ( P ) 的轉置矩陣。
- 元素:
- 酉矩陣的元素可以是複數。
- 正交矩陣的元素只能是實數。
- 性質:
- 酉矩陣的逆矩陣等於其共軛轉置矩陣,即 ( 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(....); |