Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- typedef map<string, aiMatrix4x4> Pose;
- class RiggedModel : public ofxAssimpModelLoader {
- protected:
- void updatePose(int which = 0) {
- const aiMesh* mesh = modelMeshes[which].mesh;
- int n = mesh->mNumBones;
- vector<aiMatrix4x4> boneMatrices(n);
- for(int a = 0; a < n; a++) {
- const aiBone* bone = mesh->mBones[a];
- aiNode* node = scene->mRootNode->FindNode(bone->mName);
- boneMatrices[a] = bone->mOffsetMatrix;
- const aiNode* tempNode = node;
- while(tempNode) {
- boneMatrices[a] = tempNode->mTransformation * boneMatrices[a];
- tempNode = tempNode->mParent;
- }
- modelMeshes[which].hasChanged = true;
- modelMeshes[which].validCache = false;
- }
- modelMeshes[which].animatedPos.assign(modelMeshes[which].animatedPos.size(),0);
- if(mesh->HasNormals()){
- modelMeshes[which].animatedNorm.assign(modelMeshes[which].animatedNorm.size(),0);
- }
- // loop through all vertex weights of all bones
- for(int a = 0; a < n; 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[which].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[which].animatedNorm[vertexId] += weight.mWeight * (normTrafo * srcNorm);
- }
- }
- }
- }
- public:
- Pose getPose(int which = 0) {
- const aiMesh* mesh = modelMeshes[which].mesh;
- int n = mesh->mNumBones;
- Pose pose;
- for(int a = 0; a < n; a++) {
- const aiBone* bone = mesh->mBones[a];
- aiNode* node = scene->mRootNode->FindNode(bone->mName);
- pose[node->mName.data] = node->mTransformation;
- }
- return pose;
- }
- void setPose(Pose& pose, int which = 0) {
- // load the pose
- for(Pose::iterator i = pose.begin(); i != pose.end(); i++) {
- const string& name = i->first;
- const aiMatrix4x4& mat = i->second;
- scene->mRootNode->FindNode(name)->mTransformation = mat;
- }
- updatePose(which);
- updateGLResources();
- }
- void 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){
- updatePose(i);
- }
- }
- };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement