# Quaternions 筆記 2024/11/02 ## 四元數特性與定義 [來源]( https://hackmd.io/@shengwen/rotation-matrix) - 四元數由一實數與三虛數組成 : $q=w+xi+yj+zk$ - 四元數虛數之間相互乘法不具有交換性: - $i^2=j^2=k^2=-1$ - $ij=k,\ ji=-k$ - $jk=i,\ kj=-i$ - $ki=j,\ ik=-j$ - 四元數逆運算等於共軛值 - $q* = w -xi -yi-zk$ - $q^{-1} = q^* \space if|q|=1$ - 四元數乘法並不具備交換性,改變順序將會導致結果改變。 ### 補充 酉矩陣(unitary matrix): 逆矩陣=共軛矩陣 - 對於單位矩陣(即模長為1的矩陣),其逆矩陣等於其共軛轉置矩陣。這類矩陣稱為酉矩陣(unitary matrix) - 酉矩陣是可對角化的,即 $U=VDV$,其中V是酉矩陣、D是對角矩陣。 - 酉矩陣和正交矩陣之間有一些重要的區別和相似之處: 1. **定義**: - [**酉矩陣**(Unitary Matrix):是一個複數矩陣,其列(或行)構成複數空間 ( $\mathbb{C}^n$ ) 的正交基。酉矩陣 ( U ) 滿足 ( $U^*U = UU^* = I$),其中 ( U^* ) 是 ( U ) 的共軛轉置矩陣。 - [**正交矩陣**(Orthogonal Matrix):是一個實數矩陣,其列(或行)構成實數空間 ( $\mathbb{R}^n$ ) 的正交基。正交矩陣 ( P ) 滿足 ( $P^T P = PP^T = I$ ),其中 ( $P^T$ ) 是 ( $P$ ) 的轉置矩陣。 2. **元素**: - 酉矩陣的元素可以是複數。 - 正交矩陣的元素只能是實數。 3. **性質**: - 酉矩陣的逆矩陣等於其共軛轉置矩陣,即 ( $U^{-1} = U^*$ )。 - 正交矩陣的逆矩陣等於其轉置矩陣,即 ( $P^{-1} = P^T$ )。 總結來說,酉矩陣可以看作是複數空間中的正交矩陣,而正交矩陣是實數空間中的特例。 ### 使用範例 ![image](https://hackmd.io/_uploads/BJlNXcQ-ke.png) ![image](https://hackmd.io/_uploads/rJFVmcQbJg.png) - 虛數部分 i,j,k為想要旋轉的軸 - 實數部分用來控制旋轉角度大小。 - 旋轉公式: $q\cdot p \cdot q^{-1}$,實際旋轉角度要/2,因為使用q旋轉時會造成位移,需要 $q^{-1}$抵銷位移,而它本身也會旋轉。 ### 程式範例 [來源](https://www.songho.ca/opengl/gl_camera.html) #### 四元數 = (s, vec3) ```cpp 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 ```cpp // 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 } ``` #### 算共軛 ```cpp 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; } ``` #### 換算旋轉矩陣 ```cpp 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 } ``` #### 使用範例 ```cpp glPushMatrix(); // tramsform camera (取代lookAt function) Matrix4 mat = quat.getMatrix(); // view matrix --> Camera的視角旋轉 mat.translate(0, 0, -cameraDistance); //---->位移camera glMultMatrixf(mat.get()); draw(....); ``` --- ### 參考 1. https://hackmd.io/@shengwen/rotation-matrix 2. https://youtu.be/zjMuIxRvygQ 3. https://eater.net/quaternions/video/intro ### 其他讀物 1. https://krasjet.github.io/quaternion/quaternion.pdf from https://github.com/Krasjet/quaternion