1. 程式人生 > >OpenGL ES 從零開始系列9:動畫基礎和關鍵幀動畫

OpenGL ES 從零開始系列9:動畫基礎和關鍵幀動畫

Creating a Rotation Matrix from a Quaternion 從一個四元數中建立旋轉矩陣
這另外的一個方法相對簡單些。並且這個基本演算法來自於Matrix FAQ,雖然我需要把它轉換成行優先的順序。
static inline void Matrix3DSetUsingQuaternion3D(Matrix3D matrix, Quaternion3D quat)
{
   matrix[0]  = (1.0f - (2.0f * ((quat.y * quat.y) + (quat.z * quat.z))));
   matrix[1]  = (2.0f * ((quat.x * quat.y) - (quat.z * quat.w)));
   matrix[2]  = (2.0f * ((quat.x * quat.z) + (quat.y * quat.w)));
   matrix[3] = 0.0f;
   matrix[4]  = (2.0f * ((quat.x * quat.y) + (quat.z * quat.w)));
   matrix[5]  = (1.0f - (2.0f * ((quat.x * quat.x) + (quat.z * quat.z))));
   matrix[6]  = (2.0f * ((quat.y * quat.z) - (quat.x * quat.w)));
   matrix[7] = 0.0f;
   matrix[8]  = (2.0f * ((quat.x * quat.z) - (quat.y * quat.w)));
   matrix[9]  = (2.0f * ((quat.y * quat.z) + (quat.x * quat.w)));
   matrix[10] = (1.0f - (2.0f * ((quat.x * quat.x) + (quat.y * quat.y))));
   matrix[11] = 0.0f;
   matrix[12]  = 0.0f;
   matrix[13]  = 0.0f;
   matrix[14] = 0.0f;
   matrix[15] = 1.0f;
}

Converting an Angle and Axis of Rotation to a Quaternion 把一個角度和旋轉軸轉換成一個四元數

四元數可以做的另外一種轉換是,表示成在一個Vector3D表示的軸線上進行旋轉。這在骨骼動畫裡面是非常有用的,因為這種表現形式通過矩陣是很難做到的。建立一個基於角度和軸旋轉得四元數,我們可以這樣做:
static inline Quaternion3D Quaternion3DMakeWithAxisAndAngle(Vector3D axis, GLfloat angle)
{
   Quaternion3D quat;
   GLfloat sinAngle;
  
   angle *= 0.5f;
    Vector3DNormalize(&axis);
   sinAngle = sinf(angle);
   quat.x = (axis.x * sinAngle);
   quat.y = (axis.y * sinAngle);
   quat.z = (axis.z * sinAngle);
   quat.w = cos(angle);
  
   return quat;
}

Extracting an Angle and Axis of Rotation from a Quaternion 從一個四元數中檢測角度和軸得旋轉

反過來,我們也可以從四元數中取得旋轉的資料,包括旋轉角度和深度,就像這樣
static inline void Quaternion3DExtractAxisAndAngle(Quaternion3D quat, Vector3D *axis, GLfloat *angle)
{
   GLfloat s;
    Quaternion3DNormalize(&quat);
   s = sqrtf(1.0f - (quat.w * quat.w));
 
   if (fabs(s) < 0.0005f) s = 1.0f;
  
   if (axis != NULL)
   {
       axis->x = (quat.x / s);
       axis->y = (quat.y / s);
       axis->z = (quat.z / s);
   }
  
   if (angle != NULL)
       *angle = (acosf(quat.w) * 2.0f);
}

Quaternion Multiplication 四元數乘法

為了合併兩種不同形式的四元數中得3D旋轉資訊。我們只需要讓他們彼此相乘。好了繼續我們得程式碼
static inline void Quaternion3DMultiply(Quaternion3D *quat1, Quaternion3D *quat2)
{
   Vector3D v1, v2, cp;
   float angle;
  
   v1.x = quat1->x;
   v1.y = quat1->y;
   v1.z = quat1->z;
   v2.x = quat2->x;
   v2.y = quat2->y;
   v2.z = quat2->z;
   angle = (quat1->w * quat2->w) - Vector3DDotProduct(v1, v2);
  
   cp = Vector3DCrossProduct(v1, v2);
   v1.x *= quat2->w;
   v1.y *= quat2->w;
   v1.z *= quat2->w;
   v2.x *= quat1->w;
   v2.y *= quat1->w;
   v2.z *= quat1->w;
  
   quat1->x = v1.x + v2.x + cp.x;
   quat1->y = v1.y + v2.y + cp.y;
   quat1->z = v1.z + v2.z + cp.z;
   quat1->w = angle;
}

Inverting a Quaternion 四元數轉置
我們通過做一個四元數的共軛運算來取得四元數的轉置。四元數做共軛運算其實就是將四元數中表示向量(x,y,z)的值取反。在這裡的實現中,我們把它[四元數轉置計算]作為四元數標準計算的一部分,而不是一個獨立的步驟:
static inline void Quaternion3DInvert(Quaternion3D  *quat)
{
   GLfloat length = 1.0f / ((quat->x * quat->x) +
                    (quat->y * quat->y) +
                    (quat->z * quat->z) +
                    (quat->w * quat->w));
   quat->x *= -length;
   quat->y *= -length;
   quat->z *= -length;
   quat->w *= length;
}

Creating a Quaternion from Euler Angles 從尤拉角中建立四元數
前面我說過在旋轉中最好不要使用尤拉角,但是有時候我們需要將尤拉角轉換成四元數,比如說使用者輸入的資訊是尤拉角資訊。轉換的步驟是,將尤拉軸用Vector3D表示出來,然後將Vector3D的值轉換成四元數,最後將四元數相乘來得到結果:
static inline Quaternion3D Quaternion3DMakeWithEulerAngles(GLfloat x, GLfloat y, GLfloat z)
{
   Vector3D vx = Vector3DMake(1.f, 0.f, 0.f);
   Vector3D vy = Vector3DMake(0.f, 1.f, 0.f);
   Vector3D vz = Vector3DMake(0.f, 0.f, 1.f);
  
   Quaternion3D qx = Quaternion3DMakeWithAxisAndAngle(vx, x);
   Quaternion3D qy = Quaternion3DMakeWithAxisAndAngle(vy, y);
   Quaternion3D qz = Quaternion3DMakeWithAxisAndAngle(vz, z);


    Quaternion3DMultiply(&qx, &qy );
    Quaternion3DMultiply(&qx, &qz );
   return qx;
}