日志 教程
当前位置: 教程  >  游戏开发  >  网页游戏开发  >  正文

MD2关键帧动画

作者:任雪梅 发表于 2011/9/13 22:52:56     评论(0)     阅读(3851)     
本想用骨骼动画的,无奈.x格式的太过于复杂,而且游戏业里也不怎么用。
只是把它的原理弄明白一些了,但是,我弱小的意志在DirectX SDK那个1000多行的SkinedMesh例子面前顺利地崩溃了,心想,还是先从最基本的关键帧动画开始做吧-_-!

确定文件格式:md2(正好连找都不用找了,老师给了)

以下是我Copy的:MD2文件格式简介



MD2是Quake2中使用的模型文件格式,由于其比较简单,容易实现,所以应用很广,是一种经典的动画模型格式。该文件格式由2部分组成:一部分是文件头,包含了文件ID号、版本号和有关模型的各种数据的起始地址等;另一部分是文件的主体,包含了有关模型的各种数据,如顶点数据、纹理数据、法向量数据等。



MD2是基于关键帧动画的,关键帧插值的数学公式为:

p(t) = p(0) + t ( p1 - p0 )

其中:



t — 当前时间。0表示开始,1表示结束;



p(t) — 时间t 时方程的值;



p0 — 起始位置;



p1 — 结束位置。



MD2共有16个关键帧:

start:0 end:39 name:stand
start:40 end:45 name:run
start:46 end:53 name:attack
start:54 end:65 name:pain
start:66 end:71 name:jump
start:72 end:83 name:flip
start:84 end:94 name:salute
start:95 end:111 name:taunt
start:112 end:122 name:wave
start:123 end:134 name:point
start:135 end:153 name:crstnd
start:154 end:159 name:crwalk
start:160 end:168 name:crattack
start:169 end:172 name:crpain
start:173 end:177 name:crdeath
start:178 end:197 name:death


说白了,一个模型有16个动作,每个动作有很多帧组成,每帧由很多三角形组成一个网络,每个三角形由三个顶点组成,每个顶点由x,y,z三个坐标组成,每个……(再说就欠揍了)
那么怎么让它动呢?知道怎么放电影不?就是一帧帧地画就行了!

这是我改写的类:



#pragma once
#include
#include
/**//***************************************************************************/
/**//* */
/**//* File: XMD2Model.h */
/**//* Author: bkenwright@screentoys.net */
/**//* Date: 10-11-2002 */
/**//* */
/**//***************************************************************************/
// This file holds our self contained .md2 (quake2) class for loading in and
// displaying our .md2 file in directX3D.


struct stMd2Header
...{
int magic; // The magic number used to identify the file.
int version; // The file version number (must be 8).
int skinWidth; // The width in pixels of our image.
int skinHeight; // The height in pixels of our image.
int frameSize; // The size in bytes the frames are.
int numSkins; // The number of skins associated with the model.
int numVertices; // The number of vertices.
int numTexCoords; // The number of texture coordinates.
int numTriangles; // The number of faces (polygons).
int numGlCommands; // The number of gl commands.
int numFrames; // The number of animated frames.
int offsetSkins; // The offset in the file for the skin data.
int offsetTexCoords;// The offset in the file for the texture data.
int offsetTriangles;// The offset in the file for the face data.
int offsetFrames; // The offset in the file for the frames data.
int offsetGlCommands;// The offset in the file for the gl commands data.
int offsetEnd; // The end of the file offset.
};


// Some structures to hold or read in data in.
struct stMd2Skins
...{
char skinName[64];
};


struct stMd2TexCoords
...{
short u, v;
};


struct stMd2Triangles
...{
short vertexIndex[3];
short texIndex[3];
};


struct stMd2Vertices
...{
float vertex[3];
float normal[3];
};

struct stMd2Frames
...{
char name[16];
stMd2Vertices* pFinalVerts;
};


// These two variables are declared in dxdraw.cpp thats why they have the
// extern keyword in front of them.
extern LPDIRECT3DDEVICE9 g_pd3dDevice;


struct stKeyFrame
...{
int start;
int end;
char szName[16];
};

struct stKey
...{
int numKeys;
stKeyFrame *pKey;
};


// Our DirectX3D structure definition.
struct my_vertex
...{
D3DXVECTOR3 m_vecPos; //位置
D3DCOLOR m_dwDiffuse; //颜色
D3DXVECTOR2 m_vecTex; //纹理坐标
};



/**//***************************************************************************/
/**//* */
/**//* The XMD2Model class, yup its name speaks for itself, it loads the 3D */
/**//* model data from the .md2 file and then we can access its public data */
/**//* variables to use the data. */
/**//* */
/**//***************************************************************************/


class XMD2Model
...{
public:
XMD2Model()...{ m_vertex_description = (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1); };
~XMD2Model()...{};

public:
bool ImportMD2(char* szFileName, char* szTexName);
void Release();
void RenderFrame();
void Animate(UINT iAnimKey);

protected:
void ReadMD2Data();
void SetUpFrames();
void SetUpDX();

bool Timer(float* t);
void SetDXVertices(UINT iAnimKey);

FILE* m_fp;

protected:
stMd2Header m_Md2Header;

stMd2Skins *m_pSkins;
stMd2Triangles *m_pTriangles;
stMd2TexCoords *m_pTexCoords;
stMd2Frames *m_pFrames;

protected:
stKey m_Keys;
int m_curFrame;
int m_nextFrame;
int m_curAnimKey;

protected:
float m_lastTime;
float m_elapsedTime;

protected:// dx variables
UINT m_vertex_description;
IDirect3DTexture9* m_pTexture;
IDirect3DVertexBuffer9* m_vb; // vertex buffer
};



#include "XMD2Model.h"

/**//***************************************************************************/
/**//* */
/**//* The action implimentations of our XMD2Model class. */
/**//* */
/**//***************************************************************************/

bool XMD2Model::ImportMD2(char* szFileName, char* szTexName)
...{
m_fp = fopen(szFileName, "rb");

ReadMD2Data();
SetUpFrames();
SetUpDX();

fclose(m_fp);

// Load or textures into our DX.
// Use D3DX to create a texture from a file based image
if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, szTexName, &m_pTexture ) ) )
...{
MessageBox(NULL, "加载纹理失败!", NULL, MB_OK);
return false;
}

return true;
}

void XMD2Model::ReadMD2Data()
...{
fread(&m_Md2Header, 1, sizeof(m_Md2Header), m_fp);

// Allocate memory for our data so we can read it in.
m_pSkins = new stMd2Skins [ m_Md2Header.numSkins ];
m_pTexCoords = new stMd2TexCoords[ m_Md2Header.numTexCoords ];
m_pTriangles = new stMd2Triangles[ m_Md2Header.numTriangles ];
m_pFrames = new stMd2Frames [ m_Md2Header.numFrames ];

// -1- Seek to the start of our skins name data and read it in.
fseek(m_fp, m_Md2Header.offsetSkins, SEEK_SET);
fread(m_pSkins, sizeof(stMd2Skins), m_Md2Header.numSkins, m_fp);

// -2- Seek to the start of our Texture Coord data and read it in.
fseek(m_fp, m_Md2Header.offsetTexCoords, SEEK_SET);
fread(m_pTexCoords, sizeof(stMd2TexCoords), m_Md2Header.numTexCoords, m_fp);

// -3- Seek to the start of the Triangle(e.g. Faces) data and read that in.
fseek(m_fp, m_Md2Header.offsetTriangles, SEEK_SET);
fread(m_pTriangles, sizeof(stMd2Triangles), m_Md2Header.numTriangles, m_fp);

// -4- Finally lets read in "one" of the frames, the first one.!
struct stAliasVerts
...{
byte vertex[3]; // an index reference into the location of our vertexs
byte lightNormalIndex; // in index into which tex coords to use.
};
struct stAliasFrame
...{
float scale[3];
float translate[3];
char name[16];
stAliasVerts aliasVerts[1];
};

unsigned char largebuffer[50000];
stAliasFrame* pTempFrame = (stAliasFrame*) largebuffer;

fseek(m_fp, m_Md2Header.offsetFrames, SEEK_SET);

for(int iFrame=0; iFrame< m_Md2Header.numFrames; iFrame++)
...{
fread(pTempFrame, 1, m_Md2Header.frameSize, m_fp); // We have read in all the frame data here (into a temporyary!!..eeEKK)..

m_pFrames[iFrame].pFinalVerts = new stMd2Vertices[ m_Md2Header.numVertices ];

strcpy( m_pFrames[iFrame].name, pTempFrame->name );
// CONVERSION! A few things before we can use our read in values,
// for some reason the Z and Y need to be swapped, as Z is facing up
// and Y is facing into the screen.
// Also our texture coordinates values are between 0 and 256, we just
// divide them all by 256 which makes them between 0 and 1.

// Swap Z<->Y
for(int i=0; i< m_Md2Header.numVertices; i++)
...{
m_pFrames[iFrame].pFinalVerts[i].vertex[0] = pTempFrame->aliasVerts[i].vertex[0] * pTempFrame->scale[0]
+ pTempFrame->translate[0]; // x
m_pFrames[iFrame].pFinalVerts[i].vertex[2] = -1*(pTempFrame->aliasVerts[i].vertex[1] * pTempFrame->scale[1]
+ pTempFrame->translate[1]); // z
m_pFrames[iFrame].pFinalVerts[i].vertex[1] = pTempFrame->aliasVerts[i].vertex[2] * pTempFrame->scale[2]
+ pTempFrame->translate[2]; // y
}
}

// Scale Textures.
for (int j=0; j< m_Md2Header.numTexCoords; j++)
...{
// WARNING.. you can't put a decimal number into a short...e.g.
// you can't put 0.1 into a unsigned short int, it will be changed to 0.
/**//*
m_pTexCoords[j].u = m_pTexCoords[j].u ;// 256; //float(m_Md2Header.skinWidth);
m_pTexCoords[j].v = m_pTexCoords[j].v ;// 256; //float(m_Md2Header.skinHeight);
*/
}
}

void XMD2Model::SetUpFrames()
...{
//stand01, stand02... walk01 etc.
//First lets see how many key frames there are.. e.g. walk, run, stand etc.
m_Keys.numKeys = 0;
char strName[16] = ...{0};
char strLastName[16] = ...{0};
char strVeryFirstName[16] = ...{0};

for(int iFrame=0; iFrame< m_Md2Header.numFrames; iFrame++)
...{
strcpy(strName, m_pFrames[iFrame].name);
int stringLength = strlen( strName );
for(int i=0; i< stringLength; i++)
...{
// a:97 A:65 z:122 Z:90
if( (strName[i] < 'A') || (strName[i] > 'z' ) )
...{
// Its an integer if we are here.
strName[i] = '
 
评论
显示
悄悄话
汇众教育官网 | 联系方式 | 版权声明 | 友情链接
Copyright 2008© 汇众益智(北京)教育科技有限公司. All Rights Reserved
京ICP备09092043号 京公网安备11010802009023号