ogre初学动画笔记

来源:互联网 发布:des算法主要内容 编辑:程序博客网 时间:2024/06/13 23:25

动画基础

实现动画的基本原理:多个关键帧组成一个动画轨迹,多个动画轨迹组成一个动画。在各个关键帧之间通过插值算法(Spline插值或线性插值)进行插值来生成最终的动画。一个动画不只包括关键帧,还有其它的一些属性(动画名、动画长度、动画的权重、是否被启用等)。一个动画轨迹可以指定其控制的节点。

SimpleSpline与RotationSpline类

实现了样条的插值算法。SimpleSpline用来对Translate和Scale进行插值,RotationSpline用来对Rotation进行插值。

关键帧类(KeyFrame)

组成动画最基本的元素。一个动画轨迹里有多个关键帧,每个关键帧具有自己的位置、缩放比例和旋转角,同时每个关键帧还保存有自己在整个动画轨迹里所处的时间点。在实际运行时,根据当前时间,通过对两个关键帧的插值可以得到当前帧(当前位置、缩放比例和旋转角)。随着时间的变化,插值得到的当前帧也是变化的,动画就产生了。由于关键帧包括位置信息、缩放比例信息和旋转信息,所以可以实现运动动画、缩放动画和旋转动画以及混合动画。  

动画轨迹类(AnimationTrack)

动画轨迹由多个关健帧组成,负责对相邻的两个关键帧之间插值。

每个动画轨迹保存关键帧列表、本动画轨迹所属的动画(Animation)、本动画轨迹所控制的Node,又由于动画轨迹负责关键帧的插值,所以它保存SimpleSpline(简单样条插值计算器)和RotationSpline(旋转样条插值计算器)对象以实现插值功能。

一个动画轨迹可以对一个物体产生作用,使物体按照动画轨迹运动。这个物体可以是一个Node(一块骨头或场景中的一个结点)。如果骨头受动画轨迹控制,可以实现骨骼动画,如果场景节点受动画轨迹控制,可以直接实现场景节点的动画运动。

重要函数

创建一个关键帧,传入这一帧的所在的时间点。

KeyFrame* createKeyFrame(Real timePos);

根据当前时间,得到插值计算出来的的当前帧。

KeyFrame getInterpolatedKeyFrame(Real timeIndex) const;

使当前动画轨迹对其控制的节点产生作用,参数是当前时间点、权重和是否累计权重。

void apply(Real timePos, Real weight = 1.0, bool accumulate = false);

动画类(Animation)

一个动画由多个动画轨迹(AnimationTrack)组成。而一个动画轨迹可以控制一个节点,这样一个动画可以使多个节点沿着自己的轨迹运动。

设想一下一个人的行走动画,人身上的关节点都沿着自己的轨迹运动,如果把两个关节点连接起来,就形成骨头,再让表面的网格受骨头影响而运动,骨骼动画的基础有了!

每个动画保存自己的AnimationTrack列表,保存动画名称和长度(时间)。

重要函数

设置关键帧间的插值方式。参数IM_LINEAR 代表线性插值、IM_SPLINE代表样条插值。

void setInterpolationMode(InterpolationMode im);

创建一个动画轨迹。第一个参数是这个动画轨迹的唯一标识,第二个参数指定应用这个动画轨迹的节点。

AnimationTrack* createTrack(unsigned short handle, Node* node);

使当前动画对其控制的节点产生作用(委托AnimationTrack进行),参数是当前时间点、权重和是否累计权重。

void apply(Real timePos, Real weight = 1.0, bool accumulate = false);

 

动画状态类(AnimationState)

一个动画状态类的对象对应一个动画类的对象,看上面的类图,AnimationState的数据成员mAnimationName与Animation类的数据成员mName是相对应的。它保存相应动画的状态。

动画状态包括动画名、当前时间点,动画长度(总时间)、动画权重和动画的enable开关。

重要函数

设置动画是否启用。

    void setEnabled(bool enabled);

移动当前时间点,让动画状态在动画时间线上向前移动。参数为移动量。

void addTime(Real offset);

场景管理器类(SceneManager)

场景管理器负责动画和动画状态的创建与维护。在场景管理器里保存有mAnimationsList(动画列表)和mAnimationStates(动画状态列表),其中每个动画和动画状态通过名字一一对应。

场景管理器中有一个很重要的方法_applySceneAnimations ,它在每次渲染时(_renderScene函数里)都会被调用(自动调用不需要程序员控制),它的任务是在每一帧渲染前根据动画状态更新动画,完成动作。_applySceneAnimations方法遍历全部的动画状态,并根据这些状态找出与之一一对应的动画,再找出每个动画中的全部动画轨迹,在每个轨迹里都保存有该轨迹控制的节点。_applySceneAnimations方法先将这些被动画控制的节点都还原为初始状态,而后再调用动画的apply方法将全部节点更新到新的位置、大小或方向,从而使动画向前进行。

 

通过FrameLisener调用动画状态的addTime方法,可以完成动画状态的更新。场景管理器的_applySceneAnimations方法会根据新的动画状态将对应动画的相关节点的位置、大小和方向也更新,这就是OGRE中实现动画的基本原理和方法。

重要函数

创建动画Animation,参数为动画名和长度(时间)

virtual Animation* createAnimation(const String& name, Real length);

创建动画状态AnimationState,参数是与动画对应的名称。

virtual AnimationState* createAnimationState(const String& animName);

一个简单场景节点动画实例代码:

#include"ExampleApplication.h"
using namespace Ogre;


class myFrameListener:public ExampleFrameListener
{
public:
myFrameListener(RenderWindow* win,Camera* cam,Ogre::AnimationState * animState):ExampleFrameListener(win,cam)
{
 mAnimState=animState;
}
bool frameStarted(const FrameEvent& evt)
{
mAnimState->addTime(evt.timeSinceLastFrame);
return ExampleFrameListener::frameStarted(evt);
}
Ogre::AnimationState * mAnimState;
};
class MyApp:public ExampleApplication
{
public:
MyApp()
{
}
void createScene()
{

  
Ogre::SceneNode *Node=mSceneMgr->getRootSceneNode()->createChildSceneNode();
Ogre::Entity *ent=mSceneMgr->createEntity("Sinbad.mesh");
Node->attachObject(ent);
Node->setScale(10,10,10);


Ogre::Animation *anim=mSceneMgr->createAnimation("animation",10);
Ogre::NodeAnimationTrack *track=anim->createNodeTrack(0,Node);


Ogre::TransformKeyFrame *key=track->createNodeKeyFrame(0);


key=track->createNodeKeyFrame(2);
key->setTranslate(Ogre::Vector3(-100,0,0));


key=track->createNodeKeyFrame(4);
key->setTranslate(Vector3(0,0,100));


key=track->createNodeKeyFrame(6);
key->setTranslate(Ogre::Vector3(100,0,0));


key=track->createNodeKeyFrame(8);
key->setTranslate(Ogre::Vector3(0,-100,0));


key=track->createNodeKeyFrame(10);
key->setTranslate(Ogre::Vector3(0,0,0));


mAnimState=mSceneMgr->createAnimationState("animation");
mAnimState->setEnabled(true);
}


void createFrameListener()
{
mFrameListener=new myFrameListener(mWindow,mCamera,mAnimState);
mRoot->addFrameListener(mFrameListener);
}
private:
myFrameListener *mFrameListener;
Ogre::AnimationState * mAnimState;
};
int main()
{
MyApp app;
return app.go();
}
本文的有关概念来源于网络

原创粉丝点击