Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "Headers/AnimationController.h"
- #include "Core/Math/Headers/Quaternion.h"
- #include "Hardware/Video/GFXDevice.h"
- #include <assimp/scene.h>
- using namespace boost;
- /// there is some type of alignment issue with my mat4 and the aimatrix4x4 class, so the copy must be manually
- void TransformMatrix(mat4<F32>& out,const aiMatrix4x4& in){
- if(GFX_DEVICE.getApi() == Direct3D){
- out.element(1,1)=in.a1; out.element(2,1)=in.b1; out.element(3,1)=in.c1; out.element(4,1)=in.d1;
- out.element(1,2)=in.a2; out.element(2,2)=in.b2; out.element(3,2)=in.c2; out.element(4,2)=in.d2;
- out.element(1,3)=in.a3; out.element(2,3)=in.b3; out.element(3,3)=in.c3; out.element(4,3)=in.d3;
- out.element(1,4)=in.a4; out.element(2,4)=in.b4; out.element(3,4)=in.c4; out.element(4,4)=in.d4;
- }else{
- memcpy(out.mat,&in,sizeof(F32) * 16);
- }
- }
- mat4<F32> MultiplyMatAPIDependent(mat4<F32>& a, mat4<F32>& b){
- mat4<F32> ret;
- (GFX_DEVICE.getApi() == Direct3D) ? ret = a * b : ret = b * a;
- return ret;
- }
- // ------------------------------------------------------------------------------------------------
- /// Evaluates the animation tracks for a given time stamp.
- void AnimationEvaluator::Evaluate( F32 pTime,unordered_map<std::string, Bone*>& bones) {
- pTime *= TicksPerSecond;
- F32 time = 0.0f;
- if( Duration > 0.0)
- time = fmod( pTime, Duration);
- // calculate the transformations for each animation channel
- for( U32 a = 0; a < Channels.size(); a++){
- const AnimationChannel* channel = &Channels[a];
- unordered_map<std::string, Bone*>::iterator bonenode = bones.find(channel->Name);
- if(bonenode == bones.end()) {
- D_PRINT_FN("did not find the bone node [ %s ]",channel->Name.c_str());
- continue;
- }
- // ******** Position *****
- aiVector3D presentPosition( 0, 0, 0);
- if( channel->mPositionKeys.size() > 0){
- // Look for present frame number.
- //Search from last position if time is after the last time, else from beginning
- // Should be much quicker than always looking from start for the average use case.
- U32 frame = (time >= mLastTime) ? tuple_get_impl<0>(mLastPositions[a]): 0;
- while( frame < channel->mPositionKeys.size() - 1){
- if( time < channel->mPositionKeys[frame+1].mTime){
- break;
- }
- frame++;
- }
- // interpolate between this frame's value and next frame's value
- U32 nextFrame = (frame + 1) % channel->mPositionKeys.size();
- const aiVectorKey& key = channel->mPositionKeys[frame];
- const aiVectorKey& nextKey = channel->mPositionKeys[nextFrame];
- D32 diffTime = nextKey.mTime - key.mTime;
- if( diffTime < 0.0)
- diffTime += Duration;
- if( diffTime > 0) {
- F32 factor = F32( (time - key.mTime) / diffTime);
- presentPosition = key.mValue + (nextKey.mValue - key.mValue) * factor;
- } else {
- presentPosition = key.mValue;
- }
- tuple_get_impl<0>(mLastPositions[a]) = frame;
- }
- // ******** Rotation *********
- aiQuaternion presentRotation( 1, 0, 0, 0);
- if( channel->mRotationKeys.size() > 0)
- {
- U32 frame = (time >= mLastTime) ? tuple_get_impl<1>(mLastPositions[a]) : 0;
- while( frame < channel->mRotationKeys.size() - 1){
- if( time < channel->mRotationKeys[frame+1].mTime)
- break;
- frame++;
- }
- // interpolate between this frame's value and next frame's value
- U32 nextFrame = (frame + 1) % channel->mRotationKeys.size() ;
- const aiQuatKey& key = channel->mRotationKeys[frame];
- const aiQuatKey& nextKey = channel->mRotationKeys[nextFrame];
- D32 diffTime = nextKey.mTime - key.mTime;
- if( diffTime < 0.0) diffTime += Duration;
- if( diffTime > 0) {
- F32 factor = F32( (time - key.mTime) / diffTime);
- aiQuaternion::Interpolate( presentRotation, key.mValue,
- nextKey.mValue, factor);
- } else presentRotation = key.mValue;
- tuple_get_impl<1>(mLastPositions[a]) = frame;
- }
- // ******** Scaling **********
- aiVector3D presentScaling( 1, 1, 1);
- if( channel->mScalingKeys.size() > 0) {
- U32 frame = (time >= mLastTime) ? tuple_get_impl<2>(mLastPositions[a]) : 0;
- while( frame < channel->mScalingKeys.size() - 1){
- if( time < channel->mScalingKeys[frame+1].mTime)
- break;
- frame++;
- }
- presentScaling = channel->mScalingKeys[frame].mValue;
- tuple_get_impl<2>(mLastPositions[a]) = frame;
- }
- aiMatrix4x4 mat = aiMatrix4x4( presentRotation.GetMatrix());
- mat.a1 *= presentScaling.x; mat.b1 *= presentScaling.x; mat.c1 *= presentScaling.x;
- mat.a2 *= presentScaling.y; mat.b2 *= presentScaling.y; mat.c2 *= presentScaling.y;
- mat.a3 *= presentScaling.z; mat.b3 *= presentScaling.z; mat.c3 *= presentScaling.z;
- mat.a4 = presentPosition.x; mat.b4 = presentPosition.y; mat.c4 = presentPosition.z;
- /// Transpose matrix for D3D
- if(GFX_DEVICE.getApi() == Direct3D){
- mat.Transpose();
- }
- TransformMatrix(bonenode->second->_localTransform, mat);
- }
- mLastTime = time;
- }
- /// this will build the skeleton based on the scene passed to it and CLEAR EVERYTHING
- void AnimationController::Init(const aiScene* pScene){
- if(!pScene->HasAnimations()) return;
- Release();
- Skeleton = CreateBoneTree( pScene->mRootNode, NULL);
- ExtractAnimations(pScene);
- for (U32 i = 0; i < pScene->mNumMeshes;++i){
- const aiMesh* mesh = pScene->mMeshes[i];
- //Skip points and lines ... for now -Ionut
- //ToDo: Fix this -Ionut
- if(mesh->mPrimitiveTypes == aiPrimitiveType_LINE ||
- mesh->mPrimitiveTypes == aiPrimitiveType_POINT ||
- mesh->mNumVertices == 0)
- continue;
- for (U32 n = 0; n < mesh->mNumBones;++n){
- const aiBone* bone = mesh->mBones[n];
- unordered_map<std::string, Bone*>::iterator found = BonesByName.find(bone->mName.data);
- if(found != BonesByName.end()){// FOUND IT!!! woohoo, make sure its not already in the bone list
- bool skip = false;
- for(size_t j(0); j< Bones.size(); j++){
- std::string bname = bone->mName.data;
- if(Bones[j]->_name == bname) {
- // already inserted
- skip = true;
- break;
- }
- }
- if(!skip){// only insert the bone if it has not already been inserted
- std::string tes = found->second->_name;
- TransformMatrix(found->second->_offset, bone->mOffsetMatrix);
- ///Transpose for D3D
- if(GFX_DEVICE.getApi() == Direct3D){
- // transpose their matrix to get in the correct format
- found->second->_offset.transpose(found->second->_offset);
- }
- Bones.push_back(found->second);
- }
- }
- }
- }
- Transforms.resize( Bones.size());
- F32 timestep = 1.0f/30.0f;// 30 per second
- for(size_t i(0); i< Animations.size(); i++){// pre calculate the animations
- SetAnimIndex(i);
- F32 dt = 0;
- for(F32 ticks = 0; ticks < Animations[i].Duration;
- ticks += Animations[i].TicksPerSecond/30.0f){
- dt +=timestep;
- Calculate(dt);
- Animations[i].Transforms.push_back(std::vector<mat4<F32> >());
- std::vector<mat4<F32> >& trans = Animations[i].Transforms.back();
- for( size_t a = 0; a < Transforms.size(); ++a){
- mat4<F32> rotationmat = MultiplyMatAPIDependent(Bones[a]->_offset,Bones[a]->_globalTransform);
- trans.push_back(rotationmat);
- }
- }
- }
- D_PRINT_FN("Finished loading animations with [ %d ] bones", Bones.size());
- }
- // ------------------------------------------------------------------------------------------------
- /// Calculates the bone matrices for the given mesh.
- void AnimationController::CalcBoneMatrices(){
- for( size_t a = 0; a < Transforms.size(); ++a){
- Transforms[a] = MultiplyMatAPIDependent(Bones[a]->_offset, Bones[a]->_globalTransform);
- /*
- mat4<F32> rotationmat = Transforms[a];
- quat q;
- q.frommatrix(rotationmat);
- vec4<F32> dual[2] ;
- UQTtoUDQ( dual, q, Transforms[a].row3_v);
- QuatTransforms[a].row0_v =dual[0];
- QuatTransforms[a].row1_v =dual[1];
- */
- }
- }
- // ------------------------------------------------------------------------------------------------
- /// Recursively creates an internal node structure matching the current scene and animation.
- Bone* AnimationController::CreateBoneTree( aiNode* pNode, Bone* pParent){
- Bone* internalNode = New Bone();// create a node
- internalNode->_name = pNode->mName.data;// get the name of the bone
- //set the parent, in the case this is theroot node, it will be null
- internalNode->_parent = pParent;
- BonesByName[internalNode->_name] = internalNode;// use the name as a key
- TransformMatrix(internalNode->_localTransform, pNode->mTransformation);
- ///Transpose for D3D
- if(GFX_DEVICE.getApi() == Direct3D){
- internalNode->_localTransform.transpose(internalNode->_localTransform);
- }
- internalNode->_originalLocalTransform = internalNode->_localTransform;// a copy saved
- CalculateBoneToWorldTransform(internalNode);
- // continue for all child nodes and assign the created internal nodes as our children
- for( U32 a = 0; a < pNode->mNumChildren; a++){// recursivly call this function on all children
- internalNode->_children.push_back(CreateBoneTree( pNode->mChildren[a], internalNode));
- }
- return internalNode;
- }
- // ------------------------------------------------------------------------------------------------
- /// Calculates the global transformation matrix for the given internal node
- void AnimationController::CalculateBoneToWorldTransform(Bone* child){
- child->_globalTransform = child->_localTransform;
- Bone* parent = child->_parent;
- while( parent ){// this will climb the nodes up along through the parents concentating all the matrices to get the Object to World transform, or in this case, the Bone To World transform
- ///For OpenGL : _global = _global * _local;
- ///For Direct3D: _global = _local * _global;
- child->_globalTransform = MultiplyMatAPIDependent(parent->_localTransform,child->_globalTransform);
- parent = parent->_parent;// get the parent of the bone we are working on
- }
- }
- ////--------------------------------- SHADER CODE --------------------///
- ///w - weight value
- float finalWeight = 1.0f - ( boneWeight.x + boneWeight.y + boneWeight.z );
- mat4 matTransform = boneTransforms[int(boneIndex.x)] * boneWeight.x;
- matTransform += boneTransforms[int(boneIndex.y)] * boneWeight.y;
- matTransform += boneTransforms[int(boneIndex.z)] * boneWeight.z;
- matTransform += boneTransforms[int(boneIndex.w)] * finalWeight;
- position = mul( matTransform, position);
- normal = mul( matTransform, vec4(normal.xyz,0.0));
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement