/*
 * convert a rotation matrix to quaternion
 * 
 * Quat class member variables:
 * float w; //angle of displacement: cos(theta/2)
 * float x; // x-axis of rotation: sin(theta/2)nx
 * float y; // y-axis of rotation: sin(theta/2)ny
 * float z; // z-axis of rotation: sin(theta/2)nz
 *
 * Mat4 class member variables:
 * float elem[16];
 *
 */
Quat Mat2Quat(const Mat4& m)
{
    // matrix to quaternion conversion as defined in
    //Dunn/Parberry's "3D Math Primer for Graphics and Game Development"
    //p. 284 - 287
    
    Quat m2q;
    float absVal[4];
    float m11 = m.elem[0];
    float m12 = m.elem[1];
    float m13 = m.elem[2];
    float m21 = m.elem[4];
    float m22 = m.elem[5];
    float m23 = m.elem[6];
    float m31 = m.elem[8];
    float m32 = m.elem[9];
    float m33 = m.elem[10];
    
    //determine which component has the largest absolute value
    absVal[0] = m11 + m22 + m33; //W component
    absVal[1] = m11 - m22 - m33;
    absVal[2] = m22 - m11 - m33;
    absVal[3] = m33 - m11 - m22;
    
    int idx = 0; //index of component with the largest value
    float bigVal = absVal[0]; //holds the largest value
    for (int i = 1; i < 4; i++)
    {
        if (absVal[i] > bigVal)
        {
            bigVal = absVal[i];
            idx = i;
        }
    }
    
    //perform square root and division to extract the
    //quaternion value from the matrix
    bigVal = sqrtf(bigVal + 1.0f) * 0.5f;
    float div = 0.25f / bigVal;
    
    //apply the table to calculate the quaternion
    switch (idx)
    {
    case 0:    //W component is largest
        m2q.w = bigVal;
        m2q.x = (m23 - m32) * div;
        m2q.y = (m31 - m13) * div;
        m2q.z = (m12 - m21) * div;
        break;
    case 1:    //X component is largest
        m2q.w = (m23 - m32) * div;
        m2q.x = bigVal;
        m2q.y = (m12 + m21) * div;
        m2q.z = (m31 + m13) * div;
        break;
    case 2:    //Y component is largest
        m2q.w = (m31 - m13) * div;
        m2q.x = (m12 + m21) * div;
        m2q.y = bigVal;
        m2q.z = (m23 + m32) * div;
        break;
    case 3:    //Z component is largest
        m2q.w = (m12 - m21) * div;
        m2q.x = (m31 + m13) * div;
        m2q.y = (m23 + m32) * div;
        m2q.z = bigVal;
        break;
    }
    return m2q;
}

[go to home page]