[attachment=7000:Blender.jpg]
[attachment=7001:Bind pose.jpg]
[attachment=7002:Rotations.jpg]
Here is the function I made to apply animations to my model (most likely reason I'm having this problem):
void Actor::UpdateAnimation( int32_t bone, Matrix44* matrix, double time )
{
// Initialize animation rotation matrix.
Matrix44 animRot;
Matrix44 animRot2;
animRot = MatrixIdentity();
animRot2 = MatrixIdentity();
// Get animation rotation.
Curve uCurve;
Curve lCurve;
uCurve.time = ULONG_MAX;
uCurve.value = Vector4( 0.0f, 0.0f, 0.0f, 0.0f );
lCurve.time = 0;
lCurve.value = Vector4( 0.0f, 0.0f, 0.0f, 0.0f );
// Find one frame that are directly before and one that is directly after the current time.
for( uint32_t i = 0; i < mesh->bones[bone]->Rot_Keys.size(); i++)
{
Curve nCurve = mesh->bones[bone]->Rot_Keys;
if(nCurve.time > lCurve.time && nCurve.time < time )
{
lCurve = nCurve;
}
if(nCurve.time < uCurve.time && nCurve.time > time )
{
uCurve = nCurve;
}
}
// If we can't find an upper curve then just set it to the lower curve.
if(uCurve.time == ULONG_MAX)
{
uCurve = lCurve;
}
// Check if we found any frames then interpolate between the two rotations and create a matrix from the quaternion.
if(uCurve.time > 0)
{
Vector4 currentRot;
currentRot = Slerp(lCurve.value, uCurve.value, (float)(time - lCurve.time) / (float)(uCurve.time - lCurve.time) );
animRot = Ovgl::MatrixRotationQuaternion(¤tRot);
}
// Offset the center of rotation.
animRot2 = MatrixInverse( &Vector4(), &mesh->bones[bone]->matrix) * animRot * mesh->bones[bone]->matrix;
// Get difference from original pose to the animated pose.
matrices[bone] = animRot2 * (*matrix) * MatrixInverse( &Vector4(), &mesh->bones[bone]->matrix);
// Loop through all child bones and update their animations.
for( uint32_t i = 0; i < mesh->bones[bone]->childen.size(); i++)
{
Matrix44 accumulate;
Matrix44 Bone2Parent;
Bone2Parent = MatrixInverse( &Vector4(), &mesh->bones[bone]->matrix ) * mesh->bones[mesh->bones[bone]->childen]->matrix;
accumulate = animRot2 * (*matrix) * Bone2Parent;
Actor::UpdateAnimation( mesh->bones[bone]->childen, &accumulate, time );
}
}
Here is my Slerp function:
Vector4 Slerp( Vector4 q1, Vector4 q2, float t )
{
// Quaternion to return.
Vector4 qm;
// Calculate angle between them.
float cosHalfTheta = q1.w * q2.w + q1.x * q2.x + q1.y * q2.y + q1.z * q2.z;
if (cosHalfTheta < 0)
{
q2.w = -q2.w; q2.x = -q2.x; q2.y = -q2.y; q2.z = q2.z;
cosHalfTheta = -cosHalfTheta;
}
// if qa=qb or qa=-qb then theta = 0 and we can return qa
if (abs(cosHalfTheta) >= 1.0f){
qm.w = q1.w;qm.x = q1.x;qm.y = q1.y;qm.z = q1.z;
return qm;
}
// Calculate temporary values.
float halfTheta = acos(cosHalfTheta);
float sinHalfTheta = sqrt(1.0f - cosHalfTheta*cosHalfTheta);
// if theta = 180 degrees then result is not fully defined
// we could rotate around any axis normal to qa or qb
if (fabs(sinHalfTheta) < 0.001){ // fabs is floating point absolute
qm.w = (q1.w * 0.5f + q2.w * 0.5f);
qm.x = (q1.x * 0.5f + q2.x * 0.5f);
qm.y = (q1.y * 0.5f + q2.y * 0.5f);
qm.z = (q1.z * 0.5f + q2.z * 0.5f);
return qm;
}
float ratioA = sinf((1.0f - t) * halfTheta) / sinHalfTheta;
float ratioB = sinf(t * halfTheta) / sinHalfTheta;
//calculate Quaternion.
qm.w = (q1.w * ratioA + q2.w * ratioB);
qm.x = (q1.x * ratioA + q2.x * ratioB);
qm.y = (q1.y * ratioA + q2.y * ratioB);
qm.z = (q1.z * ratioA + q2.z * ratioB);
return qm;
}
Here is my quaternion to matrix function:
Matrix44 MatrixRotationQuaternion( Vector4* q )
{
Matrix44 out;
float xx = q->x * q->x;
float xy = q->x * q->y;
float xz = q->x * q->z;
float xw = q->x * q->w;
float yy = q->y * q->y;
float yz = q->y * q->z;
float yw = q->y * q->w;
float zz = q->z * q->z;
float zw = q->z * q->w;
out._11 = 1 - 2 * ( yy + zz );
out._12 = 2 * ( xy - zw );
out._13 = 2 * ( xz + yw );
out._21 = 2 * ( xy + zw );
out._22 = 1 - 2 * ( xx + zz );
out._23 = 2 * ( yz - xw );
out._31 = 2 * ( xz - yw );
out._32 = 2 * ( yz + xw );
out._33 = 1 - 2 * ( xx + yy );
out._14 = out._24 = out._34 = out._41 = out._42 = out._43 = 0;
out._44 = 1;
return out;
}
Here is the function I use to load the model:
Mesh* MediaLibrary::ImportModel( const std::string& file )
{
if(!file.empty())
{
Mesh* mesh = new Ovgl::Mesh;
// Set media library to this library.
mesh->ml = this;
// Import scene from file.
const aiScene* scene = aiImportFile(file.c_str(), 0);
// Iterate through scene nodes.
for( uint32_t n = 0; n < scene->mRootNode->mNumChildren; n++)
{
// Iterate through meshes of this node.
for( uint32_t sm = 0; sm < scene->mRootNode->mChildren[n]->mNumMeshes; sm++)
{
uint32_t voffset = mesh->vertices.size();
uint32_t foffset = mesh->faces.size();
uint32_t aoffset = 0;
for( uint32_t i = 0; i < mesh->faces.size(); i++ )
{
if( mesh->attributes > aoffset )
{
aoffset = mesh->attributes;
}
}
uint32_t m = scene->mRootNode->mChildren[n]->mMeshes[sm];
Matrix44 matrix;
if(scene->mMeshes[m]->HasBones())
matrix = Ovgl::MatrixTranspose((Matrix44*)&scene->mRootNode->FindNode(scene->mMeshes[m]->mBones[0]->mName)->mTransformation).Translation();
else
matrix = *(Matrix44*)&scene->mRootNode->mChildren[n]->mTransformation.Transpose();
matrix = matrix * MatrixRotationX(1.57f);
if(scene->mMeshes[m]->HasBones())
matrix = matrix * Ovgl::MatrixTranspose((Matrix44*)&scene->mMeshes[m]->mBones[0]->mOffsetMatrix).Translation();
std::vector< std::vector< float > > weights(scene->mMeshes[m]->mNumVertices);
std::vector< std::vector< float > > indices(scene->mMeshes[m]->mNumVertices);
std::vector< Face > faces;
std::vector< uint32_t > attributes;
mesh->vertices.resize( voffset + scene->mMeshes[m]->mNumVertices);
// Get skeleton.
if(scene->mMeshes[m]->HasBones())
{
for( uint32_t b = 0; b < scene->mMeshes[m]->mNumBones; b++ )
{
Bone* bone = new Bone;
mesh->bones.push_back(bone);
bone->length = 1.0f;
bone->mesh = new Mesh;
bone->convex = NULL;
aiNode* bnode = scene->mRootNode->FindNode(scene->mMeshes[m]->mBones->mName);
aiMatrix4x4 GlobalTransform = bnode->mTransformation;
aiNode* parent = bnode->mParent;
while( parent->mParent != scene->mRootNode )
{
GlobalTransform = parent->mTransformation * GlobalTransform;
parent = parent->mParent;
}
bone->matrix = Ovgl::MatrixTranspose((Matrix44*)&GlobalTransform)* MatrixRotationX(1.57f);
// Get bone hierarchy.
for( uint32_t cb = 0; cb < bnode->mNumChildren; cb++ )
{
for( uint32_t mb = 0; mb < scene->mMeshes[m]->mNumBones; mb++ )
{
if( bnode->mParent->mName == scene->mMeshes[m]->mBones[mb]->mName )
{
bone->parent = mb;
}
if( bnode->mChildren[cb]->mName == scene->mMeshes[m]->mBones[mb]->mName )
{
bone->childen.push_back(mb);
}
}
}
for (uint32_t w = 0 ; w < scene->mMeshes[m]->mBones->mNumWeights; w++)
{
weights[scene->mMeshes[m]->mBones->mWeights[w].mVertexId].push_back((float)scene->mMeshes[m]->mBones->mWeights[w].mWeight);
indices[scene->mMeshes[m]->mBones->mWeights[w].mVertexId].push_back((float)b);
}
// Get animation for this bone.
for( uint32_t a = 0; a < scene->mNumAnimations; a++ )
{
for( uint32_t ac = 0; ac < scene->mAnimations[a]->mNumChannels; ac++ )
{
if(scene->mAnimations[a]->mChannels[ac]->mNodeName == scene->mMeshes[m]->mBones->mName)
{
for( uint32_t rk = 0; rk < scene->mAnimations[a]->mChannels[ac]->mNumRotationKeys; rk++ )
{
scene->mAnimations[a]->mChannels[ac]->mPreState = aiAnimBehaviour_LINEAR;
Ovgl::Curve curve;
curve.time = scene->mAnimations[a]->mChannels[ac]->mRotationKeys[rk].mTime;
curve.value.w = scene->mAnimations[a]->mChannels[ac]->mRotationKeys[rk].mValue.w;
curve.value.x = scene->mAnimations[a]->mChannels[ac]->mRotationKeys[rk].mValue.x;
curve.value.y = scene->mAnimations[a]->mChannels[ac]->mRotationKeys[rk].mValue.y;
curve.value.z = scene->mAnimations[a]->mChannels[ac]->mRotationKeys[rk].mValue.z;
mesh->bones->Rot_Keys.push_back( curve );
}
}
}
}
}
}
// Cap off bone influences to no more than 4.
for ( uint32_t w = 0; w < scene->mMeshes[m]->mNumVertices; w++)
{
weights[w].resize(4);
indices[w].resize(4);
if(!scene->mMeshes[m]->HasBones())
weights[w][0] = 1.0f;
}
// Get geometry.
for( uint32_t f = 0; f < scene->mMeshes[m]->mNumFaces; f++ )
{
uint32_t findices[4];
for( uint32_t i = 0; i < scene->mMeshes[m]->mFaces[f].mNumIndices; i++ )
{
int vi = scene->mMeshes[m]->mFaces[f].mIndices;
Vertex vertex;
vertex.position.x = scene->mMeshes[m]->mVertices[vi].x;
vertex.position.y = scene->mMeshes[m]->mVertices[vi].y;
vertex.position.z = scene->mMeshes[m]->mVertices[vi].z;
vertex.position = Vector3Transform(&vertex.position, &matrix);
vertex.normal.x = scene->mMeshes[m]->mNormals[vi].x;
vertex.normal.y = scene->mMeshes[m]->mNormals[vi].y;
vertex.normal.z = scene->mMeshes[m]->mNormals[vi].z;
vertex.normal = Vector3Transform(&vertex.normal, &matrix.Rotation());
if(scene->mMeshes[m]->GetNumUVChannels() > 0)
{
vertex.texture.x = scene->mMeshes[m]->mTextureCoords[0][vi].x;
vertex.texture.y = scene->mMeshes[m]->mTextureCoords[0][vi].y;
}
else
{
vertex.texture.x = 0.0f;
vertex.texture.y = 0.0f;
}
vertex.weight[0] = weights[vi][0];
vertex.weight[1] = weights[vi][1];
vertex.weight[2] = weights[vi][2];
vertex.weight[3] = weights[vi][3];
vertex.indices[0] = indices[vi][0];
vertex.indices[1] = indices[vi][1];
vertex.indices[2] = indices[vi][2];
vertex.indices[3] = indices[vi][3];
findices = (uint32_t)vi + voffset;
mesh->vertices[vi+voffset] = vertex;
}
if(scene->mMeshes[m]->mFaces[f].mNumIndices == 4)
{
Face face;
face.indices[0] = findices[0];
face.indices[1] = findices[2];
face.indices[2] = findices[3];
mesh->faces.push_back( face );
mesh->attributes.push_back(scene->mMeshes[m]->mMaterialIndex);
}
Face face;
face.indices[0] = findices[0];
face.indices[1] = findices[1];
face.indices[2] = findices[2];
mesh->faces.push_back( face );
mesh->attributes.push_back(scene->mMeshes[m]->mMaterialIndex);
}
}
}
// If no bones exist create one.
if(mesh->bones.size() == 0 )
{
Bone* bone = new Bone;
bone->matrix = MatrixIdentity();
bone->length = 1.0f;
bone->mesh = new Mesh;
bone->convex = NULL;
mesh->bones.push_back(bone);
}
// Save vertices which influence each bone for bone shape automatic generation.
for( uint32_t i = 0; i < mesh->bones.size(); i++ )
{
for( uint32_t v = 0; v < mesh->vertices.size(); v++ )
{
for( uint32_t j = 0; j < 4; j++)
{
if(mesh->vertices[v].indices[j] == i && mesh->vertices[v].weight[j] > 0.1f)
{
Vertex Vertex;
Vertex.position = Vector3Transform( &mesh->vertices[v].position, &MatrixInverse( &Vector4( 0.0f, 0.0f, 0.0f, 0.0f ), &mesh->bones->matrix));
Vertex.weight[0] = 1.0f;
mesh->bones->mesh->vertices.push_back( Vertex );
}
}
}
}
// Null index and vertex buffers.
mesh->VertexBuffer = 0;
mesh->IndexBuffers = 0;
// Update video memory copies of index and vertex buffers.
mesh->Update();
Meshes.push_back( mesh );
return mesh;
}
// Function failed so return NULL.
return NULL;
}
If anyone can help me figure this out they will be my hero!!!