MD2关键帧动画

本想用骨骼动画的,无奈.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 <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 stMd2Heade

{

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 buffe

};

#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] = '

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏程序生活

第四周编程作业(二)-Deep Neural Network for Image Classification: ApplicationDeep Neural Network for Image Cl

Deep Neural Network for Image Classification: Application When you finish this, ...

1.1K70
来自专栏CreateAMind

Hebbian learning 的实现 Fast Weights

9420
来自专栏程序生活

第二周编程作业 -Logistic Regression with a Neural Network mindsetLogistic Regression with a Neural Network

Logistic Regression with a Neural Network mindset Welcome to your first (require...

1.1K60
来自专栏人工智能头条

Deep Learning Machine Beats Humans in IQ Test

18940
来自专栏人工智能头条

将机器学习应用于金融技术领域的15家公司(英)

16520
来自专栏HansBug's Lab

1475: 方格取数

1475: 方格取数 Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 578  Solved: 309 [Subm...

27160
来自专栏杨熹的专栏

Udacity-Machine Learning纳米学位-学习笔记1

课程地址 Category: Machine Learning    Artificial Intelligence    Data Science   ...

35770
来自专栏HansBug's Lab

3381: [Usaco2004 Open]Cave Cows 2 洞穴里的牛之二

3381: [Usaco2004 Open]Cave Cows 2 洞穴里的牛之二 Time Limit: 10 Sec  Memory Limit: 128 ...

30270
来自专栏程序生活

第三周编程作业-Planar data classification with one hidden layerPlanar data classification with one hidden l

Planar data classification with one hidden layer Welcome to your week 3 programm...

1.3K100
来自专栏玉树芝兰

How to Accelerate Your Python Deep Learning with Cloud GPU?

This afternoon, I trained a 3-layers neural network as a regression model to pre...

11810

扫码关注云+社区

领取腾讯云代金券