If you haven't done so already, be sure to visit the Wiki Portal to read about how the wiki works. Especially the Ogre Wiki Overview page.
Table of contents
Introduction
To blend is to fade between two states. In the animation process it allows to create a transition between two animations. With this sample code, you can blend animations in 3 ways:
- BlendSwitch: just switch to the second/destination animation (stop the first/source and start the second).
- BlendWhileAnimating: cross-fade, blend source animation out while blending destination animation in.
- BlendThenAnimate: pick source's current frame and blend it with destination's first frame.
Here is a Mogre port: MOGRE AnimationBlender
Source Code
AnimationBlender.h
class AnimationBlender { public: enum BlendingTransition { BlendSwitch, // stop source and start dest BlendWhileAnimating, // cross fade, blend source animation out while blending destination animation in BlendThenAnimate // blend source to first frame of dest, when done, start dest anim }; private: Entity *mEntity; AnimationState *mSource; AnimationState *mTarget; BlendingTransition mTransition; bool loop; ~AnimationBlender() {} public: Real mTimeleft, mDuration; bool complete; void blend( const String &animation, BlendingTransition transition, Real duration, bool l=true ); void addTime( Real ); Real getProgress() { return mTimeleft/ mDuration; } AnimationState *getSource() { return mSource; } AnimationState *getTarget() { return mTarget; } AnimationBlender( Entity *); void init( const String &animation, bool l=true ); };
AnimationBlender.cpp
void AnimationBlender::init(const String &animation, bool l) { AnimationStateSet *set = mEntity->getAllAnimationStates(); AnimationStateSet::iterator it = set->begin(); while(it != set->end()) { AnimationState &anim = it->second; anim.setEnabled(false); anim.setWeight(0); anim.setTimePosition(0); ++it; } mSource = mEntity->getAnimationState( animation ); mSource->setEnabled(true); mSource->setWeight(1); mTimeleft = 0; mDuration = 1; mTarget = 0; complete = false; loop = l; } void AnimationBlender::blend( const String &animation, BlendingTransition transition, Real duration, bool l ) { loop = l; if( transition == AnimationBlender::BlendSwitch ) { if( mSource != 0 ) mSource->setEnabled(false); mSource = mEntity->getAnimationState( animation ); mSource->setEnabled(true); mSource->setWeight(1); mSource->setTimePosition(0); mTimeleft = 0; } else { AnimationState *newTarget = mEntity->getAnimationState( animation ); if( mTimeleft > 0 ) { // oops, weren't finished yet if( newTarget == mTarget ) { // nothing to do! (ignoring duration here) } else if( newTarget == mSource ) { // going back to the source state, so let's switch mSource = mTarget; mTarget = newTarget; mTimeleft = mDuration - mTimeleft; // i'm ignoring the new duration here } else { // ok, newTarget is really new, so either we simply replace the target with this one, or // we make the target the new source if( mTimeleft < mDuration * 0.5 ) { // simply replace the target with this one mTarget->setEnabled(false); mTarget->setWeight(0); } else { // old target becomes new source mSource->setEnabled(false); mSource->setWeight(0); mSource = mTarget; } mTarget = newTarget; mTarget->setEnabled(true); mTarget->setWeight( 1.0 - mTimeleft / mDuration ); mTarget->setTimePosition(0); } } else { // assert( target == 0, "target should be 0 when not blending" ) // mSource->setEnabled(true); // mSource->setWeight(1); mTransition = transition; mTimeleft = mDuration = duration; mTarget = newTarget; mTarget->setEnabled(true); mTarget->setWeight(0); mTarget->setTimePosition(0); } } } void AnimationBlender::addTime( Real time ) { if( mSource != 0 ) { if( mTimeleft > 0 ) { mTimeleft -= time; if( mTimeleft < 0 ) { // finish blending mSource->setEnabled(false); mSource->setWeight(0); mSource = mTarget; mSource->setEnabled(true); mSource->setWeight(1); mTarget = 0; } else { // still blending, advance weights mSource->setWeight(mTimeleft / mDuration); mTarget->setWeight(1.0 - mTimeleft / mDuration); if(mTransition == AnimationBlender::BlendWhileAnimating) mTarget->addTime(time); } } if (mSource->getTimePosition() >= mSource->getLength()) { complete=true; } else { complete=false; } mSource->addTime(time); mSource->setLoop(loop); } } AnimationBlender::AnimationBlender( Entity *entity ) : mEntity(entity) { }
AnimationBlender.cpp for Ogre 1.2 (minor changes)
void AnimationBlender::init(const String &animation, bool l) { AnimationStateSet *set = mEntity->getAllAnimationStates(); AnimationStateIterator it = set->getAnimationStateIterator(); while(it.hasMoreElements()) { AnimationState *anim = it.getNext(); anim->setEnabled(false); anim->setWeight(0); anim->setTimePosition(0); } mSource = mEntity->getAnimationState( animation ); mSource->setEnabled(true); mSource->setWeight(1); mTimeleft = 0; mDuration = 1; mTarget = 0; complete = false; loop = l; } void AnimationBlender::blend( const String &animation, BlendingTransition transition, Real duration, bool l ) { loop = l; if( transition == AnimationBlender::BlendSwitch ) { if( mSource != 0 ) mSource->setEnabled(false); mSource = mEntity->getAnimationState( animation ); mSource->setEnabled(true); mSource->setWeight(1); mSource->setTimePosition(0); mTimeleft = 0; } else { AnimationState *newTarget = mEntity->getAnimationState( animation ); if( mTimeleft > 0 ) { // oops, weren't finished yet if( newTarget == mTarget ) { // nothing to do! (ignoring duration here) } else if( newTarget == mSource ) { // going back to the source state, so let's switch mSource = mTarget; mTarget = newTarget; mTimeleft = mDuration - mTimeleft; // i'm ignoring the new duration here } else { // ok, newTarget is really new, so either we simply replace the target with this one, or // we make the target the new source if( mTimeleft < mDuration * 0.5 ) { // simply replace the target with this one mTarget->setEnabled(false); mTarget->setWeight(0); } else { // old target becomes new source mSource->setEnabled(false); mSource->setWeight(0); mSource = mTarget; } mTarget = newTarget; mTarget->setEnabled(true); mTarget->setWeight( 1.0 - mTimeleft / mDuration ); mTarget->setTimePosition(0); } } else { // assert( target == 0, "target should be 0 when not blending" ) // mSource->setEnabled(true); // mSource->setWeight(1); mTransition = transition; mTimeleft = mDuration = duration; mTarget = newTarget; mTarget->setEnabled(true); mTarget->setWeight(0); mTarget->setTimePosition(0); } } } void AnimationBlender::addTime( Real time ) { if( mSource != 0 ) { if( mTimeleft > 0 ) { mTimeleft -= time; if( mTimeleft < 0 ) { // finish blending mSource->setEnabled(false); mSource->setWeight(0); mSource = mTarget; mSource->setEnabled(true); mSource->setWeight(1); mTarget = 0; } else { // still blending, advance weights mSource->setWeight(mTimeleft / mDuration); mTarget->setWeight(1.0 - mTimeleft / mDuration); if(mTransition == AnimationBlender::BlendWhileAnimating) mTarget->addTime(time); } } if (mSource->getTimePosition() >= mSource->getLength()) { complete = true; } else { complete = false; } mSource->addTime(time); mSource->setLoop(loop); } } AnimationBlender::AnimationBlender( Entity *entity ) : mEntity(entity) { }
Utilisation
To use the functions, you can do something like this:
If you want your character to walk for instance you could do this:
if (!walking) { thePlayer->mAnimationBlender->blend( "Walk",AnimationBlender::BlendWhileAnimating, 0.2, true ); walking=true; } if (mInputDevice->isKeyDown( KC_SPACE ) && !jumping) { jumping=true; thePlayer->mAnimationBlender->blend("Jump",AnimationBlender::BlendWhileAnimating, 0.2, false ); } if (jumping) { if (thePlayer->mAnimationBlender->complete) { thePlayer->mAnimationBlender->blend( "Idle1",AnimationBlender::BlendWhileAnimating, 0.02, true ); jumping=false; } }
Transition Bug
I have noticed that the AnimationBlender dies/freezes (the animation not the application) when the blend function is called between the transition time of the last blend.
I am specifically talking about "BlendWhileAnimating" state here.
Work around posted here:
http://www.ogre3d.org/forums/viewtopic.php?f=2&t=53911&p=366582#p366582
Alias: Talk:AnimationBlender
Contributors to this page: pyritie
,
jacmoe
and
Danoli3
.
Page last modified on Monday 16 of January, 2012 14:11:29 GMT by pyritie
.
The content on this page is licensed under the terms of the Creative Commons Attribution-ShareAlike License.
As an exception, any source code contributed within the content is released into the Public Domain.

