動畫技術-主要畫面格(keyFrame)
主要畫面格是一種常用的動畫技術,其基本原理是將動畫序列中比較關鍵的幀提取出來,而其他幀根據時間用這些主要畫面格插值計算得到。
一個簡單的主要畫面格結構:
typedef struct sKeyframe {
DWORD Time ;
D3DMATRIX matTransformation ;
}sKeyframe
這是一個非常簡化的結構,只包含時間和矩陣。但從這個結構可以看出keyFrame技術最根本的含義。假設我們要建立一個正方形旋轉並移動的動畫。
,這個正方形在3個位置間旋轉著移動。我們需要定義4個主要畫面格,每個主要畫面格都通過矩陣設定正方形相對於初始位置的偏轉和位移。
sKeyframe Keyframes[4] = {
{ 0, 1.00000f, 0.00000f, 0.00000f, 0.00000f,
0.00000f, 1.00000f, 0.00000f, 0.00000f,
0.00000f, 0.00000f, 1.00000f, 0.00000f,
0.00000f, 0.00000f, 0.00000f, 1.00000f; },
{ 400, 0.000796f, 1.00000f, 0.00000f, 0.00000f,
-1.00000f, 0.000796f, 0.00000f, 0.00000f,
0.00000f, 0.00000f, 1.00000f, 0.00000f,
50.00000f, 0.00000f, 0.00000f, 1.00000f; },
{ 800, -0.99999f, 0.001593f, 0.00000f, 0.00000f,
-0.001593f, -0.99999f, 0.00000f, 0.00000f,
0.00000f, 0.00000f, 1.00000f, 0.00000f,
25.00000f, 25.00000f, 0.00000f, 1.00000f; },
{ 1200, 1.00000f, 0.00000f, 0.00000f, 0.00000f,
0.00000f, 1.00000f, 0.00000f, 0.00000f,
0.00000f, 0.00000f, 1.00000f, 0.00000f,
0.00000f, 0.00000f, 0.00000f, 1.00000f; }
};
keyFrame4雖然與keyFrame1動畫完全一樣,但時間不同,所以要定義keyFrame4。
更新動畫時首先要根據動畫已經播放的時間計算出當前幀處於哪兩個主要畫面格之間。
DWORD Keyframe = 0; // Start at 1st keyframe
for(DWORD i=0;i<4;i++) {
// If time is greater or equal to a
// key-frame's time then update the
// keyframe to use
if(Time >= Keyframes[i].Time)
Keyframe = i;
}
如果目前時間>=某個主要畫面格設定的時間,那麼該主要畫面格就是當前幀的前一個主要畫面格。而下一幀就是後一個主要畫面格。如果前一個主要畫面格已經是最後一個主要畫面格,那麼後一個主要畫面格也使用該幀。
DWORD keyframe2 = (Keyframe==LAST_KEYFRAME_ID)?Keyframe:Keyframe+1 ;
計算出兩個主要畫面格後,根據目前時間和兩個主要畫面格的時間進行插值計算,得到當前幀。
DWORD TimeDiff = Keyframes[Keyframe2].Time -
Keyframes[Keyframe].Time;
// Make sure there's a time difference to
// avoid divide-by-zero errors later on.
if(!TimeDiff)
TimeDiff=1;
float Scalar = (Time - Keyframes[Keyframe].Time)/TimeDiff;
// Calculate the difference in transformations
D3DXMATRIX matInt = /
D3DXMATRIX(Keyframes[Keyframe2].matTransformation) - /
D3DXMATRIX(Keyframes[Keyframe].matTransformation);
matInt *= Scalar; // Scale the difference
// Add scaled transformation matrix back to 1st keyframe matrix
matInt += D3DXMATRIX(Keyframes[Keyframe].matTransformation);
matInt就是計算出的當前幀的轉換矩陣,用這個矩陣可以得到當前幀動畫的位置。
這個例子是一個最簡單的主要畫面格動畫,因為這個動畫的Frame只包含一個正方型而以,也就是說該動畫每一幀的Mesh是一樣的。在稍微複雜些的情況中,比如一個人走動的動畫。可以選取幾個動作作為主要畫面格,如果使用簡單的動畫,每個主要畫面格要記錄一套mesh資訊;如果使用骨骼動畫,每個主要畫面格要記錄骨骼的變換。這些情況中,需要插值計算的內容就複雜多了。不過根據時間,插值計算出當前幀仍是基礎。
主要畫面格技術除了用於播放動畫,還可以用於物體的運動。特別是固定路線的物體運動。
雖然我們談到主要畫面格技術都是在3D動畫中,不過2D遊戲中也可以很好的使用。其實這個簡單的例子就可以看成是一個2D動畫主要畫面格的例子,只不過我們要使用2D轉換矩陣。
參考資料: <Advanced Animation with DirectX> Chapter2