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);

				}
			}
		}
	}
}
示例#5
0
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;
}