Opengl скелетная анимация
Делаю загрузчик 3D с анимацией из 3ds max. Пример взял от сюда"Экспорт анимированных 3D моделей". Взял исходник из примера к статье. Попытался перевести с паскаля на C++.
То что получилось видно на видио. Слева мой вариант.
Мне кажется что мой вариант не такой хароший как тот что справа =).
[video=youtube;hklLuMXwKK8]http://www.youtube.com/watch?v=hklLuMXwKK8[/video]
Так вот собственно вопрос:
Почему у меня нет девушки? xD
И может я не правильно перевел исходник?
Цитата:
main.cpp
Код:
class TModel {
private:
int Texture;
int FPS;
int K_Count;
int B_Count;
int V_Count;
int F_Count;
int T_Count;
TVector *Vertex;
TFace *Face;
TVector2D *TexCoord;
TFace *TexFace;
TWeight **Weight; // веса вершин
int *int_weight;
TVector *RVertex; // вершины после применения костей
TBone *Bone; // список костей и их анимации
int bon;
public:
TModel() {
bon = 1;
};
void Load(char *_N);
void Render(void);
};
void TModel::Load(char *_N) {
FILE *l_file;
int i;
int W_Count;
char name[50];
sprintf(name, "%s.mx3", _N);
if ((l_file = fopen(name, "rb")) == NULL)
return;
fread(&K_Count, sizeof(K_Count), 1, l_file);
fread(&FPS, sizeof(FPS), 1, l_file);
fread(&B_Count, sizeof(B_Count), 1, l_file);
fread(&V_Count, sizeof(V_Count), 1, l_file);
fread(&F_Count, sizeof(F_Count), 1, l_file);
fread(&T_Count, sizeof(T_Count), 1, l_file);
Vertex = new TVector[V_Count];
Face = new TFace[F_Count];
TexCoord = new TVector2D[T_Count];
TexFace = new TFace[F_Count];
// TVector
fread(Vertex, sizeof(TVector), V_Count, l_file);
fread(Face, sizeof(TFace), F_Count, l_file);
fread(TexCoord, sizeof(TVector2D), T_Count, l_file);
fread(TexFace, sizeof(TFace), F_Count, l_file);
Weight = (TWeight * *)new int[V_Count];
int_weight = new int[V_Count];
for (int i = 0; i < V_Count; i++) {
fread(&W_Count, sizeof(W_Count), 1, l_file);
Weight = (TWeight*)malloc(V_Count*sizeof(TWeight));
fread((void*)Weight, sizeof(TWeight), W_Count, l_file);
int_weight = W_Count;
}
Bone = new TBone[B_Count];
for (int i = 0; i < B_Count; i++) {
Bone.Frame = (_TFrame*)malloc(K_Count*sizeof(_TFrame));
fread(Bone.Frame, sizeof(_TFrame), K_Count, l_file);
}
fclose(l_file);
RVertex = (TVector*)malloc(V_Count*sizeof(TVector));
sprintf(name, "%s.bmp", _N);
LoadBitmap(num, name);
CreateTexture(num, name);
}
void TModel::Render(void) {
bon += 1;
if (bon >= K_Count - 1) {
bon = 1;
}
// TVector null_vec=TVector(0,0,0);
int i, j;
int lf, nf;
char dt, t;
TVector p;
TQuat r;
TMatrix W_Matrix;
/*
#define _frac(num,i) (i)*((num)/(i) - floor((num)/(i)))
dt = 1000 / FPS; // длительность одного кадра
lf = (int)floor ((bon/dt)) % K_Count; // вычисляем предыдущий кадр
nf = (lf + 1) % K_Count; // и следующий
t = _frac(bon,dt); // временной коэффициент */
dt = 1; // длительность одного кадра
lf = bon - 1; // вычисляем предыдущий кадр
nf = bon + 1; // и следующий
t = 1;
// расчёт интерполированных матриц костей
for (int i = 0; i < B_Count; i++) {
// линейная интерполяция кватерниона и позиции
r = Q_Lerp(&Bone.Frame[lf].Rot, &Bone.Frame[nf].Rot, t);
p = V_Lerp(&Bone.Frame[lf].Pos, &Bone.Frame[nf].Pos, t);
// расчёт матрицы трансформации для объекта
Q_Matrix(&r, &Bone.Matrix); // перевод кватерниона в матрицу
Bone.Matrix[3][0] = p.x; // дописываем позицию в последнюю строку
Bone.Matrix[3][1] = p.y;
Bone.Matrix[3][2] = p.z;
}
// Расчёт положения вершин в соответствии с текущим состоянием костей
for (int i = 0; i < V_Count; i++) {
RVertex = TVector(0, 0, 0);
for (int j = 0; j < int_weight; j++) {
// Weight[j]
M_Mult(&W_Matrix, &Bone[Weight[j].ID].Matrix,Weight[j].Value); // Получение "взвешенной" матрицы
V_Add(&RVertex, &M_Mult(W_Matrix, &Vertex));
}
}
glBegin(GL_TRIANGLES);
for (int i = 0; i < F_Count; i++) {
glTexCoord2f(TexCoord[Face[0]].u, TexCoord[Face[0]].v);
glVertex3f(RVertex[Face[0]].x, RVertex[Face[0]].y,
RVertex[Face[0]].z);
glTexCoord2f(TexCoord[Face[1]].u, TexCoord[Face[1]].v);
glVertex3f(RVertex[Face[1]].x, RVertex[Face[1]].y,
RVertex[Face[1]].z);
glTexCoord2f(TexCoord[Face[2]].u, TexCoord[Face[2]].v);
glVertex3f(RVertex[Face[2]].x, RVertex[Face[2]].y,
RVertex[Face[2]].z);
}
glEnd();
}
private:
int Texture;
int FPS;
int K_Count;
int B_Count;
int V_Count;
int F_Count;
int T_Count;
TVector *Vertex;
TFace *Face;
TVector2D *TexCoord;
TFace *TexFace;
TWeight **Weight; // веса вершин
int *int_weight;
TVector *RVertex; // вершины после применения костей
TBone *Bone; // список костей и их анимации
int bon;
public:
TModel() {
bon = 1;
};
void Load(char *_N);
void Render(void);
};
void TModel::Load(char *_N) {
FILE *l_file;
int i;
int W_Count;
char name[50];
sprintf(name, "%s.mx3", _N);
if ((l_file = fopen(name, "rb")) == NULL)
return;
fread(&K_Count, sizeof(K_Count), 1, l_file);
fread(&FPS, sizeof(FPS), 1, l_file);
fread(&B_Count, sizeof(B_Count), 1, l_file);
fread(&V_Count, sizeof(V_Count), 1, l_file);
fread(&F_Count, sizeof(F_Count), 1, l_file);
fread(&T_Count, sizeof(T_Count), 1, l_file);
Vertex = new TVector[V_Count];
Face = new TFace[F_Count];
TexCoord = new TVector2D[T_Count];
TexFace = new TFace[F_Count];
// TVector
fread(Vertex, sizeof(TVector), V_Count, l_file);
fread(Face, sizeof(TFace), F_Count, l_file);
fread(TexCoord, sizeof(TVector2D), T_Count, l_file);
fread(TexFace, sizeof(TFace), F_Count, l_file);
Weight = (TWeight * *)new int[V_Count];
int_weight = new int[V_Count];
for (int i = 0; i < V_Count; i++) {
fread(&W_Count, sizeof(W_Count), 1, l_file);
Weight = (TWeight*)malloc(V_Count*sizeof(TWeight));
fread((void*)Weight, sizeof(TWeight), W_Count, l_file);
int_weight = W_Count;
}
Bone = new TBone[B_Count];
for (int i = 0; i < B_Count; i++) {
Bone.Frame = (_TFrame*)malloc(K_Count*sizeof(_TFrame));
fread(Bone.Frame, sizeof(_TFrame), K_Count, l_file);
}
fclose(l_file);
RVertex = (TVector*)malloc(V_Count*sizeof(TVector));
sprintf(name, "%s.bmp", _N);
LoadBitmap(num, name);
CreateTexture(num, name);
}
void TModel::Render(void) {
bon += 1;
if (bon >= K_Count - 1) {
bon = 1;
}
// TVector null_vec=TVector(0,0,0);
int i, j;
int lf, nf;
char dt, t;
TVector p;
TQuat r;
TMatrix W_Matrix;
/*
#define _frac(num,i) (i)*((num)/(i) - floor((num)/(i)))
dt = 1000 / FPS; // длительность одного кадра
lf = (int)floor ((bon/dt)) % K_Count; // вычисляем предыдущий кадр
nf = (lf + 1) % K_Count; // и следующий
t = _frac(bon,dt); // временной коэффициент */
dt = 1; // длительность одного кадра
lf = bon - 1; // вычисляем предыдущий кадр
nf = bon + 1; // и следующий
t = 1;
// расчёт интерполированных матриц костей
for (int i = 0; i < B_Count; i++) {
// линейная интерполяция кватерниона и позиции
r = Q_Lerp(&Bone.Frame[lf].Rot, &Bone.Frame[nf].Rot, t);
p = V_Lerp(&Bone.Frame[lf].Pos, &Bone.Frame[nf].Pos, t);
// расчёт матрицы трансформации для объекта
Q_Matrix(&r, &Bone.Matrix); // перевод кватерниона в матрицу
Bone.Matrix[3][0] = p.x; // дописываем позицию в последнюю строку
Bone.Matrix[3][1] = p.y;
Bone.Matrix[3][2] = p.z;
}
// Расчёт положения вершин в соответствии с текущим состоянием костей
for (int i = 0; i < V_Count; i++) {
RVertex = TVector(0, 0, 0);
for (int j = 0; j < int_weight; j++) {
// Weight[j]
M_Mult(&W_Matrix, &Bone[Weight[j].ID].Matrix,Weight[j].Value); // Получение "взвешенной" матрицы
V_Add(&RVertex, &M_Mult(W_Matrix, &Vertex));
}
}
glBegin(GL_TRIANGLES);
for (int i = 0; i < F_Count; i++) {
glTexCoord2f(TexCoord[Face[0]].u, TexCoord[Face[0]].v);
glVertex3f(RVertex[Face[0]].x, RVertex[Face[0]].y,
RVertex[Face[0]].z);
glTexCoord2f(TexCoord[Face[1]].u, TexCoord[Face[1]].v);
glVertex3f(RVertex[Face[1]].x, RVertex[Face[1]].y,
RVertex[Face[1]].z);
glTexCoord2f(TexCoord[Face[2]].u, TexCoord[Face[2]].v);
glVertex3f(RVertex[Face[2]].x, RVertex[Face[2]].y,
RVertex[Face[2]].z);
}
glEnd();
}
Цитата:
IncludLib.h
Код:
typedef float TMatrix[4][4];
typedef int TFace[3];
struct TVector2D{
float u, v;
};
struct TVector{
TVector(){};
inline TVector(float _x,float _y,float _z):x(_x),y(_y),z(_z){};
float x,y,z;
};
struct TQuat{
TQuat() {};
inline TQuat(float _x,float _y,float _z,float _w):x(_x),y(_y),z(_z),w(_w){}
float x, y, z, w; // :Single
};
struct _TFrame{
TVector Pos; // позиция
TQuat Rot; // поворот
};
// Вес вершины
struct TWeight{
int ID; // Номер кости
float Value; // Значение
};
// Кость
struct TBone{
TMatrix Matrix;
_TFrame *Frame;
};
inline TVector M_Mult(TMatrix m,TVector v){
TVector( m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0],
m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1],
m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z + m[3][2]);
}
inline void M_MultAdd(TVector *result, TMatrix &m, TVector *v){
result->x += (m[0][0] * v->x + m[1][0] * v->y + m[2][0] * v->z + m[3][0]);
result->y += (m[0][1] * v->x + m[1][1] * v->y + m[2][1] * v->z + m[3][1]);
result->z += (m[0][2] * v->x + m[1][2] * v->y + m[2][2] * v->z + m[3][2]);
}
inline M_Mult(TMatrix &result, TMatrix &m, float x){
for(int i=0; i<4; i++)
for(int j=0; j<4; j++)
result[j] = m[j] * x;
};
inline V_Add(TVector *v1,TVector *v2){
v1->x += v2->x;
v1->y += v2->y;
v1->z += v2->z;
}
inline TVector V_Lerp(TVector *v1, TVector *v2 ,float t){
return TVector(v1->x + (v2->x - v1->x) * t,v1->y + (v2->y - v1->y) * t,v1->z + (v2->z - v1->z) * t);
};
inline void Q_Matrix(TQuat *q,TMatrix &m){
float wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2;
x2 =q->x+ q->x; y2 =q->y+ q->y; z2 =q->z+ q->z;
xx =q->x * x2; xy =q->x * y2; xz =q->x * z2;
yy =q->y * y2; yz =q->y * z2; zz =q->z * z2;
wx =q->w * x2; wy =q->w * y2; wz =q->w * z2;
m[0][0] = 1 - (yy + zz); m[1][0] = xy + wz; m[2][0] = xz - wy;
m[0][1] = xy - wz; m[1][1] = 1 - (xx + zz); m[2][1] = yz + wx;
m[0][2] = xz + wy; m[1][2] = yz - wx; m[2][2] = 1 - (xx + yy);
m[3][0] = 0;
m[3][1] = 0;
m[3][2] = 0;
m[0][3] = 0;
m[1][3] = 0;
m[2][3] = 0;
m[3][3] = 1;
}
inline TQuat Q_Add(TQuat *q1,TQuat *q2){
return TQuat(q1->x + q2->x,q1->y + q2->y,q1->z + q2->z,q1->w + q2->w);
}
inline TQuat Q_Sub(TQuat *q1,TQuat *q2){
return TQuat(q1->x - q2->x,q1->y - q2->y,q1->z - q2->z,q1->w - q2->w);
}
inline float Q_Dot(TQuat *q1,TQuat *q2){
return q1->x * q2->x + q1->y * q2->y + q1->z * q2->z + q1->w * q2->w;
}
inline TQuat Q_Mult(TQuat *q,float d){
return TQuat(q->x * d,q->y * d,q->z * d,q->w * d);
}
inline TQuat Q_Lerp(TQuat *q1,TQuat *q2, float t)
typedef int TFace[3];
struct TVector2D{
float u, v;
};
struct TVector{
TVector(){};
inline TVector(float _x,float _y,float _z):x(_x),y(_y),z(_z){};
float x,y,z;
};
struct TQuat{
TQuat() {};
inline TQuat(float _x,float _y,float _z,float _w):x(_x),y(_y),z(_z),w(_w){}
float x, y, z, w; // :Single
};
struct _TFrame{
TVector Pos; // позиция
TQuat Rot; // поворот
};
// Вес вершины
struct TWeight{
int ID; // Номер кости
float Value; // Значение
};
// Кость
struct TBone{
TMatrix Matrix;
_TFrame *Frame;
};
inline TVector M_Mult(TMatrix m,TVector v){
TVector( m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0],
m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1],
m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z + m[3][2]);
}
inline void M_MultAdd(TVector *result, TMatrix &m, TVector *v){
result->x += (m[0][0] * v->x + m[1][0] * v->y + m[2][0] * v->z + m[3][0]);
result->y += (m[0][1] * v->x + m[1][1] * v->y + m[2][1] * v->z + m[3][1]);
result->z += (m[0][2] * v->x + m[1][2] * v->y + m[2][2] * v->z + m[3][2]);
}
inline M_Mult(TMatrix &result, TMatrix &m, float x){
for(int i=0; i<4; i++)
for(int j=0; j<4; j++)
result[j] = m[j] * x;
};
inline V_Add(TVector *v1,TVector *v2){
v1->x += v2->x;
v1->y += v2->y;
v1->z += v2->z;
}
inline TVector V_Lerp(TVector *v1, TVector *v2 ,float t){
return TVector(v1->x + (v2->x - v1->x) * t,v1->y + (v2->y - v1->y) * t,v1->z + (v2->z - v1->z) * t);
};
inline void Q_Matrix(TQuat *q,TMatrix &m){
float wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2;
x2 =q->x+ q->x; y2 =q->y+ q->y; z2 =q->z+ q->z;
xx =q->x * x2; xy =q->x * y2; xz =q->x * z2;
yy =q->y * y2; yz =q->y * z2; zz =q->z * z2;
wx =q->w * x2; wy =q->w * y2; wz =q->w * z2;
m[0][0] = 1 - (yy + zz); m[1][0] = xy + wz; m[2][0] = xz - wy;
m[0][1] = xy - wz; m[1][1] = 1 - (xx + zz); m[2][1] = yz + wx;
m[0][2] = xz + wy; m[1][2] = yz - wx; m[2][2] = 1 - (xx + yy);
m[3][0] = 0;
m[3][1] = 0;
m[3][2] = 0;
m[0][3] = 0;
m[1][3] = 0;
m[2][3] = 0;
m[3][3] = 1;
}
inline TQuat Q_Add(TQuat *q1,TQuat *q2){
return TQuat(q1->x + q2->x,q1->y + q2->y,q1->z + q2->z,q1->w + q2->w);
}
inline TQuat Q_Sub(TQuat *q1,TQuat *q2){
return TQuat(q1->x - q2->x,q1->y - q2->y,q1->z - q2->z,q1->w - q2->w);
}
inline float Q_Dot(TQuat *q1,TQuat *q2){
return q1->x * q2->x + q1->y * q2->y + q1->z * q2->z + q1->w * q2->w;
}
inline TQuat Q_Mult(TQuat *q,float d){
return TQuat(q->x * d,q->y * d,q->z * d,q->w * d);
}
inline TQuat Q_Lerp(TQuat *q1,TQuat *q2, float t)