http://blog.sina.com.cn/s/blog_5e3213f30100zlx2.html
OGRE中与基本动画相关的类
根据动画原理我们可以抽象出下面的几个类(动画状态\动画类\动画轨迹(由关键帧、简单插值和角度插值组成):
SimpleSpline与RotationSpline类:
关键帧(KeyFrame)类:
通过观察下面的代码明显可以看出,Ogre中大量使用工厂模式的痕迹,用KeyFrame为基类,继承产生了以下的不同用途的五个关键帧类:
1. 关键帧类(KeyFrame类,所有下面的关键帧类的基础类):
class_OgreExport KeyFrame : public AnimationAlloc
{ //关键帧类
public:
KeyFrame(const AnimationTrack* parent, Real time);
//构造函数,应该是被AnimationTrack类的createKeyFrame方法来调用而不是直接产生的virtual ~KeyFrame() {}
Real getTime(void)const { return mTime; }
virtual KeyFrame* _clone(AnimationTrack* newParent)const;
protected: //--------------------------一个关键帧中有时间(在动作轨迹中)和其所属的动作序列的指针
Real mTime;
const AnimationTrack* mParentTrack;
};
2.
class_OgreExport NumericKeyFrame :public KeyFrame
{//------------------------数值关键帧类,里面存储了数值
public:
NumericKeyFrame(const AnimationTrack* parent, Real time);
~NumericKeyFrame() {}
virtualconst AnyNumeric& getValue(void)const;
virtualvoid setValue(const AnyNumeric& val);
KeyFrame* _clone(AnimationTrack* newParent)const;
protected:
AnyNumeric mValue;
};
3. 变换关键帧类(TransformKeyFrame):其中存储了一个完整的该帧的数学变换
class _OgreExport TransformKeyFrame :public KeyFrame
{//变换关键帧:其中存储了一个完整的帧变换
public:
TransformKeyFrame(const AnimationTrack* parent, Real time);
~TransformKeyFrame() {}
virtualvoid setTranslate(const Vector3& trans);
//-----------------设置这个帧中的平移变换(用一个三维向量表示
const Vector3& getTranslate(void)const;
virtualvoid setScale(const Vector3& scale);
//----------------用三维向量表示的此帧的缩放
virtualconst Vector3& getScale(void)const;
virtualvoid setRotation(const Quaternion& rot);
//-----------------用四元数表示的此帧的旋转
virtualconst Quaternion& getRotation(void)const;
KeyFrame* _clone(AnimationTrack* newParent)const;
protected:
Vector3 mTranslate;
Vector3 mScale;
Quaternion mRotate;
};
4. 点Morph关键帧类:存储了在一个完整缓存中点的绝对位置
class _OgreExport VertexMorphKeyFrame :public KeyFrame
{ //点morph关键帧:存储了在一个完整缓存中点的绝对位置,用来在相同的动作轨迹中进行插值。
public:
VertexMorphKeyFrame(const AnimationTrack* parent, Real time);
~VertexMorphKeyFrame() {}
void setVertexBuffer(const HardwareVertexBufferSharedPtr& buf);
//为当前帧设置点缓存,我们假设在位置来源中的前3个位置是这帧的位置
const HardwareVertexBufferSharedPtr& getVertexBuffer(void)const;
KeyFrame* _clone(AnimationTrack* newParent)const;
protected:
HardwareVertexBufferSharedPtr mBuffer;
};
5. 动作点关键帧类:在使用Mesh的情况下存储vertex偏移量
class _OgreExport VertexPoseKeyFrame :public KeyFrame
{//点位置帧:因为使用mesh产生的动作,其内部存储了指定的影响级别(大概是mesh受点位置变化的影响程度)下该帧的偏移
public:
VertexPoseKeyFrame(const AnimationTrack* parent, Real time);
~VertexPoseKeyFrame() {}
struct PoseRef//----------------参考的动作
{
ushort poseIndex;
//------------------------动作索引(短整型)
Real influence;
PoseRef(ushort p, Real i) : poseIndex(p), influence(i) {}
};
typedef vector<PoseRef>::type PoseRefList;
void addPoseReference(ushort poseIndex, Real influence);
void updatePoseReference(ushort poseIndex, Real influence);
void removePoseReference(ushort poseIndex);
void removeAllPoseReferences(void);
const PoseRefList& getPoseReferences(void)const;
typedef VectorIterator<PoseRefList> PoseRefIterator;
typedef ConstVectorIterator<PoseRefList> ConstPoseRefIterator;
PoseRefIterator getPoseReferenceIterator(void);
ConstPoseRefIterator getPoseReferenceIterator(void)const;
KeyFrame* _clone(AnimationTrack* newParent) const;
protected:
PoseRefList mPoseRefs;
};
PS:以上关键帧的创建均通过AnimationTrack::createKeyFrame()来完成,由此看继承机制真是个好东西
动画轨迹(AnimationTrack)类
重要函数:
1)
KeyFrame *createKeyFrame(Real timePos);
2)
KeyFrame
3)
Void
主要构成类:
A.动作轨迹(AnimationTrack)类:一个“轨迹“是指一个动作序列,因为最普通的可动作物体是节点Node,所以当”apply“方法被使用的时候会自动的实现帧的更新
class_OgreExport AnimationTrack :public AnimationAlloc
{//-----------------一个“轨迹”是指一个动作序列,因为最普遍的可动作物体是节点Node,所以当“apply”方法被使用的时候会自动的实现帧的更新
public:
class _OgreExport Listener
{ //----------------------------监听类,使用这个类可以允许你重写一个确定的运动轨迹
public:
virtual ~Listener() {}
virtualbool getInterpolatedKeyFrame(const AnimationTrack* t,const TimeIndex& timeIndex, KeyFrame* kf) = 0;
};
/// Constructor
AnimationTrack(Animation* parent,unsigned short handle);
virtual ~AnimationTrack();
unsignedshort getHandle(void)const { return mHandle; }
//得到轨迹相关的句柄
virtualunsigned short getNumKeyFrames(void)const;
//得到这个动作轨迹中的帧数
virtual KeyFrame* getKeyFrame(unsignedshort index) const;
//通过特定索引来得到动画中的帧
virtual Real getKeyFramesAtTime(const TimeIndex& timeIndex, KeyFrame** keyFrame1, KeyFrame** keyFrame2,
unsignedshort* firstKeyIndex = 0) const;
//-------------------------------返回介于KeyFrame1和KeyFrame2之间的帧,timeIndex是用于两帧之间时间标记,keyFrame1和KeyFrame2分别是用来构造新帧的帧模板,最后一个参数指向了形成的帧
virtual KeyFrame* createKeyFrame(Real timePos);
virtualvoid removeKeyFrame(unsignedshort index);
virtual void removeAllKeyFrames(void);
virtualvoid getInterpolatedKeyFrame(const TimeIndex& timeIndex, KeyFrame* kf)const = 0;
//得到在timeIndex上的插值帧
virtualvoid apply(const TimeIndex& timeIndex, Real weight = 1.0, Real scale = 1.0f) = 0;
//-----------------在特定的目标上面使用该动作轨迹
virtual void _keyFrameDataChanged(void) const {}
//-------------------告知关键帧已经改变
virtualbool hasNonZeroKeyFrames(void)const { return true; }
//-------------------使用这个函数来说明是否这个序列中有可用帧
virtualvoid optimise(void) {}
virtualvoid _collectKeyFrameTimes(vector<Real>::type& keyFrameTimes);
//----------------使用一个关键帧时间序列来定义特殊的帧轨迹
virtualvoid _buildKeyFrameIndexMap(const vector<Real>::type& keyFrameTimes);
//----------------通过定义一个关键帧时间序列来完成关键帧映射动画的建立
virtualvoid setListener(Listener* l) { mListener = l; }
Animation *getParent() const { return mParent; }
protected:
typedef vector<KeyFrame*>::type KeyFrameList;
KeyFrameList mKeyFrames;
Animation* mParent;
unsignedshort mHandle;
Listener* mListener;
/// Map used to translate global keyframe time lower bound index to local lower bound index
typedef vector<ushort>::type KeyFrameIndexMap;
KeyFrameIndexMap mKeyFrameIndexMap;
/// Create a keyframe implementation - must be overridden
virtual KeyFrame* createKeyFrameImpl(Real time) = 0;
/// Internal method for clone implementation
virtualvoid populateClone(AnimationTrack* clone) const;
};
B. 数值动作轨迹(NumericAnimationTrack)类:通过处理一般的动作数值来完成动作轨迹的建立(由上面提到的数值关键帧(NumeraicKeyFrame)来构成)
class_OgreExport NumericAnimationTrack :public AnimationTrack
{ //数值动作轨迹:通过处理一般的动作数值来完成动作轨迹的建立
public:
/// Constructor
NumericAnimationTrack(Animation* parent,unsigned short handle);
/// Constructor, associates with an AnimableValue
NumericAnimationTrack(Animation* parent,unsigned short handle,
AnimableValuePtr& target);
virtual NumericKeyFrame* createNumericKeyFrame(Real timePos);
//由数值关键帧构成
/// @copydoc AnimationTrack::getInterpolatedKeyFrame
virtualvoid getInterpolatedKeyFrame(const TimeIndex& timeIndex, KeyFrame* kf)const;
/// @copydoc AnimationTrack::apply
virtualvoid apply(const TimeIndex& timeIndex, Real weight = 1.0, Real scale = 1.0f);
void applyToAnimable(const AnimableValuePtr& anim,const TimeIndex& timeIndex,Real weight = 1.0, Real scale = 1.0f);
virtual const AnimableValuePtr& getAssociatedAnimable(void)const;
virtualvoid setAssociatedAnimable(const AnimableValuePtr& val);
NumericKeyFrame* getNumericKeyFrame(unsignedshort index) const;
NumericAnimationTrack* _clone(Animation* newParent)const;
protected:
/// Target to animate
AnimableValuePtr mTargetAnim;
/// @copydoc AnimationTrack::createKeyFrameImpl
KeyFrame* createKeyFrameImpl(Real time);
};
C. 节点动作轨迹(NodeAnimationTrack)类:主要是处理以节点为目标帧变换
class_OgreExport NodeAnimationTrack :public AnimationTrack
{ //---------------------结点动作轨迹
public:
/// Constructor
NodeAnimationTrack(Animation* parent,unsigned short handle);
/// Constructor, associates with a Node
NodeAnimationTrack(Animation* parent,unsigned short handle,
Node* targetNode);
/// Destructor
virtual ~NodeAnimationTrack();
virtual TransformKeyFrame* createNodeKeyFrame(Real timePos);
virtual Node* getAssociatedNode(void)const;
virtualvoid setAssociatedNode(Node* node);
virtualvoid applyToNode(Node* node, const TimeIndex& timeIndex, Real weight = 1.0,Real scale = 1.0f);
virtualvoid setUseShortestRotationPath(bool useShortestPath);
virtualbool getUseShortestRotationPath() const;
/// @copydoc AnimationTrack::getInterpolatedKeyFrame
virtualvoid getInterpolatedKeyFrame(const TimeIndex& timeIndex, KeyFrame* kf)const;
/// @copydoc AnimationTrack::apply
virtualvoid apply(const TimeIndex& timeIndex, Real weight = 1.0, Real scale = 1.0f);
/// @copydoc AnimationTrack::_keyFrameDataChanged
void _keyFrameDataChanged(void)const;
virtual TransformKeyFrame* getNodeKeyFrame(unsignedshort index) const;
virtualbool hasNonZeroKeyFrames(void)const;
virtualvoid optimise(void);
NodeAnimationTrack* _clone(Animation* newParent)const;
protected:
/// Specialised keyframe creation
KeyFrame* createKeyFrameImpl(Real time);
// Flag indicating we need to rebuild the splines next time
virtualvoid buildInterpolationSplines(void)const;
// Struct for store splines, allocate on demand for better memory footprint
struct Splines//里面保存了修改器
{
SimpleSpline positionSpline;
SimpleSpline scaleSpline;
RotationalSpline rotationSpline;
};
Node* mTargetNode;
// Prebuilt splines, must be mutable since lazy-update in const method
mutable Splines* mSplines;
mutablebool mSplineBuildNeeded;
/// Defines if rotation is done using shortest path
mutablebool mUseShortestRotationPath ;
};
D. 顶点动作轨迹(VertexAnimationTrack)类:用来处理变化顶点信息的类
class_OgreExport VertexAnimationTrack :public AnimationTrack
{//----------------------------顶点动作轨迹
public:
enum TargetMode
{
/// Interpolate vertex positions in software
TM_SOFTWARE,
TM_HARDWARE
};
/// Constructor
VertexAnimationTrack(Animation* parent,unsigned short handle, VertexAnimationType animType);
/// Constructor, associates with target VertexData and temp buffer (for software)
VertexAnimationTrack(Animation* parent,unsigned short handle, VertexAnimationType animType,
VertexData* targetData, TargetMode target = TM_SOFTWARE);
VertexAnimationType getAnimationType(void)const { return mAnimationType; }
virtual VertexMorphKeyFrame* createVertexMorphKeyFrame(Real timePos);
virtual VertexPoseKeyFrame* createVertexPoseKeyFrame(Real timePos);
virtualvoid getInterpolatedKeyFrame(const TimeIndex& timeIndex, KeyFrame* kf)const
{ (void)timeIndex; (void)kf; }
/// @copydoc AnimationTrack::apply
virtualvoid apply(const TimeIndex& timeIndex, Real weight = 1.0, Real scale = 1.0f);
virtualvoid applyToVertexData(VertexData* data,
const TimeIndex& timeIndex, Real weight = 1.0,
const PoseList* poseList = 0);
VertexMorphKeyFrame* getVertexMorphKeyFrame(unsignedshort index) const;
VertexPoseKeyFrame* getVertexPoseKeyFrame(unsignedshort index) const;
void setAssociatedVertexData(VertexData* data) { mTargetVertexData = data; }
VertexData* getAssociatedVertexData(void)const { return mTargetVertexData; }
/// Set the target mode
void setTargetMode(TargetMode m) { mTargetMode = m; }
/// Get the target mode
TargetMode getTargetMode(void)const { return mTargetMode; }
virtualbool hasNonZeroKeyFrames(void)const;
virtualvoid optimise(void);
VertexAnimationTrack* _clone(Animation* newParent)const;
protected:
/// Animation type
VertexAnimationType mAnimationType;
/// Target to animate
VertexData* mTargetVertexData;
/// Mode to apply
TargetMode mTargetMode;
/// @copydoc AnimationTrack::createKeyFrameImpl
KeyFrame* createKeyFrameImpl(Real time);
/// Utility method for applying pose animation
void applyPoseToVertexData(const Pose* pose, VertexData* data, Real influence);
};
动画类(Animation)
重要函数
1)
Void setInterpolationMode(InterpolationMode im)
2)
AnimationTrack *createTrack(unsigned shor handle,Node *node);
3)
Void apply(Real timePos,Real weight=1.0,bool accumulate=false)
(具体的各种函数可以在OgreAnimation.h中看到)
动画状态类(AnimationState)
重要函数
1)
Void setEnabled(bool enabled);
2)
Void addTime(Real offset)
场景管理器(SceneManager)类:
重要函数
1)
Virtual Animation *createAnimation(const string &name,Real length)
2) 创建动画状态AnimationState,参数是与动画对应的名称
Ogre的骨骼动画:
骨骼动画用骨架(由一系列骨头构成的继承体系)来单独保存动作信息,这样就将动作信息与网络、皮肤信息分割成两种数据结构分别进行处理,从而比以往的动画技术效率更高。每块骨头都有自己的位置和旋转方向,这些骨头以树的形式组织起来构成骨骼。例如:腕关节是肘关节的子节点,肘关节又是肩关节的子节点。肩关节旋转会自动带动肘关节运动,腕关节同样也会运动。
怎样使得一个网格产生动作效果?我们可以使网格上的每个顶点都对应于一块或多块骨头,当这些骨头移动时便会影响网格的位置。如果一个点与多块骨头关联,则必须通过指定权重类决定每块骨头对此顶点的影响程度(一个顶点对应一块骨头的时候,该点的权重为1.0)。
与关键帧动画相比,使用骨骼动画有很多优点。首先,骨骼动画需要保存的动作数据量非常小。其次,通过指定不同的权重,可以很容易的将多个动作绑定在一起形成新的动作。还可以实现动作键的平滑过渡等等。
当然骨骼动画的实现中,骨骼本身的运动还是需要关键帧来完成,但是信息量已经很小了。