只是把它的原理弄明白一些了,但是,我弱小的意志在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 |
说白了,一个模型有16个动作,每个动作有很多帧组成,每帧由很多三角形组成一个网络,每个三角形由三个顶点组成,每个顶点由x,y,z三个坐标组成,每个……(再说就欠揍了)
那么怎么让它动呢?知道怎么放电影不?就是一帧帧地画就行了!
这是我改写的类:
#include < iostream >
#include < d3dx9.h >
/**/ /***************************************************************************/
/**/ /* */
/**/ /* 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] = '