.X文件中的AnimationSet分析

从网上下了个模型,导出成.X文件放程序里后发现有些问题。虽然模型动作很多,但是所有动作都放到同一个动画集里了。这样导致的后果就是这个模型只能看不能用。。。

      在经过对.X文件格式分析后,发现可以修改下.X文件来把所有动作分离出来,放到不同动画集(AnimationSet)里去。理论上完全可以。于是便开始手动修改,像老黄牛般的改了一个多小时,等到头晕眼花的时侯,才发现手动修改不现实。一个多小时才完成不到十分之一的工作。。。

     于是再对.X进行了分析,发现完全可以写个程序来进行所有的工作。学以至用,哈哈!从准备写到最终完成,用了不到三个小时。事实证明,学程序确实有用!

     以上都是废话,哈哈,现在把分析.X得到的经验总结一下。

 

1。动作集

AnimationSet stand {
}

这个结构就是一个动画集(当然还不完整),stand是动作名,在程序中可以通过SetAnimationByName()来播放这个动画集。一个.X可以有多个动画集,每个动画集都是一个动作,比如走路、跑步、攻击等。

2。Animation

结构如下:

Animation Anim-Object15 {

{ Object15 }
}

Object15是骨骼名,这个结构可以理解为:在这一个动作集(比如stand)中,这一个骨骼(Object15)的动画信息。

3。AnimationKey

结构如下:

AnimationKey {

   4;
   63;
   0;16;(。。。后面省略16个浮点数,变换矩阵)
   160;16;(。。。后面省略16个浮点数,变换矩阵)
   。。。省略61个数据

}

其中4表示下面的数据类型是矩阵。63表示下面共有多少条数据(每条数据都是动画的一帧)。0,160,。。。表示时间,是一个Delta时间。

 

以上几个结构不是独立的,将他们组合起来后的结构如下:

AnimationSet stand {

Animation Anim-Object15 {

{ Object15 }

AnimationKey {
   4;
   63;
   。。。
   }
}

。。。其它骨骼动画数据
}

。。。其它动画集

 

最后把写的重组.X文件的代码发出来。。。

//原.x文件中所有动作都只用了一个AnimationSet
//通过此程序可分析数据并生成多个AnimationSet


#include <iostream>
#include <fstream>
#include <string>

using namespace std;

struct AniSet
{
string key; //搜索关键字
int beg; //起始行
int end; //结束行
};

//
//全局变量

string g_sIn; //原始数据
string g_sFrame; //框架数据
string g_sTemp;
string g_sOut; //重组后的数据

//
//函数前向声明

/** 从文件中读取数据,并将数据存入内存
@param
   sFile 源文件名
@param
   sBuffer 存储数据的缓冲
*/
bool LoadDataFromFile( string sFile, string& sBuffer );

/** 重组数据
*/
void RebuildData();

/** 从原始数据中搜索子串
@param
   skey 搜索关键字
@param
   posSet 搜索起点
@param
   beg, end 搜索范围
*/
void GetSubStr( string skey, int beg, int end );

/** 把搜索到的数据插入到最后输出字符串中
@param
   skeySet AnimationSet搜索关键字
@param
   sKeyBone AnimationKey搜索起点
*/
void InsertToAnimationKey( string skeySet, string sKeyBone );

/** 将重组后的数据写入文件
*/
void WriteToFile();

int main(void)
{
//
//读取源数据

if ( !LoadDataFromFile( "old.txt", g_sIn ) )
   return 1;
cout<<"已读取文件 old.txt"<<endl;

//
//读取框架数据

if ( !LoadDataFromFile( "frame.txt", g_sFrame ) )
   return 1;
cout<<"已读取文件 frame.txt"<<endl;

//
//重组数据

RebuildData();
cout<<"重组数据完成"<<endl;

//
//将重组后的数据写入文件

WriteToFile();
cout<<"写入文件完成"<<endl;

//

cout<<"按Enter键退出"<<endl;

cin.get();
return 0;
}

//从文件中读取数据
bool LoadDataFromFile( string sFile, string& sBuffer )
{
//打开文件
ifstream f( sFile.c_str(), ios::in );

//获得文件长度
unsigned int fileLength = 0;
f.seekg( 0, ios_base::end );
fileLength = f.tellg();
f.seekg( 0, ios_base::beg );

if ( fileLength == 0 )
   return false;

sBuffer.reserve( fileLength );

//从文件中读取所有数据
char temp;
for ( unsigned int i=0; i<fileLength; i++ )
{
   f.read( &temp, 1 );
   sBuffer += temp;
}

f.close();

return true;
}

//重组数据
void RebuildData()
{
g_sOut += g_sFrame;

AniSet as[11] =
{
   { "AnimationSet stand",    1,   63 },
   { "AnimationSet walk",     65, 106 },
   { "AnimationSet run",      108, 133 },
   { "AnimationSet swim",     134, 200 },
   { "AnimationSet prefight", 201, 263 },
   { "AnimationSet die",      264, 353 },
   { "AnimationSet attack1", 354, 436 },
   { "AnimationSet attack2", 437, 530 },
   { "AnimationSet throw",    531, 590 },
   { "AnimationSet relax",    591, 688 },
   { "AnimationSet hurt",     689, 725 }
};

string AnimationKey[29] =
{
   "{ Object15 }",
   "{ Object02 }",
   "{ Object01 }",
   "{ root }",
   "{ RPelvis }",
   "{ RThigh }",
   "{ RLowLeg }",
   "{ rFoot }",
   "{ Bone02 }",
   "{ LPelvis }",
   "{ LThigh }",
   "{ LLowLeg }",
   "{ LFoot }",
   "{ Bone01 }",
   "{ Uppertorso }",
   "{ Neck }",
   "{ head }",
   "{ top }",
   "{ RCollar }",
   "{ RUpArm }",
   "{ RLowArm }",
   "{ RHand }",
   "{ Rfinger }",
   "{ LCollar }",
   "{ LUpArm }",
   "{ LLowArm }",
   "{ LHand }",
   "{ Lfinger }",
   "{ np134 }"
};

for ( int i=0; i<11; i++ )
{
   for ( int j=0; j<29; j++ )
   {
    GetSubStr( AnimationKey[j], as[i].beg, as[i].end );
    InsertToAnimationKey( as[i].key, AnimationKey[j] );
   }
}

}

//从源数据中获得子串
void GetSubStr( string skey, int beg, int end )
{
string::size_type posBeg=0, posEnd=0;
string::size_type pos = 0;

pos = g_sIn.find( skey );

for ( int i=0; i<5+beg-1; i++ )
{
   pos = g_sIn.find( "/n", pos+1, 1 );
}
posBeg = pos+1;
for ( int i=0; i<end-beg+1; i++ )
{
   pos = g_sIn.find( "/n", pos+1, 1 );
}
posEnd = pos+1;
g_sTemp = g_sIn.substr( posBeg, posEnd-posBeg );

char a[20];

//重新计算time
pos = 0;
string::size_type posSt = 0;
for ( int i=0; i<end-beg+1; i++ )
{
   posSt = g_sTemp.find( ";", pos, 1 );
   itoa( i*160, a, 10 );
   if ( i==0 )
    g_sTemp.replace( pos+3, posSt-(pos+3), a );
   else
    g_sTemp.replace( pos+4, posSt-(pos+4), a );
   pos = g_sTemp.find( "/n", posSt, 1 );
}

//插入nKeys行
itoa( end-beg+1, a, 10 );
string temp;
temp = "   ";
temp += a;
temp += ";/n";
g_sTemp.insert( 0, temp );
}

void InsertToAnimationKey( string skeySet, string sKeyBone )
{
string::size_type pos = 0;

pos = g_sOut.find( skeySet );
pos = g_sOut.find( sKeyBone.c_str(), pos+1, sKeyBone.size() );

for ( int i=0; i<4; i++ )
{
   pos = g_sOut.find( "/n", pos+1, 1 );
}

g_sOut.insert( pos+1, g_sTemp );
}

void WriteToFile()
{
ofstream newFile( "new.txt", ios::out );

newFile<<g_sOut;

newFile.close();
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值