AnimationBlender - Ogre实现不同动画之间的混合

AnimationBlender - Ogre实现不同动画之间的混合

英文原文: http://test.ogitor.org/tiki/AnimationBlender

动画混合 -- 实现两个动画的切换, 一个动画逐渐消逝, 另一个动画逐渐显示来实现. 主要通过动画状态的权重来实现
通过三种方式来实现两个动画的混合:
    - BlendSwitch - 直接切换至目标动画
    - BlendWhileAnimating - 混合的过程中目标动画也更新帧, 实现动画
    - BlendThenAnimate - 用源动画的当前帧混合目标动画的第一个帧

源码理解, 主要代码位于下面两个函数
AnimationBlender::blend函数 根据传入的参数设置新转换的源动画和目标动画
AnimationBlender::add函数则更新源动画和目标动画(如存在)的状态和权重

AnimationBlender.h 

 1 #ifndef __ANIMATION_BLENDER_H__
 2  #define __ANIMATION_BLENDER_H__
 3 #include <Ogre.h>
 4  using  namespace Ogre;
 5 
 6  class AnimationBlender
 7 {
 8  public:
 9      enum BlendingTransition
10     {
11         BlendSwitch,          //  stop source and start dest
12          BlendWhileAnimating,    //  cross fade, blend source animation out while blending destination animation in
13          BlendThenAnimate       //  blend source to first frame of dest, when done, start dest anim
14      };
15 
16  private:
17     Entity *mEntity;
18     AnimationState *mSource;
19     AnimationState *mTarget;
20 
21     BlendingTransition mTransition;
22 
23      bool loop;
24 
25     ~AnimationBlender() {}
26 
27  public
28     Real mTimeleft, mDuration;
29 
30      bool complete;
31 
32      void blend(  const String &animation, BlendingTransition transition, Real duration,  bool l= true );
33      void addTime( Real );
34     Real getProgress() {  return mTimeleft/ mDuration; }
35     AnimationState *getSource() {  return mSource; }
36     AnimationState *getTarget() {  return mTarget; }
37     AnimationBlender( Entity *);
38      void init(  const String &animation,  bool l= true );
39 };
40 
41  #endif

 

AnimationBlender.cpp 

  1 #include "AnimationBlender.h"
  2 
  3  void AnimationBlender::init( const String &animation,  bool l)
  4 {
  5      //  初始化, 将所有的动画禁止, 只允许参数中的动画运行.
  6      AnimationStateSet * set = mEntity->getAllAnimationStates();
  7     AnimationStateIterator it =  set->getAnimationStateIterator();
  8      while(it.hasMoreElements())
  9     {
 10         AnimationState *anim = it.getNext();
 11         anim->setEnabled( false);
 12         anim->setWeight(0);
 13         anim->setTimePosition(0);
 14     }
 15     mSource = mEntity->getAnimationState( animation );
 16     mSource->setEnabled( true);
 17     mSource->setWeight(1);
 18     mTimeleft = 0;
 19     mDuration = 1;
 20     mTarget = 0;
 21     complete =  false;
 22     loop = l;
 23 } 
 24  void AnimationBlender::blend(  const String &animation, BlendingTransition transition, Real duration,  bool l )
 25 {
 26     loop = l;
 27      if( transition == AnimationBlender::BlendSwitch )
 28     {
 29          if( mSource != 0 )
 30             mSource->setEnabled( false);
 31         mSource = mEntity->getAnimationState( animation );
 32         mSource->setEnabled( true);
 33         mSource->setWeight(1);
 34         mSource->setTimePosition(0);
 35         mTimeleft = 0;
 36     } 
 37      else 
 38     { 
 39         AnimationState *newTarget = mEntity->getAnimationState( animation );
 40          if( mTimeleft > 0 )
 41         {
 42              //  oops, weren't finished yet
 43               if( newTarget == mTarget )
 44             {
 45                  //  nothing to do! (ignoring duration here)
 46              }
 47              else  if( newTarget == mSource )
 48             {
 49                  //  going back to the source state, so let's switch
 50                  mSource = mTarget;
 51                 mTarget = newTarget;
 52                 mTimeleft = mDuration - mTimeleft;  //  i'm ignoring the new duration here
 53              }
 54              else
 55             {
 56                  //  ok, newTarget is really new, so either we simply replace the target with this one, or
 57                   //  we make the target the new source
 58                   if( mTimeleft < mDuration * 0.5 )
 59                 {
 60                      //  simply replace the target with this one
 61                      mTarget->setEnabled( false);
 62                     mTarget->setWeight(0);
 63                 }
 64                  else
 65                 {
 66                      //  old target becomes new source
 67                      mSource->setEnabled( false);
 68                     mSource->setWeight(0);
 69                     mSource = mTarget;
 70                 } 
 71                 mTarget = newTarget;
 72                 mTarget->setEnabled( true);
 73                 mTarget->setWeight( 1.0 - mTimeleft / mDuration );
 74                 mTarget->setTimePosition(0);
 75             }
 76         }
 77          else
 78         {
 79              //  assert( target == 0, "target should be 0 when not blending" )
 80               //  mSource->setEnabled(true);
 81               //  mSource->setWeight(1);
 82              mTransition = transition;
 83             mTimeleft = mDuration = duration;
 84             mTarget = newTarget;
 85             mTarget->setEnabled( true);
 86             mTarget->setWeight(0);
 87             mTarget->setTimePosition(0);
 88         }
 89     }
 90 }
 91  void AnimationBlender::addTime( Real time )
 92 {
 93      if( mSource != 0 )
 94     {
 95          if( mTimeleft > 0 )
 96         {
 97             mTimeleft -= time;
 98              if( mTimeleft < 0 )
 99             {
100                  //  finish blending
101                  mSource->setEnabled( false);
102                 mSource->setWeight(0);
103                 mSource = mTarget;
104                 mSource->setEnabled( true);
105                 mSource->setWeight(1);
106                 mTarget = 0;
107             }
108              else
109             {
110                  //  still blending, advance weights
111                  mSource->setWeight(mTimeleft / mDuration);
112                 mTarget->setWeight(1.0 - mTimeleft / mDuration);
113                  if(mTransition == AnimationBlender::BlendWhileAnimating)
114                     mTarget->addTime(time);
115             }
116         }
117          if (mSource->getTimePosition() >= mSource->getLength())
118         {
119             complete =  true;
120         }
121          else
122         {
123             complete =  false;
124         }
125         mSource->addTime(time);
126         mSource->setLoop(loop);
127     }
128 }
129 AnimationBlender::AnimationBlender( Entity *entity ) : mEntity(entity) 
130 {
131 }
132 

 

AnimationBlenderDemo.h

 1 #ifndef __ANIMATIONBLENDER_DEMO_H__
 2  #define __ANIMATIONBLENDER_DEMO_H__
 3 #include "ExampleApplication.h"
 4 #include "AnimationBlender.h"
 5 
 6  class AnimationBlenderDemoFrameListener :  public ExampleFrameListener
 7 {
 8  protected:
 9     Entity* mNinjaEnt;
10     AnimationBlender* mAnimationBlender;
11      bool walking, jumping;
12  public:
13     AnimationBlenderDemoFrameListener(RenderWindow* mWin, Camera* mCam, Entity* ent)
14         : ExampleFrameListener(mWin, mCam,  falsefalse), mNinjaEnt(ent)
15     {
16         mAnimationBlender =  new AnimationBlender(mNinjaEnt);
17         mAnimationBlender->init("Walk",  true);
18         walking =  false;
19         jumping =  false;
20     }
21 
22      virtual ~AnimationBlenderDemoFrameListener()
23     {
24          if(mAnimationBlender)
25         {
26  //             delete mAnimationBlender;
27          }
28     }
29 
30      bool frameRenderingQueued( const FrameEvent& evt)
31     {
32          if (!ExampleFrameListener::frameRenderingQueued(evt))
33         {
34              return  false;
35         }
36 
37          if (!walking)
38         {
39             mAnimationBlender->blend( "Walk",AnimationBlender::BlendWhileAnimating, 0.2,  true );
40             walking= true;
41         }
42          if (mKeyboard->isKeyDown( OIS::KC_SPACE ) && !jumping)
43         {
44             jumping= true;
45             mAnimationBlender->blend("Jump",AnimationBlender::BlendWhileAnimating, 0.2,  false );
46         }
47          if (jumping)
48         {
49              if (mAnimationBlender->complete)
50             {
51                 mAnimationBlender->blend( "Idle1",AnimationBlender::BlendWhileAnimating, 0.02,  true );
52                 jumping= false;
53             }
54         }
55         mAnimationBlender->addTime(evt.timeSinceLastFrame);
56 
57          return  true;
58     }
59 };
60 
61  class AnimationBlenderDemoApp :  public ExampleApplication
62 {
63  public:
64     AnimationBlenderDemoApp() {}
65  protected:
66     Entity* mNinjaEnt;
67      void createScene();
68      void createFrameListener()
69     {
70         mFrameListener =  new AnimationBlenderDemoFrameListener(mWindow, mCamera, mNinjaEnt);
71         mRoot->addFrameListener(mFrameListener);
72     }
73 };
74 
75  #endif

 

AnimationBlenderDemo.cpp

 1 #include "AnimationBlenderDemo.h"
 2 #include <OgreStringConverter.h>
 3 
 4  void AnimationBlenderDemoApp::createScene()
 5 {
 6     mSceneMgr->setAmbientLight(ColourValue(1.0, 1.0, 1.0));
 7 
 8     mNinjaEnt = mSceneMgr->createEntity("Ninja", "ninja.mesh");
 9     SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode();
10     node->attachObject(mNinjaEnt);
11 }
12 
13 #ifdef __cplusplus
14  extern "C" {
15  #endif
16 
17  #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
18  #define WIN32_LEAN_AND_MEAN
19 #include "windows.h"
20 
21     INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
22  #else
23      int main( int argc,  char **argv)
24  #endif
25     {
26         AnimationBlenderDemoApp app;
27          try {
28             app.go();
29         }  catch( Ogre::Exception& e ) {
30  #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
31             MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL );
32  #else
33             std::cerr << "An exception has occured: " << e.getFullDescription();
34  #endif
35         }
36          return 0;
37     }
38 
39 #ifdef __cplusplus
40 }
41  #endif


http://www.cppblog.com/summericeyl/archive/2010/05/02/114175.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值