ofVec3f AssimpUtils::getAnimatedObjectPosition(ofxAssimpModelLoader &model){ ofxAssimpAnimation &animation = model.getAnimation(0); const aiNodeAnim * channel = animation.getAnimation()->mChannels[0]; float progressInSeconds = animation.getPositionInSeconds(); aiVector3D presentPosition(0, 0, 0); if(channel->mNumPositionKeys > 0) { unsigned int frame = 0; while(frame < channel->mNumPositionKeys - 1) { if(progressInSeconds < channel->mPositionKeys[frame+1].mTime) { break; } frame++; } unsigned int nextFrame = (frame + 1) % channel->mNumPositionKeys; const aiVectorKey & key = channel->mPositionKeys[frame]; const aiVectorKey & nextKey = channel->mPositionKeys[nextFrame]; double diffTime = nextKey.mTime - key.mTime; if(diffTime < 0.0) { diffTime += animation.getDurationInSeconds(); } if(diffTime > 0) { float factor = float((progressInSeconds - key.mTime) / diffTime); presentPosition = key.mValue + (nextKey.mValue - key.mValue) * factor; } else { presentPosition = key.mValue; } } return ofVec3f(presentPosition.x, presentPosition.y, presentPosition.z); }
// ------------------------------------------------------------------------------------------------ // Evaluates the animation tracks for a given time stamp. void cAnimEvaluator::Evaluate( float pTime, std::map<std::string, cBone*>& bones) { pTime *= TicksPerSecond; float time = 0.0f; if( Duration > 0.0) time = fmod( pTime, Duration); // calculate the transformations for each animation channel for( unsigned int a = 0; a < Channels.size(); a++){ const cAnimationChannel* channel = &Channels[a]; std::map<std::string, cBone*>::iterator bonenode = bones.find(channel->Name); if(bonenode == bones.end()) { OUTPUT_DEBUG_MSG("did not find the bone node "<<channel->Name); 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. unsigned int frame = (time >= mLastTime) ? std::get<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 unsigned int nextFrame = (frame + 1) % channel->mPositionKeys.size(); const aiVectorKey& key = channel->mPositionKeys[frame]; const aiVectorKey& nextKey = channel->mPositionKeys[nextFrame]; double diffTime = nextKey.mTime - key.mTime; if( diffTime < 0.0) diffTime += Duration; if( diffTime > 0) { float factor = float( (time - key.mTime) / diffTime); presentPosition = key.mValue + (nextKey.mValue - key.mValue) * factor; } else { presentPosition = key.mValue; } std::get<0>(mLastPositions[a]) = frame; } // ******** Rotation ********* aiQuaternion presentRotation( 1, 0, 0, 0); if( channel->mRotationKeys.size() > 0) { unsigned int frame = (time >= mLastTime) ? std::get<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 unsigned int nextFrame = (frame + 1) % channel->mRotationKeys.size() ; const aiQuatKey& key = channel->mRotationKeys[frame]; const aiQuatKey& nextKey = channel->mRotationKeys[nextFrame]; double diffTime = nextKey.mTime - key.mTime; if( diffTime < 0.0) diffTime += Duration; if( diffTime > 0) { float factor = float( (time - key.mTime) / diffTime); aiQuaternion::Interpolate( presentRotation, key.mValue, nextKey.mValue, factor); } else presentRotation = key.mValue; std::get<1>(mLastPositions[a]) = frame; } // ******** Scaling ********** aiVector3D presentScaling( 1, 1, 1); if( channel->mScalingKeys.size() > 0) { unsigned int frame = (time >= mLastTime) ? std::get<2>(mLastPositions[a]) : 0; while( frame < channel->mScalingKeys.size() - 1){ if( time < channel->mScalingKeys[frame+1].mTime) break; frame++; } presentScaling = channel->mScalingKeys[frame].mValue; std::get<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; mat.Transpose(); TransformMatrix(bonenode->second->LocalTransform, mat); } mLastTime = time; }
void ofxAssimpAnimation::updateAnimationNodes() { for(unsigned int i=0; i<animation->mNumChannels; i++) { const aiNodeAnim * channel = animation->mChannels[i]; aiNode * targetNode = scene->mRootNode->FindNode(channel->mNodeName); aiVector3D presentPosition(0, 0, 0); if(channel->mNumPositionKeys > 0) { unsigned int frame = 0; while(frame < channel->mNumPositionKeys - 1) { if(progressInSeconds < channel->mPositionKeys[frame+1].mTime) { break; } frame++; } unsigned int nextFrame = (frame + 1) % channel->mNumPositionKeys; const aiVectorKey & key = channel->mPositionKeys[frame]; const aiVectorKey & nextKey = channel->mPositionKeys[nextFrame]; double diffTime = nextKey.mTime - key.mTime; if(diffTime < 0.0) { diffTime += getDurationInSeconds(); } if(diffTime > 0) { float factor = float((progressInSeconds - key.mTime) / diffTime); presentPosition = key.mValue + (nextKey.mValue - key.mValue) * factor; } else { presentPosition = key.mValue; } } aiQuaternion presentRotation(1, 0, 0, 0); if(channel->mNumRotationKeys > 0) { unsigned int frame = 0; while(frame < channel->mNumRotationKeys - 1) { if(progressInSeconds < channel->mRotationKeys[frame+1].mTime) { break; } frame++; } unsigned int nextFrame = (frame + 1) % channel->mNumRotationKeys; const aiQuatKey& key = channel->mRotationKeys[frame]; const aiQuatKey& nextKey = channel->mRotationKeys[nextFrame]; double diffTime = nextKey.mTime - key.mTime; if(diffTime < 0.0) { diffTime += getDurationInSeconds(); } if(diffTime > 0) { float factor = float((progressInSeconds - key.mTime) / diffTime); aiQuaternion::Interpolate(presentRotation, key.mValue, nextKey.mValue, factor); } else { presentRotation = key.mValue; } } aiVector3D presentScaling(1, 1, 1); if(channel->mNumScalingKeys > 0) { unsigned int frame = 0; while(frame < channel->mNumScalingKeys - 1){ if(progressInSeconds < channel->mScalingKeys[frame+1].mTime) { break; } frame++; } presentScaling = channel->mScalingKeys[frame].mValue; } 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; targetNode->mTransformation = mat; } }
//------------------------------------------- void ofxAssimpModelLoader::updateAnimation(unsigned int animationIndex, float currentTime){ const aiAnimation* mAnim = scene->mAnimations[animationIndex]; // calculate the transformations for each animation channel for( unsigned int a = 0; a < mAnim->mNumChannels; a++) { const aiNodeAnim* channel = mAnim->mChannels[a]; aiNode* targetNode = scene->mRootNode->FindNode(channel->mNodeName); // ******** Position ***** aiVector3D presentPosition( 0, 0, 0); if( channel->mNumPositionKeys > 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. unsigned int frame = 0;// (currentTime >= lastAnimationTime) ? lastFramePositionIndex : 0; while( frame < channel->mNumPositionKeys - 1) { if( currentTime < channel->mPositionKeys[frame+1].mTime) break; frame++; } // interpolate between this frame's value and next frame's value unsigned int nextFrame = (frame + 1) % channel->mNumPositionKeys; const aiVectorKey& key = channel->mPositionKeys[frame]; const aiVectorKey& nextKey = channel->mPositionKeys[nextFrame]; double diffTime = nextKey.mTime - key.mTime; if( diffTime < 0.0) diffTime += mAnim->mDuration; if( diffTime > 0) { float factor = float( (currentTime - key.mTime) / diffTime); presentPosition = key.mValue + (nextKey.mValue - key.mValue) * factor; } else { presentPosition = key.mValue; } } // ******** Rotation ********* aiQuaternion presentRotation( 1, 0, 0, 0); if( channel->mNumRotationKeys > 0) { unsigned int frame = 0;//(currentTime >= lastAnimationTime) ? lastFrameRotationIndex : 0; while( frame < channel->mNumRotationKeys - 1) { if( currentTime < channel->mRotationKeys[frame+1].mTime) break; frame++; } // interpolate between this frame's value and next frame's value unsigned int nextFrame = (frame + 1) % channel->mNumRotationKeys; const aiQuatKey& key = channel->mRotationKeys[frame]; const aiQuatKey& nextKey = channel->mRotationKeys[nextFrame]; double diffTime = nextKey.mTime - key.mTime; if( diffTime < 0.0) diffTime += mAnim->mDuration; if( diffTime > 0) { float factor = float( (currentTime - key.mTime) / diffTime); aiQuaternion::Interpolate( presentRotation, key.mValue, nextKey.mValue, factor); } else { presentRotation = key.mValue; } } // ******** Scaling ********** aiVector3D presentScaling( 1, 1, 1); if( channel->mNumScalingKeys > 0) { unsigned int frame = 0;//(currentTime >= lastAnimationTime) ? lastFrameScaleIndex : 0; while( frame < channel->mNumScalingKeys - 1) { if( currentTime < channel->mScalingKeys[frame+1].mTime) break; frame++; } // TODO: (thom) interpolation maybe? This time maybe even logarithmic, not linear presentScaling = channel->mScalingKeys[frame].mValue; } // build a transformation matrix from it //aiMatrix4x4& mat;// = mTransforms[a]; 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; //mat.Transpose(); targetNode->mTransformation = mat; } lastAnimationTime = currentTime; // update mesh position for the animation for (unsigned int i = 0; i < modelMeshes.size(); ++i){ // current mesh we are introspecting const aiMesh* mesh = modelMeshes[i].mesh; // calculate bone matrices std::vector<aiMatrix4x4> boneMatrices( mesh->mNumBones); for( size_t a = 0; a < mesh->mNumBones; ++a) { const aiBone* bone = mesh->mBones[a]; // find the corresponding node by again looking recursively through the node hierarchy for the same name aiNode* node = scene->mRootNode->FindNode(bone->mName); // start with the mesh-to-bone matrix boneMatrices[a] = bone->mOffsetMatrix; // and now append all node transformations down the parent chain until we're back at mesh coordinates again const aiNode* tempNode = node; while( tempNode) { // check your matrix multiplication order here!!! boneMatrices[a] = tempNode->mTransformation * boneMatrices[a]; // boneMatrices[a] = boneMatrices[a] * tempNode->mTransformation; tempNode = tempNode->mParent; } modelMeshes[i].hasChanged = true; modelMeshes[i].validCache = false; } modelMeshes[i].animatedPos.assign(modelMeshes[i].animatedPos.size(),0); if(mesh->HasNormals()){ modelMeshes[i].animatedNorm.assign(modelMeshes[i].animatedNorm.size(),0); } // loop through all vertex weights of all bones for( size_t a = 0; a < mesh->mNumBones; ++a) { const aiBone* bone = mesh->mBones[a]; const aiMatrix4x4& posTrafo = boneMatrices[a]; for( size_t b = 0; b < bone->mNumWeights; ++b) { const aiVertexWeight& weight = bone->mWeights[b]; size_t vertexId = weight.mVertexId; const aiVector3D& srcPos = mesh->mVertices[vertexId]; modelMeshes[i].animatedPos[vertexId] += weight.mWeight * (posTrafo * srcPos); } if(mesh->HasNormals()){ // 3x3 matrix, contains the bone matrix without the translation, only with rotation and possibly scaling aiMatrix3x3 normTrafo = aiMatrix3x3( posTrafo); for( size_t b = 0; b < bone->mNumWeights; ++b) { const aiVertexWeight& weight = bone->mWeights[b]; size_t vertexId = weight.mVertexId; const aiVector3D& srcNorm = mesh->mNormals[vertexId]; modelMeshes[i].animatedNorm[vertexId] += weight.mWeight * (normTrafo * srcNorm); } } } } }
void AnimEvaluator::Evaluate( float pTime, std::map<std::string, SkinData::Bone*>& bones ) { pTime *= mTicksPerSecond; float time = 0.0f; if (mDuration > 0.0) time = fmod(pTime, mDuration); // Calculate transformations for each channel for (UINT i = 0; i < Channels.size(); ++i) { const SkinData::AnimationChannel* channel = &Channels[i]; std::map<std::string, SkinData::Bone*>::iterator boneNode = bones.find(channel->Name); // Did not find bone node if (boneNode == bones.end()) continue; //--------------------------------------------- // Position //--------------------------------------------- aiVector3D presentPosition(0, 0, 0); if (channel->PositionKeys.size() > 0) { // Look for present frame number UINT frame = (time >= mLastTime) ? std::get<0>(mLastPositions[i]) : 0; while (frame < channel->PositionKeys.size() - 1) { if (time < channel->PositionKeys[frame+1].mTime) break; frame++; } // Interpolate between this frame's value and the next frame's value UINT nextFrame = (frame + 1) % channel->PositionKeys.size(); const aiVectorKey& key = channel->PositionKeys[frame]; const aiVectorKey& nextKey = channel->PositionKeys[nextFrame]; double diffTime = nextKey.mTime - key.mTime; if (diffTime < 0.0) diffTime += mDuration; if (diffTime > 0) { float factor = float((time - key.mTime) / diffTime); presentPosition = key.mValue + (nextKey.mValue - key.mValue) * factor; } else { presentPosition = key.mValue; } std::get<0>(mLastPositions[i]) = frame; } //--------------------------------------------- // Rotation //--------------------------------------------- aiQuaternion presentRotation(1, 0, 0, 0); if (channel->RotationKeys.size() > 0) { UINT frame = (time >= mLastTime) ? std::get<1>(mLastPositions[i]) : 0; while (frame < channel->RotationKeys.size() - 1) { if (time < channel->RotationKeys[frame+1].mTime) break; frame++; } UINT nextFrame = (frame + 1) % channel->RotationKeys.size(); const aiQuatKey& key = channel->RotationKeys[frame]; const aiQuatKey& nextKey = channel->RotationKeys[nextFrame]; double diffTime = nextKey.mTime - key.mTime; if (diffTime < 0.0) diffTime += mDuration; if (diffTime > 0) { float factor = float((time - key.mTime) / diffTime); aiQuaternion::Interpolate(presentRotation, key.mValue, nextKey.mValue, factor); } else { presentRotation = key.mValue; } std::get<1>(mLastPositions[i]) = frame; } //--------------------------------------------- // Scaling //--------------------------------------------- aiVector3D presentScaling(1, 1, 1); if (channel->ScalingKeys.size() > 0) { UINT frame = (time >= mLastTime) ? std::get<2>(mLastPositions[i]) : 0; while (frame < channel->ScalingKeys.size() - 1) { if (time < channel->ScalingKeys[frame+1].mTime) break; frame++; } presentScaling = channel->ScalingKeys[frame].mValue; std::get<2>(mLastPositions[i]) = 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; mat.Transpose(); SkinData::ReadAiMatrix(boneNode->second->LocalTransform, mat); } // Channel end mLastTime = time; }