从网上下了个模型,导出成.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();
}