一.帧/帧时刻
2D屏幕采用扫描周期的方式定时刷新渲染管线,单位时间内刷新的帧数即为FPS,是衡量游戏质量的重要标准。通过定义帧,帧时刻实现连续性动画播放实现
FPS = FrameCount/FrameRenderTime
Direct3D提供API实现2D屏幕的重绘:
int frameCount = 0;
while(true){
long startTime = getTime();
D3DDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);//清理GPU渲染管线
d3dDevice->BeginScene();
D3DDevice->EndScene();
D3DDevice->Present(NULL, NULL, NULL, NULL); //写入GPU渲染管线
long endTime = getTime();
frameCount++;
}
FPS = frameCount/(endTime - startTime)
二.形变动画/顶点动画(MorphAnimation)
通过在3D资源文件中定义每一帧的静态模型数据(顶点,法向,材质),游戏引擎预加载3D资源文件读取每一帧的静态模型,使用Direct3D提供API更新GPU缓存实现动画即为顶点动画.
Direct3D提供动态更新静态模型顶点坐标API:
D3dDevice->SetStreamSource(0, model->vertexBuffer, 0, sizeof(Vertex));
D3dDevice->SetFVF(D3D_FVF_TEXTURE_VERTEX);
D3dDevice->SetIndices(model->indexBuffer);
D3dDevice->SetTexture(0, model->texture); //启用纹理
顶点动画 = obj1(time1) + obj2(time2) + obj3(time3)
故不同的游戏引擎导出的顶点动画最终是obj静态模型的组合.如常见M3D顶点动画3D文件,数据结构就是不同frame的静态模型组合MD3FileData.h:
// -------------------------------------------------------------------------------
/** @brief Data structure for the MD3 main header
*/
struct Header
{
//! magic number
uint32_t IDENT;
//! file format version
uint32_t VERSION;
//! original name in .pak archive
char NAME[ AI_MD3_MAXQPATH ];
//! unknown
int32_t FLAGS;
//! number of frames in the file
uint32_t NUM_FRAMES;
//! number of tags in the file
uint32_t NUM_TAGS;
//! number of surfaces in the file
uint32_t NUM_SURFACES;
//! number of skins in the file
uint32_t NUM_SKINS;
//! offset of the first frame
uint32_t OFS_FRAMES;
//! offset of the first tag
uint32_t OFS_TAGS;
//! offset of the first surface
uint32_t OFS_SURFACES;
//! end of file
uint32_t OFS_EOF;
} PACK_STRUCT;
// -------------------------------------------------------------------------------
/** @brief Data structure for the frame header
*/
struct Frame
{
//! minimum bounds
aiVector3D min;
//! maximum bounds
aiVector3D max;
//! local origin for this frame
aiVector3D origin;
//! radius of bounding sphere
ai_real radius;
//! name of frame
char name[ AI_MD3_MAXFRAME ];
} /* PACK_STRUCT */;
// -------------------------------------------------------------------------------
/** @brief Data structure for the surface header
*/
struct Surface {
//! magic number
int32_t IDENT;
//! original name of the surface
char NAME[ AI_MD3_MAXQPATH ];
//! unknown
int32_t FLAGS;
//! number of frames in the surface
uint32_t NUM_FRAMES;
//! number of shaders in the surface
uint32_t NUM_SHADER;
//! number of vertices in the surface
uint32_t NUM_VERTICES;
//! number of triangles in the surface
uint32_t NUM_TRIANGLES;
//! offset to the triangle data
uint32_t OFS_TRIANGLES;
//! offset to the shader data
uint32_t OFS_SHADERS;
//! offset to the texture coordinate data
uint32_t OFS_ST;
//! offset to the vertex/normal data
uint32_t OFS_XYZNORMAL;
//! offset to the end of the Surface object
int32_t OFS_END;
} /*PACK_STRUCT*/;
三.骨骼动画(SkelAnimation)
对于有规律性质的动画,如人物移动,人物飞行等,可通过动态运算计算每一帧的模型,大大减少了3D资源文件存储空间,即为骨骼动画。
骨骼动画 = (Base*BoneTransformMatrix1)(time1) + (BasMatrix*BoneTransformMatrix2)(time2)
<1.将人物等生物模型进行顶点组划分,定义骨架,骨骼等基本概念,完成绑骨操作。
<2.通过Blender编辑每个帧时刻的骨骼位置和旋转角度,得到骨骼相对于起始位置的旋转矩阵.
如常见的FBX,DAE文件存储骨骼动画采用将每一帧的变换矩阵进行封装存储,FBXDocument.h:
namespace FBX {
class AnimationCurve;
class AnimationCurveNode; //顶点组节点
class AnimationLayer;
class AnimationStack;
}
/** DOM class for skin deformer clusters (aka sub-deformers) */
class Cluster : public Deformer {
private:
WeightArray weights; //权重
WeightIndexArray indices;
aiMatrix4x4 transform; //每一帧对应的旋转矩阵
aiMatrix4x4 transformLink; //每一帧对应的旋转矩阵
const Model* node;
};