AnimationBlender - Ogre实现不同动画之间的混合
来源:互联网 发布:java程序员的自我介绍 编辑:程序博客网 时间:2024/04/30 20:52
英文原文: http://test.ogitor.org/tiki/AnimationBlender
动画混合 -- 实现两个动画的切换, 一个动画逐渐消逝, 另一个动画逐渐显示来实现. 主要通过动画状态的权重来实现
通过三种方式来实现两个动画的混合:
- BlendSwitch - 直接切换至目标动画
- BlendWhileAnimating - 混合的过程中目标动画也更新帧, 实现动画
- BlendThenAnimate - 用源动画的当前帧混合目标动画的第一个帧
源码理解, 主要代码位于下面两个函数
AnimationBlender::blend函数 根据传入的参数设置新转换的源动画和目标动画
AnimationBlender::add函数则更新源动画和目标动画(如存在)的状态和权重
AnimationBlender::blend函数
1. 如果动画转换类型为 AnimationBlender::BlendSwitch
直接将源动画转换成目标动画
2. 如果不是这个转换类型 AnimationBlender::BlendSwitch
如果上次的动画转换还未完成
如果新的目标动画等于上次转换的源动画
则反向转换
如果新的目标动画不等于上次转换的源动画和目标动画
根据上次转换的剩余时间设置是显示上次转换的源动画还是目标动画, 并将其设置为新转换的源动画
显示新转换的目标动画, 并设置其权重
假设上次的动画转换已经完成了转换
设置转换时间, 转换类型, 目标动画和其权重
AnimationBlender::addTime 函数
1. 如有动画在运行
如果存在转换
更新剩余时间
如剩余时间小于0
禁止源动画
将目标动画设置为源动画, 继续运行
如剩余时间不小于0
更新源动画和目标动画的权重
如转换类型为AnimationBlender::BlendWhileAnimating
更新目标动画
判断动画是否完成
更新源动画
完整代码和Demo代码
AnimationBlender.h
01
#ifndef __ANIMATION_BLENDER_H__
02
#define __ANIMATION_BLENDER_H__
03
#include <Ogre.h>
04
using
namespace
Ogre;
05
class
AnimationBlender
06
{
07
public
:
08
enum
BlendingTransition
09
{
10
BlendSwitch,
// stop source and start dest
11
BlendWhileAnimating,
// cross fade, blend source animation out while blending destination animation in
12
BlendThenAnimate
// blend source to first frame of dest, when done, start dest anim
13
};
14
private
:
15
Entity *mEntity;
16
AnimationState *mSource;
17
AnimationState *mTarget;
18
BlendingTransition mTransition;
19
bool
loop;
20
~AnimationBlender() {}
21
public
:
22
Real mTimeleft, mDuration;
23
bool
complete;
24
void
blend(
const
String &animation, BlendingTransition transition, Real duration,
bool
l=
true
);
25
void
addTime( Real );
26
Real getProgress() {
return
mTimeleft/ mDuration; }
27
AnimationState *getSource() {
return
mSource; }
28
AnimationState *getTarget() {
return
mTarget; }
29
AnimationBlender( Entity *);
30
void
init(
const
String &animation,
bool
l=
true
);
31
};
32
#endif
AnimationBlender.cpp
001
#include "AnimationBlender.h"
002
void
AnimationBlender::init(
const
String &animation,
bool
l)
003
{
004
// 初始化, 将所有的动画禁止, 只允许参数中的动画运行.
005
AnimationStateSet *set = mEntity->getAllAnimationStates();
006
AnimationStateIterator it = set->getAnimationStateIterator();
007
while
(it.hasMoreElements())
008
{
009
AnimationState *anim = it.getNext();
010
anim->setEnabled(
false
);
011
anim->setWeight(0);
012
anim->setTimePosition(0);
013
}
014
mSource = mEntity->getAnimationState( animation );
015
mSource->setEnabled(
true
);
016
mSource->setWeight(1);
017
mTimeleft = 0;
018
mDuration = 1;
019
mTarget = 0;
020
complete =
false
;
021
loop = l;
022
}
023
void
AnimationBlender::blend(
const
String &animation, BlendingTransition transition, Real duration,
bool
l )
024
{
025
loop = l;
026
if
( transition == AnimationBlender::BlendSwitch )
027
{
028
if
( mSource != 0 )
029
mSource->setEnabled(
false
);
030
mSource = mEntity->getAnimationState( animation );
031
mSource->setEnabled(
true
);
032
mSource->setWeight(1);
033
mSource->setTimePosition(0);
034
mTimeleft = 0;
035
}
036
else
037
{
038
AnimationState *newTarget = mEntity->getAnimationState( animation );
039
if
( mTimeleft > 0 )
040
{
041
// oops, weren't finished yet
042
if
( newTarget == mTarget )
043
{
044
// nothing to do! (ignoring duration here)
045
}
046
else
if
( newTarget == mSource )
047
{
048
// going back to the source state, so let's switch
049
mSource = mTarget;
050
mTarget = newTarget;
051
mTimeleft = mDuration - mTimeleft;
// i'm ignoring the new duration here
052
}
053
else
054
{
055
// ok, newTarget is really new, so either we simply replace the target with this one, or
056
// we make the target the new source
057
if
( mTimeleft < mDuration * 0.5 )
058
{
059
// simply replace the target with this one
060
mTarget->setEnabled(
false
);
061
mTarget->setWeight(0);
062
}
063
else
064
{
065
// old target becomes new source
066
mSource->setEnabled(
false
);
067
mSource->setWeight(0);
068
mSource = mTarget;
069
}
070
mTarget = newTarget;
071
mTarget->setEnabled(
true
);
072
mTarget->setWeight( 1.0 - mTimeleft / mDuration );
073
mTarget->setTimePosition(0);
074
}
075
}
076
else
077
{
078
// assert( target == 0, "target should be 0 when not blending" )
079
// mSource->setEnabled(true);
080
// mSource->setWeight(1);
081
mTransition = transition;
082
mTimeleft = mDuration = duration;
083
mTarget = newTarget;
084
mTarget->setEnabled(
true
);
085
mTarget->setWeight(0);
086
mTarget->setTimePosition(0);
087
}
088
}
089
}
090
void
AnimationBlender::addTime( Real
time
)
091
{
092
if
( mSource != 0 )
093
{
094
if
( mTimeleft > 0 )
095
{
096
mTimeleft -=
time
;
097
if
( mTimeleft < 0 )
098
{
099
// finish blending
100
mSource->setEnabled(
false
);
101
mSource->setWeight(0);
102
mSource = mTarget;
103
mSource->setEnabled(
true
);
104
mSource->setWeight(1);
105
mTarget = 0;
106
}
107
else
108
{
109
// still blending, advance weights
110
mSource->setWeight(mTimeleft / mDuration);
111
mTarget->setWeight(1.0 - mTimeleft / mDuration);
112
if
(mTransition == AnimationBlender::BlendWhileAnimating)
113
mTarget->addTime(
time
);
114
}
115
}
116
if
(mSource->getTimePosition() >= mSource->getLength())
117
{
118
complete =
true
;
119
}
120
else
121
{
122
complete =
false
;
123
}
124
mSource->addTime(
time
);
125
mSource->setLoop(loop);
126
}
127
}
128
AnimationBlender::AnimationBlender( Entity *entity ) : mEntity(entity)
129
{
130
}
AnimationBlenderDemo.h
01
<P>#ifndef __ANIMATIONBLENDER_DEMO_H__
02
#define __ANIMATIONBLENDER_DEMO_H__
03
#include "ExampleApplication.h"
04
#include "AnimationBlender.h"
05
class
AnimationBlenderDemoFrameListener :
public
ExampleFrameListener
06
{
07
protected
:
08
Entity* mNinjaEnt;
09
AnimationBlender* mAnimationBlender;
10
bool
walking, jumping;
11
public
:
12
AnimationBlenderDemoFrameListener(RenderWindow* mWin, Camera* mCam, Entity* ent)
13
: ExampleFrameListener(mWin, mCam,
false
,
false
), mNinjaEnt(ent)
14
{
15
mAnimationBlender =
new
AnimationBlender(mNinjaEnt);
16
mAnimationBlender->init(
"Walk"
,
true
);
17
walking =
false
;
18
jumping =
false
;
19
}
20
virtual
~AnimationBlenderDemoFrameListener()
21
{
22
if
(mAnimationBlender)
23
{
24
// delete mAnimationBlender;
25
}
26
}
27
bool
frameRenderingQueued(
const
FrameEvent& evt)
28
{
29
if
(!ExampleFrameListener::frameRenderingQueued(evt))
30
{
31
return
false
;
32
}
33
if
(!walking)
34
{
35
mAnimationBlender->blend(
"Walk"
,AnimationBlender::BlendWhileAnimating, 0.2,
true
);
36
walking=
true
;
37
}
38
if
(mKeyboard->isKeyDown( OIS::KC_SPACE ) && !jumping)
39
{
40
jumping=
true
;
41
mAnimationBlender->blend(
"Jump"
,AnimationBlender::BlendWhileAnimating, 0.2,
false
);
42
}
43
if
(jumping)
44
{
45
if
(mAnimationBlender->complete)
46
{
47
mAnimationBlender->blend(
"Idle1"
,AnimationBlender::BlendWhileAnimating, 0.02,
true
);
48
jumping=
false
;
49
}
50
}
51
mAnimationBlender->addTime(evt.timeSinceLastFrame);
52
return
true
;
53
}
54
};
55
class
AnimationBlenderDemoApp :
public
ExampleApplication
56
{
57
public
:
58
AnimationBlenderDemoApp() {}
59
protected
:
60
Entity* mNinjaEnt;
61
void
createScene();
62
void
createFrameListener()
63
{
64
mFrameListener =
new
AnimationBlenderDemoFrameListener(mWindow, mCamera, mNinjaEnt);
65
mRoot->addFrameListener(mFrameListener);
66
}
67
};
68
#endif</P>
AnimationBlenderDemo.cpp
01
<P>#include
"AnimationBlenderDemo.h"
02
#include <OgreStringConverter.h>
03
void
AnimationBlenderDemoApp::createScene()
04
{
05
mSceneMgr->setAmbientLight(ColourValue(1.0, 1.0, 1.0));
06
mNinjaEnt = mSceneMgr->createEntity(
"Ninja"
,
"ninja.mesh"
);
07
SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode();
08
node->attachObject(mNinjaEnt);
09
}
10
#ifdef __cplusplus
11
extern
"C"
{
12
#endif
13
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
14
#define WIN32_LEAN_AND_MEAN
15
#include "windows.h"
16
INT
WINAPI WinMain(
HINSTANCE
hInst,
HINSTANCE
,
LPSTR
strCmdLine,
INT
)
17
#else
18
int
main(
int
argc,
char
**argv)
19
#endif
20
{
21
AnimationBlenderDemoApp app;
22
try
{
23
app.go();
24
}
catch
( Ogre::Exception& e ) {
25
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
26
MessageBox( NULL, e.getFullDescription().c_str(),
"An exception has occured!"
, MB_OK | MB_ICONERROR | MB_TASKMODAL );
27
#else
28
std::cerr <<
"An exception has occured: "
<< e.getFullDescription();
29
#endif
30
}
31
return
0;
32
}
33
#ifdef __cplusplus
34
}
35
#endif</P>
不过由于Ninja.mesh的动画时间太小, 很难看出混合效果, 以上代码适合Ogre1.6.5
- AnimationBlender - Ogre实现不同动画之间的混合
- AnimationBlender - Ogre实现不同动画之间的混合
- Ogre实现不同动画之间的混合
- Ogre实现不同动画之间的混合
- Ogre实现不同动画之间的混合
- Ogre中的动画混合(AnimationBlender)
- Ogre 动画过度(AnimationBlender)
- OGRE实现天龙八部组合的骨骼动画
- 不同Activity之间的动画切换
- Unity_混合树实现三种动画的混合_070
- android混合动画实现
- Ogre的骨骼动画
- Ogre overlay实现帧动画
- Ogre overlay实现帧动画
- 使用Kinect驱动OGRE顶点动画的实现
- Ogre中submesh之间的共享缓存的使用 手动画球体
- jquery同一按钮实现不同的动画
- 实现不同页面之间的通信
- 大数据的处理总结
- TCP/IP连接建立与断开
- 根据共享参数来过滤满足条件的对象(代码)
- 闲来无事,对链表做了一下整理...
- 海量数据Top K算法(C实现)
- AnimationBlender - Ogre实现不同动画之间的混合
- oracle 9i 安装时报错----areasquerie
- 从此落户CSDN...
- A potentially dangerous Request.Path value was detected from the client 异常
- 简述Android触摸屏手势识别
- objective-c set
- Android 几个特别注意的小知识
- 无奈
- 学习笔记之继承与派生