发文章也慢了。3D果然比2D复杂些。
MD2是一系列“帧”组成的动画模型。读取模型的文件包括md2.h,md2.cpp。此外,纹理贴图也被封装成类class Texture,相关文件包括texture.h,texture.lib。md2.cpp代码量有900多行。没必要贴出来。为了读取和显示模型,作者封装了一个类class anmobj。
使用的相关函数:
md2_readModel 读取模型
md2_getAnimationCount 读取动作数量
md2_getAnimationFrames 读取指定动作的起始帧,结束帧
测试时没有正确显示贴图,类Texture没有源文件,也无法调试。我用下面这个函数指定贴图也可以。
void mytexture(UINT textur)
{
glBindTexture (GL_TEXTURE_2D, textur);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
再看class anmobj。重要的是md2模型的动画信息,即每个动作的动作名称,起始帧和结束帧。这个类封装了10个士兵的帧数据,坐标数据。条条大路通罗马,这些数据也可以放到其他地方。简化后的anmobj类,如下:
//动作
struct animation
{
char name[16]; //动作名称
int start; //动作起始帧
int end; //动作结束帧
};
//md2接口
class anmobj
{
public:
md2_model_t* model[2]; //两个MD2模型
animation* anim[2]; //各个模型的动画数据
int size[2]; //动作数量
//初始化模型
void getobj(CString na);
//读取模型的动画信息
animation* animations (md2_model_t* model,int p);
//绘制模型
//入参 ID 坐标 帧
void drawModel(int id,float x,float y,float z,int iframe);
};
void anmobj::getobj(CString na)//
{
anim[0]=anim[1]=NULL;
if(model[0]!=NULL)
{
delete[] model[0];
model[0]=NULL;
}
if(model[1]!=NULL)
{
delete[] model[1];
model[1]=NULL;
}
model[0] = md2_readModel(na+"tris.md2");
model[1] = md2_readModel(na+"weapon.md2");
if(model[0]!=NULL)
{
size[0] = md2_getAnimationCount(model[0]);
// 获取动作序列
animations (model[0],0);//
}
if(model[1]!=NULL)
{
size[1] = md2_getAnimationCount(model[1]);
animations (model[1],1);
}
}
animation* anmobj::animations (md2_model_t* model,int p)
{
if (size[p] == 0)
return 0;//
if(anim[p]!=NULL)
delete[] anim[p];//
anim[p] = new animation[size[p]];//
//设置该模型的所有动画信息
for (int i=0; i<size[p]; i++)//
{
//得到动画名称
strcpy (anim[p][i].name,md2_getAnimationName(model,i));//
//得到动画起始结束帧
md2_getAnimationFrames(model,i,&anim[p][i].start,&anim[p][i].end);//
}
return 0;//
}
//不包含贴图代码
void anmobj::drawModel(int id,float x,float y,float z,int iframe)
{
glPushAttrib(GL_CURRENT_BIT);
glPushMatrix();
glTranslatef(x,y,z);
//旋转
glRotatef(-180,0,1,0);
//缩小
glScaled(.06f,.06f,.06f);
//role
if(model[0]!=NULL && model[0]->header.numFrames>iframe)
{
md2_drawModel (model[0],iframe,0,0);
}
//weapon
if(model[1]!=NULL && model[1]->header.numFrames>iframe)
{
md2_drawModel (model[1],iframe,0,0);
}
glPopMatrix();
glPopAttrib();
}
以下是士兵模型的动画数据:
[动作名称 起始帧 结束帧]
stand : 0 , 39
run : 40 , 45
attak : 46 , 53
pain1 : 54 , 57
pain2 : 58 , 61
pain3 : 62 , 65
jump : 66 , 71
......
death1 : 178 , 183
death2 : 184 , 189
death3 : 190 , 197
这些数据可以通过打印anim[0]得到,也可以通过anim[1]看到武器模型的帧信息,如下:
stand : 0 , 39
run : 40 , 45
attak : 46 , 53
pain1 : 54 , 57
pain2 : 58 , 61
......
注意,武器只有173帧(0至172)。
感谢《学OPENGL编3D游戏》课件(来自www.gameres.com)