维爱迪-动画创作家园 >> 动画理论 >> 3D游戏角色动画 |
二 3D游戏动画基础------基于时间的运动
在一个游戏项目中,计时扮演了一个重要的角色。基于时间的运动,也就是创建计时器来控制运动。它能够产生这样一种动画效果:同样处理10000毫秒的动画,在性能好的计算机上得到平滑完整的动画效果,在性能不好的计算机上显得跳帧,但也能够在10000毫秒的时候完成任务,和性能好的计算机是同步的。
基本思路是事先设置好动画关键帧序列,在主循环中判断出第一个动画关键帧和下一个动画关键帧的编号,利用一个时间计数器去定位相对于第一动画关键帧的位置。随着时间计数器的增长,不断从第一个动画关键帧的位置移动至下一个动画关键帧的位置。主要分为以下几个步骤:
1设置动画关键帧序列。
2计算出每一帧的时间Time,Time是相对于程序开始运行的毫秒数。
3定位出第一个动画关键帧和下一个动画关键帧。
4利用Time计算出相对于第一个动画关键帧的毫秒数,再利用这个偏移毫秒数计算出相对于第一个动画帧的偏移位置。
5设置变换矩阵。
6回到第2步。
上图表示了4帧的关键帧动画,其中第0帧和第3帧变换矩阵相同。下面直接看代码,我将结合代码详细叙述。
typedef struct sKeyframe
{
DWORD Time;
D3DMATRIX matTransformation;
} sKeyframe;//关键帧的结构,DWORD Time为执行该帧的时间,D3DMATRIX //matTransformation为在该帧时模型的变换矩阵。
sKeyframe g_Keyframes[4] =
{
// Keyframe 0, 0ms
{ 0, 1.000000f, 0.000000f, 0.000000f, 0.000000f,
0.000000f, 1.000000f, 0.000000f, 0.000000f,
0.000000f, 0.000000f, 1.000000f, 0.000000f,
0.000000f, 0.000000f, 0.000000f, 1.000000f },
// Keyframe 1, 40ms
{ 400, 0.000796f, 1.000000f, 0.000000f, 0.000000f,
-1.000000f, 0.000796f, 0.000000f, 0.000000f,
0.000000f, 0.000000f, 1.000000f, 0.000000f,
50.000000f, 0.000000f, 0.000000f, 1.000000f },
// Keyframe 2, 80ms
{ 800, -0.999999f, 0.001593f, 0.000000f, 0.000000f,
-0.001593f, -0.999999f, 0.000000f, 0.000000f,
0.000000f, 0.000000f, 1.000000f, 0.000000f,
25.000000f, 25.000000f, 0.000000f, 1.000000f },
// Keyframe 3, 120ms
{ 1200, 1.000000f, 0.000000f, 0.000000f, 0.000000f,
0.000000f, 1.000000f, 0.000000f, 0.000000f,
0.000000f, 0.000000f, 1.000000f, 0.000000f,
0.000000f, 0.000000f, 0.000000f, 1.000000f }
};//定义了4帧的关键动画。其中第3帧和第0帧的变换矩阵一样,为了使动画能进入循环状态。
void DoFrame() //此函数在循环内
{
static DWORD StartTime = timeGetTime();
DWORD Time = timeGetTime() - StartTime;
//用timeGetTime()得到一个操作系统运行的毫秒数,储存到static变量以后将不再改变,//DWORD Time变量不断改变,为本程序运行的毫秒数。
Time %= (g_Keyframes[3].Time+1);//得到一个不断从0到1200变化的毫秒数。
DWORD Keyframe = 0; // 从第0帧开始。
for(DWORD i=0;i<4;i++) {
// 如果Time>= 某一关键帧的时间,将关键帧定位于此帧。
if(Time >= g_Keyframes[i].Time)
Keyframe = i;
}
DWORD Keyframe2 = (Keyframe==3) ? Keyframe:Keyframe + 1;//得到接下来的关键帧,如//果Keyframe为第3关键动画帧,Keyframe2也为第3关键动画帧。
//当Keyframe=1200时这种情况才成立,几率很小。一般情况下,Keyframe2=Keyframe+1。
DWORD TimeDiff = g_Keyframes[Keyframe2].Time -
g_Keyframes[Keyframe].Time;
if(!TimeDiff)
TimeDiff=1;//计算两个sKeyframe的时间差,当Keyframe=Keyframe2=3时,TimeDiff=0,//此时另TimeDiff=1。
float Scalar = (float)(Time - g_Keyframes[Keyframe].Time) / (float)TimeDiff; // Scalar取 //值为[0,1),利用Time计算出相对于Keyframe的偏移毫秒数,再除以两//帧的时间差。
D3DXMATRIX matInt = D3DXMATRIX(g_Keyframes[Keyframe2].matTransformation) -
D3DXMATRIX(g_Keyframes[Keyframe].matTransformation);
matInt *= Scalar; //用于计算相对于Keyfrme的偏移位置。
matInt += D3DXMATRIX(g_Keyframes[Keyframe].matTransformation); // 计算出该帧处相//对于Keyfrme的偏移位置。
g_pD3DDevice->SetTransform(D3DTS_WORLD, &matInt); // 设置 world transformation matrix
设置完变换矩阵,剩下的事情就只是渲染了。创建计时器控制动画的技术是非常简单有效的,这是现代计算机游戏动画的基础,因此,必须深刻理解它的内容。