读取BVH文件信息,如何提取并计算每个骨骼的世界坐标

李世洋588 2014-04-26 05:17:26
这是BVH.H
#ifndef _BVH_H_
#define _BVH_H_

#include <vector>
#include <map>
#include <string>
#include "Matrix.h"
using namespace std;
class BVH
{
public:
enum ChannelEnum
{
X_ROTATION, Y_ROTATION, Z_ROTATION,
X_POSITION, Y_POSITION, Z_POSITION
};
struct Joint;
struct Channel
{
// 关节指针
Joint * joint;
// 旋转类型
ChannelEnum type;
int index;
};
struct Joint
{
string name;
int index;
Joint * parent;
vector< Joint * > children;
// 偏移
double offset[3];
// 递归是否结束
bool has_site;
double site[3];
vector< Channel * > channels;
};
private:
bool is_load_success;
/* 文件信息 */
string file_name; //
string motion_name; //
/* 骨架信息 */
int num_channel; //
vector< Channel * > channels; // 通道数目,用来解析动画数据,只用来标志旋转信息
vector< Joint * > joints; //
map< string, Joint * > joint_index; //
/* 运动数据块 */
int num_frame; // 帧数
double interval; // 间隔
double * motion; //
public:
BVH();
friend class LoadObj;
BVH(const char * bvh_file_name);
~BVH();
void Clear();
void Load(const char * bvh_file_name);
public:
bool IsLoadSuccess() const { return is_load_success; }
const string & GetFileName() const { return file_name; }
const string & GetMotionName() const { return motion_name; }
const int GetNumJoint() const { return joints.size(); }
const Joint * GetJoint(int no) const { return joints[no]; }
const int GetNumChannel() const { return channels.size(); }
const Channel * GetChannel(int no) const { return channels[no]; }
const Joint * GetJoint(const string & j) const {
map< string, Joint * >::const_iterator i = joint_index.find(j);
return (i != joint_index.end()) ? (*i).second : NULL;
}
const Joint * GetJoint(const char * j) const {
map< string, Joint * >::const_iterator i = joint_index.find(j);
return (i != joint_index.end()) ? (*i).second : NULL;
}
int GetNumFrame() const { return num_frame; }
double GetInterval() const { return interval; }
double GetMotion(int f, int c) const { return motion[f*num_channel + c]; }
void SetMotion(int f, int c, double v) { motion[f*num_channel + c] = v; }
public:
void RenderFigure(int frame_no, float scale = 1.0f);
static void RenderFigure(const Joint * root, const double * data, float scale = 1.0f);
static void RenderBone(float x0, float y0, float z0, float x1, float y1, float z1);
};
#endif // _BVH_H_

这是BVH.CPP:

#include <fstream>
#include <string.h>
#include "BVH.h"
#include "LoadObj.h"
BVH::BVH()
{
motion = NULL;
Clear();
}
BVH::BVH( const char * bvh_file_name )
{
motion = NULL;
Clear();
Load( bvh_file_name );
}
BVH::~BVH()
{
Clear();
}
void BVH::Clear()
{
int i;
for ( i=0; i<channels.size(); i++ )
delete channels[ i ];
for ( i=0; i<joints.size(); i++ )
delete joints[ i ];
if ( motion != NULL )
delete motion;
is_load_success = false;
file_name = "";
motion_name = "";
num_channel = 0;
channels.clear();
joints.clear();
joint_index.clear();
num_frame = 0;
interval = 0.0;
motion = NULL;
}
// BVH载入
void BVH::Load( const char * bvh_file_name )
{
#define BUFFER_LENGTH 1024*4
ifstream file;
char line[ BUFFER_LENGTH ];
char * token;
char separater[] = " :,\t";
vector< Joint * > joint_stack;
Joint * joint = NULL;
Joint * new_joint = NULL;
bool is_site = false;
double x, y ,z;
int i, j;
Clear();
file_name = bvh_file_name;
const char * mn_first = bvh_file_name;
const char * mn_last = bvh_file_name + strlen( bvh_file_name );
if ( strrchr( bvh_file_name, '\\' ) != NULL )
mn_first = strrchr( bvh_file_name, '\\' ) + 1;
else if ( strrchr( bvh_file_name, '/' ) != NULL )
mn_first = strrchr( bvh_file_name, '/' ) + 1;
if ( strrchr( bvh_file_name, '.' ) != NULL )
mn_last = strrchr( bvh_file_name, '.' );
if ( mn_last < mn_first )
mn_last = bvh_file_name + strlen( bvh_file_name );
motion_name.assign( mn_first, mn_last );
// 设置读取方式
file.open( bvh_file_name, ios::in );
if ( file.is_open() == 0 ) return;
while ( ! file.eof() )
{
if ( file.eof() ) goto bvh_error;
file.getline( line, BUFFER_LENGTH );
token = strtok( line, separater );
if ( token == NULL ) continue;
if ( strcmp( token, "{" ) == 0 )
{
joint_stack.push_back( joint );
joint = new_joint;
continue;
}
if ( strcmp( token, "}" ) == 0 )
{
joint = joint_stack.back();
joint_stack.pop_back();
is_site = false;
continue;
}
if ( ( strcmp( token, "ROOT" ) == 0 ) ||
( strcmp( token, "JOINT" ) == 0 ) )
{
new_joint = new Joint();
new_joint->index = joints.size();
new_joint->parent = joint;
new_joint->has_site = false;
new_joint->offset[0] = 0.0; new_joint->offset[1] = 0.0; new_joint->offset[2] = 0.0;
new_joint->site[0] = 0.0; new_joint->site[1] = 0.0; new_joint->site[2] = 0.0;
joints.push_back( new_joint );
if ( joint )
joint->children.push_back( new_joint );
token = strtok( NULL, "" );
while ( *token == ' ' ) token ++;
new_joint->name = token;
joint_index[ new_joint->name ] = new_joint;
continue;
}
// 读取完骨架
if ( ( strcmp( token, "End" ) == 0 ) )
{
new_joint = joint;
is_site = true;
continue;
}
if ( strcmp( token, "OFFSET" ) == 0 )
{
token = strtok( NULL, separater );
x = token ? atof( token ) : 0.0;
token = strtok( NULL, separater );
y = token ? atof( token ) : 0.0;
token = strtok( NULL, separater );
z = token ? atof( token ) : 0.0;
// 递归结束
if ( is_site )
{
joint->has_site = true;
joint->site[0] = x;
joint->site[1] = y;
joint->site[2] = z;
}
else
// 子骨骼相对父骨骼的偏移,也可体现父骨骼的长度和方向,骨骼偏移矩阵(BoneOffsetMatrix)用来将顶点从Mesh空间变换到骨骼空间
{
joint->offset[0] = x;
joint->offset[1] = y;
joint->offset[2] = z;
}
continue;
}
if ( strcmp( token, "CHANNELS" ) == 0 )
{
token = strtok( NULL, separater );
joint->channels.resize( token ? atoi( token ) : 0 );
for ( i=0; i<joint->channels.size(); i++ )
{
Channel * channel = new Channel();
channel->joint = joint;
channel->index = channels.size();
channels.push_back( channel );
joint->channels[ i ] = channel;
token = strtok( NULL, separater );
if ( strcmp( token, "Xrotation" ) == 0 )
channel->type = X_ROTATION;
else if ( strcmp( token, "Yrotation" ) == 0 )
channel->type = Y_ROTATION;
else if ( strcmp( token, "Zrotation" ) == 0 )
channel->type = Z_ROTATION;
else if ( strcmp( token, "Xposition" ) == 0 )
channel->type = X_POSITION;
else if ( strcmp( token, "Yposition" ) == 0 )
channel->type = Y_POSITION;
else if ( strcmp( token, "Zposition" ) == 0 )
channel->type = Z_POSITION;
}
}
// Motion数据块
if ( strcmp( token, "MOTION" ) == 0 )
break;
}
// 读取数据块
。。。。。
}
// BVH绘制部分
#include <math.h>
#include <gl/glut.h>
// 根据帧数和缩放比绘制
void BVH::RenderFigure( int frame_no, float scale )
{
// 绘制第一个关节
RenderFigure( joints[ 0 ], motion + frame_no * num_channel, scale );
}
//因为骨骼的变换都是相对于父节点的变换,但是变换Mesh顶点,又是必须使用世界矩阵的变换,所以我们需要根据骨骼点的骨骼矩阵求出每个骨骼点的世界变换矩阵。而父骨骼点的变换又实时影响到了子骨骼点的世界坐标矩阵位置,所以,这里一定需要用递归,将每个骨骼点的世界矩阵坐标求到。
void BVH::RenderFigure( const Joint * joint, const double * data, float scale )
{
glPushMatrix();
/*将骨骼移到相应的位置,否则在原点*/
// 父骨骼的初始位置,求根骨骼点的世界坐标,如何求?
if ( joint->parent == NULL )
{
glTranslatef( data[ 0 ] * scale, data[ 1 ] * scale, data[ 2 ] * scale );
}
// 子骨骼的变换位置,求子骨骼点的世界坐标,如何求?
else
{
glTranslatef( joint->offset[ 0 ] * scale, joint->offset[ 1 ] * scale, joint->offset[ 2 ] * scale );
}

// 根据鼠标旋转
int i, j;
for ( i=0; i<joint->channels.size(); i++ )
{
Channel * channel = joint->channels[ i ];
if ( channel->type == X_ROTATION )
glRotatef( data[ channel->index ], 1.0f, 0.0f, 0.0f );
else if ( channel->type == Y_ROTATION )
glRotatef( data[ channel->index ], 0.0f, 1.0f, 0.0f );
else if ( channel->type == Z_ROTATION )
glRotatef( data[ channel->index ], 0.0f, 0.0f, 1.0f );
}
//绘制根骨骼
if ( joint->children.size() == 0 )
{
RenderBone( 0.0f, 0.0f, 0.0f, joint->site[ 0 ] * scale, joint->site[ 1 ] * scale, joint->site[ 2 ] * scale );
}
if ( joint->children.size() == 1 )
{
Joint * child = joint->children[ 0 ];
RenderBone( 0.0f, 0.0f, 0.0f, child->offset[ 0 ] * scale, child->offset[ 1 ] * scale, child->offset[ 2 ] * scale );
}
if ( joint->children.size() > 1 )
{
float center[ 3 ] = { 0.0f, 0.0f, 0.0f };
for ( i=0; i<joint->children.size(); i++ )
{
Joint * child = joint->children[ i ];
center[ 0 ] += child->offset[ 0 ];
center[ 1 ] += child->offset[ 1 ];
center[ 2 ] += child->offset[ 2 ];
}
center[ 0 ] /= joint->children.size() + 1;
center[ 1 ] /= joint->children.size() + 1;
center[ 2 ] /= joint->children.size() + 1;
RenderBone( 0.0f, 0.0f, 0.0f, center[ 0 ] * scale, center[ 1 ] * scale, center[ 2 ] * scale );
for ( i=0; i<joint->children.size(); i++ )
{
Joint * child = joint->children[ i ];
RenderBone( center[ 0 ] * scale, center[ 1 ] * scale, center[ 2 ] * scale,
child->offset[ 0 ] * scale, child->offset[ 1 ] * scale, child->offset[ 2 ] * scale );
}

}
/*绘制下一段骨骼
for ( i=0; i<joint->children.size(); i++ )
{
RenderFigure( joint->children[ i ], data, scale );
}
*/
glPopMatrix();
}


//
void BVH::RenderBone( float x0, float y0, float z0, float x1, float y1, float z1 )
{
。。。。绘制圆柱骨骼
}

// End of BVH.cpp

...全文
3195 1 打赏 收藏 转发到动态 举报
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
qq69825002 2015-05-09
  • 打赏
  • 举报
回复
楼主您好,您的项目对我的毕业设计特别有帮助,希望与您取得联系,请教您一些问题。这是我的QQ:996370234

1,450

社区成员

发帖
与我相关
我的任务
社区描述
多媒体/设计/Flash/Silverlight 开发 图象工具使用
社区管理员
  • 图象工具使用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧