source: GTP/trunk/App/Demos/Geom/OgreStuff/include/OgreAnimationTrack.h @ 1812

Revision 1812, 20.9 KB checked in by gumbau, 18 years ago (diff)
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2005 The OGRE Team
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23-----------------------------------------------------------------------------
24*/
25
26#ifndef __AnimationTrack_H__
27#define __AnimationTrack_H__
28
29#include "OgrePrerequisites.h"
30#include "OgreSimpleSpline.h"
31#include "OgreRotationalSpline.h"
32#include "OgreKeyFrame.h"
33#include "OgreAnimable.h"
34#include "OgrePose.h"
35
36namespace Ogre
37{
38    /** A 'track' in an animation sequence, ie a sequence of keyframes which affect a
39        certain type of animable object.
40    @remarks
41        This class is intended as a base for more complete classes which will actually
42        animate specific types of object, e.g. a bone in a skeleton to affect
43        skeletal animation. An animation will likely include multiple tracks each of which
44        can be made up of many KeyFrame instances. Note that the use of tracks allows each animable
45        object to have it's own number of keyframes, i.e. you do not have to have the
46        maximum number of keyframes for all animable objects just to cope with the most
47        animated one.
48    @remarks
49        Since the most common animable object is a Node, there are options in this class for associating
50        the track with a Node which will receive keyframe updates automatically when the 'apply' method
51        is called.
52        @remarks
53                By default rotation is done using shortest-path algorithm.
54                It is possible to change this behaviour using
55                setUseShortestRotationPath() method.
56    */
57    class _OgreExport AnimationTrack
58    {
59    public:
60        /// Constructor
61        AnimationTrack(Animation* parent, unsigned short handle);
62
63        virtual ~AnimationTrack();
64
65                /** Get the handle associated with this track. */
66                unsigned short getHandle(void) const { return mHandle; }
67
68        /** Returns the number of keyframes in this animation. */
69        virtual unsigned short getNumKeyFrames(void) const;
70
71        /** Returns the KeyFrame at the specified index. */
72        virtual KeyFrame* getKeyFrame(unsigned short index) const;
73
74        /** Gets the 2 KeyFrame objects which are active at the time given, and the blend value between them.
75        @remarks
76            At any point in time  in an animation, there are either 1 or 2 keyframes which are 'active',
77            1 if the time index is exactly on a keyframe, 2 at all other times i.e. the keyframe before
78            and the keyframe after.
79        @par
80            This method returns those keyframes given a time index, and also returns a parametric
81            value indicating the value of 't' representing where the time index falls between them.
82            E.g. if it returns 0, the time index is exactly on keyFrame1, if it returns 0.5 it is
83            half way between keyFrame1 and keyFrame2 etc.
84        @param timePos The time index in seconds.
85        @param keyFrame1 Pointer to a KeyFrame pointer which will receive the pointer to the
86            keyframe just before or at this time index.
87        @param keyFrame2 Pointer to a KeyFrame pointer which will receive the pointer to the
88            keyframe just after this time index.
89        @param firstKeyIndex Pointer to an unsigned short which, if supplied, will receive the
90            index of the 'from' keyframe incase the caller needs it.
91        @returns Parametric value indicating how far along the gap between the 2 keyframes the timePos
92            value is, e.g. 0.0 for exactly at 1, 0.25 for a quarter etc. By definition the range of this
93            value is:  0.0 <= returnValue < 1.0 .
94        */
95        virtual Real getKeyFramesAtTime(Real timePos, KeyFrame** keyFrame1, KeyFrame** keyFrame2,
96            unsigned short* firstKeyIndex = 0) const;
97
98        /** Creates a new KeyFrame and adds it to this animation at the given time index.
99        @remarks
100            It is better to create KeyFrames in time order. Creating them out of order can result
101            in expensive reordering processing. Note that a KeyFrame at time index 0.0 is always created
102            for you, so you don't need to create this one, just access it using getKeyFrame(0);
103        @param timePos The time from which this KeyFrame will apply.
104        */
105        virtual KeyFrame* createKeyFrame(Real timePos);
106
107        /** Removes a KeyFrame by it's index. */
108        virtual void removeKeyFrame(unsigned short index);
109
110        /** Removes all the KeyFrames from this track. */
111        virtual void removeAllKeyFrames(void);
112
113
114        /** Gets a KeyFrame object which contains the interpolated transforms at the time index specified.
115        @remarks
116            The KeyFrame objects held by this class are transformation snapshots at
117            discrete points in time. Normally however, you want to interpolate between these
118            keyframes to produce smooth movement, and this method allows you to do this easily.
119            In animation terminology this is called 'tweening'.
120        @param timeIndex The time (in relation to the whole animation sequence)
121        @param kf Keyframe object to store results
122        */
123        virtual void getInterpolatedKeyFrame(Real timeIndex, KeyFrame* kf) const = 0;
124
125        /** Applies an animation track to the designated target.
126        @param timePos The time position in the animation to apply.
127        @param weight The influence to give to this track, 1.0 for full influence, less to blend with
128          other animations.
129                @param acculumate Don't make weights relative to overall weights applied,
130                        make them absolute and just add.
131            @param scale The scale to apply to translations and scalings, useful for
132                        adapting an animation to a different size target.
133        */
134        virtual void apply(Real timePos, Real weight = 1.0, bool accumulate = false,
135                        Real scale = 1.0f) = 0;
136
137        /** Internal method used to tell the track that keyframe data has been
138            changed, which may cause it to rebuild some internal data. */
139                virtual void _keyFrameDataChanged(void) const {}
140
141                /** Method to determine if this track has any KeyFrames which are
142                doing anything useful - can be used to determine if this track
143                can be optimised out.
144                */
145                virtual bool hasNonZeroKeyFrames(void) const { return true; }
146
147                /** Optimise the current track by removing any duplicate keyframes. */
148                virtual void optimise(void) {}
149
150    protected:
151        typedef std::vector<KeyFrame*> KeyFrameList;
152        KeyFrameList mKeyFrames;
153        Animation* mParent;
154                unsigned short mHandle;
155
156                /// Create a keyframe implementation - must be overridden
157                virtual KeyFrame* createKeyFrameImpl(Real time) = 0;
158
159                /// Internal method for clone implementation
160                virtual void populateClone(AnimationTrack* clone) const;
161               
162
163
164    };
165
166        /** Specialised AnimationTrack for dealing with generic animable values.
167        */
168        class _OgreExport NumericAnimationTrack : public AnimationTrack
169        {
170        public:
171                /// Constructor
172                NumericAnimationTrack(Animation* parent, unsigned short handle);
173                /// Constructor, associates with an AnimableValue
174                NumericAnimationTrack(Animation* parent, unsigned short handle,
175                        AnimableValuePtr& target);
176
177        /** Creates a new KeyFrame and adds it to this animation at the given time index.
178        @remarks
179            It is better to create KeyFrames in time order. Creating them out of order can result
180            in expensive reordering processing. Note that a KeyFrame at time index 0.0 is always created
181            for you, so you don't need to create this one, just access it using getKeyFrame(0);
182        @param timePos The time from which this KeyFrame will apply.
183        */
184        virtual NumericKeyFrame* createNumericKeyFrame(Real timePos);
185
186                /// @copydoc AnimationTrack::getInterpolatedKeyFrame
187                void getInterpolatedKeyFrame(Real timeIndex, KeyFrame* kf) const;
188
189                /// @copydoc AnimationTrack::apply
190                void apply(Real timePos, Real weight = 1.0, bool accumulate = false,
191                        Real scale = 1.0f);
192
193        /** Applies an animation track to a given animable value.
194                @param anim The AnimableValue to which to apply the animation
195        @param timePos The time position in the animation to apply.
196        @param weight The influence to give to this track, 1.0 for full influence, less to blend with
197          other animations.
198            @param scale The scale to apply to translations and scalings, useful for
199                        adapting an animation to a different size target.
200        */
201                void applyToAnimable(const AnimableValuePtr& anim, Real timePos,
202                        Real weight = 1.0, Real scale = 1.0f);
203
204                /** Returns a pointer to the associated animable object (if any). */
205                virtual const AnimableValuePtr& getAssociatedAnimable(void) const;
206
207                /** Sets the associated animable object which will be automatically
208                        affected by calls to 'apply'. */
209                virtual void setAssociatedAnimable(const AnimableValuePtr& val);
210
211                /** Returns the KeyFrame at the specified index. */
212                NumericKeyFrame* getNumericKeyFrame(unsigned short index) const;
213
214                /** Clone this track (internal use only) */
215                NumericAnimationTrack* _clone(Animation* newParent) const;
216
217
218        protected:
219                /// Target to animate
220                AnimableValuePtr mTargetAnim;
221
222                /// @copydoc AnimationTrack::createKeyFrameImpl
223                KeyFrame* createKeyFrameImpl(Real time);
224
225
226        };
227
228        /** Specialised AnimationTrack for dealing with node transforms.
229        */
230        class _OgreExport NodeAnimationTrack : public AnimationTrack
231        {
232        public:
233                /// Constructor
234                NodeAnimationTrack(Animation* parent, unsigned short handle);
235                /// Constructor, associates with a Node
236                NodeAnimationTrack(Animation* parent, unsigned short handle,
237                        Node* targetNode);
238        /** Creates a new KeyFrame and adds it to this animation at the given time index.
239        @remarks
240            It is better to create KeyFrames in time order. Creating them out of order can result
241            in expensive reordering processing. Note that a KeyFrame at time index 0.0 is always created
242            for you, so you don't need to create this one, just access it using getKeyFrame(0);
243        @param timePos The time from which this KeyFrame will apply.
244        */
245        virtual TransformKeyFrame* createNodeKeyFrame(Real timePos);
246                /** Returns a pointer to the associated Node object (if any). */
247                virtual Node* getAssociatedNode(void) const;
248
249                /** Sets the associated Node object which will be automatically affected by calls to 'apply'. */
250                virtual void setAssociatedNode(Node* node);
251
252                /** As the 'apply' method but applies to a specified Node instead of associated node. */
253                virtual void applyToNode(Node* node, Real timePos, Real weight = 1.0,
254                        bool accumulate = false, Real scale = 1.0f);
255
256                /** Sets the method of rotation calculation */
257                virtual void setUseShortestRotationPath(bool useShortestPath);
258
259                /** Gets the method of rotation calculation */
260                virtual bool getUseShortestRotationPath() const;
261
262                /// @copydoc AnimationTrack::getInterpolatedKeyFrame
263                void getInterpolatedKeyFrame(Real timeIndex, KeyFrame* kf) const;
264
265                /// @copydoc AnimationTrack::apply
266                void apply(Real timePos, Real weight = 1.0, bool accumulate = false,
267                        Real scale = 1.0f);
268
269                /// @copydoc AnimationTrack::_keyFrameDataChanged
270                void _keyFrameDataChanged(void) const;
271
272                /** Returns the KeyFrame at the specified index. */
273                virtual TransformKeyFrame* getNodeKeyFrame(unsigned short index) const;
274
275
276                /** Method to determine if this track has any KeyFrames which are
277                        doing anything useful - can be used to determine if this track
278                        can be optimised out.
279                */
280                virtual bool hasNonZeroKeyFrames(void) const;
281
282                /** Optimise the current track by removing any duplicate keyframes. */
283                virtual void optimise(void);
284
285                /** Clone this track (internal use only) */
286                NodeAnimationTrack* _clone(Animation* newParent) const;
287               
288        protected:
289                /// Specialised keyframe creation
290                KeyFrame* createKeyFrameImpl(Real time);
291                // Flag indicating we need to rebuild the splines next time
292                virtual void buildInterpolationSplines(void) const;
293
294                Node* mTargetNode;
295                // Prebuilt splines, must be mutable since lazy-update in const method
296                mutable bool mSplineBuildNeeded;
297                mutable SimpleSpline mPositionSpline;
298                mutable SimpleSpline mScaleSpline;
299                mutable RotationalSpline mRotationSpline;
300                /// Defines if rotation is done using shortest path
301                mutable bool mUseShortestRotationPath ;
302
303
304        };
305
306        /** Type of vertex animation.
307                Vertex animation comes in 2 types, morph and pose. The reason
308                for the 2 types is that we have 2 different potential goals - to encapsulate
309                a complete, flowing morph animation with multiple keyframes (a typical animation,
310                but implemented by having snapshots of the vertex data at each keyframe),
311                or to represent a single pose change, for example a facial expression.
312                Whilst both could in fact be implemented using the same system, we choose
313                to separate them since the requirements and limitations of each are quite
314                different.
315        @par
316                Morph animation is a simple approach where we have a whole series of
317                snapshots of vertex data which must be interpolated, e.g. a running
318                animation implemented as morph targets. Because this is based on simple
319                snapshots, it's quite fast to use when animating an entire mesh because
320                it's a simple linear change between keyframes. However, this simplistic
321                approach does not support blending between multiple morph animations.
322                If you need animation blending, you are advised to use skeletal animation
323                for full-mesh animation, and pose animation for animation of subsets of
324                meshes or where skeletal animation doesn't fit - for example facial animation.
325                For animating in a vertex shader, morph animation is quite simple and
326                just requires the 2 vertex buffers (one the original position buffer)
327                of absolute position data, and an interpolation factor. Each track in
328                a morph animation refrences a unique set of vertex data.
329        @par
330                Pose animation is more complex. Like morph animation each track references
331                a single unique set of vertex data, but unlike morph animation, each
332                keyframe references 1 or more 'poses', each with an influence level.
333                A pose is a series of offsets to the base vertex data, and may be sparse - ie it
334                may not reference every vertex. Because they're offsets, they can be
335                blended - both within a track and between animations. This set of features
336                is very well suited to facial animation.
337        @par
338                For example, let's say you modelled a face (one set of vertex data), and
339                defined a set of poses which represented the various phonetic positions
340                of the face. You could then define an animation called 'SayHello', containing
341                a single track which referenced the face vertex data, and which included
342                a series of keyframes, each of which referenced one or more of the facial
343                positions at different influence levels - the combination of which over
344                time made the face form the shapes required to say the word 'hello'. Since
345                the poses are only stored once, but can be referenced may times in
346                many animations, this is a very powerful way to build up a speech system.
347        @par
348                The downside of pose animation is that it can be more difficult to set up.
349                Also, since it uses more buffers (one for the base data, and one for each
350                active pose), if you're animating in hardware using vertex shaders you need
351                to keep an eye on how many poses you're blending at once. You define a
352                maximum supported number in your vertex program definition, see the
353                includes_pose_animation material script entry.
354        @par
355                So, by partitioning the vertex animation approaches into 2, we keep the
356                simple morph technique easy to use, whilst still allowing all
357                the powerful techniques to be used. Note that morph animation cannot
358                be blended with other types of vertex animation (pose animation or other
359                morph animation); pose animation can be blended with other pose animation
360                though, and both types can be combined with skeletal animation. Also note
361                that all morph animation can be expressed as pose animation, but not vice
362                versa.
363        */
364        enum VertexAnimationType
365        {
366                /// No animation
367                VAT_NONE = 0,
368                /// Morph animation is made up of many interpolated snapshot keyframes
369                VAT_MORPH = 1,
370                /// Pose animation is made up of a single delta pose keyframe
371                VAT_POSE = 2
372        };
373
374        /** Specialised AnimationTrack for dealing with changing vertex position information.
375        @see VertexAnimationType
376        */
377        class _OgreExport VertexAnimationTrack : public AnimationTrack
378        {
379        public:
380                /** The target animation mode */
381                enum TargetMode
382                {
383                        /// Interpolate vertex positions in software
384                        TM_SOFTWARE,
385                        /** Bind keyframe 1 to position, and keyframe 2 to a texture coordinate
386                                for interpolation in hardware */
387                        TM_HARDWARE
388                };
389                /// Constructor
390                VertexAnimationTrack(Animation* parent, unsigned short handle, VertexAnimationType animType);
391                /// Constructor, associates with target VertexData and temp buffer (for software)
392                VertexAnimationTrack(Animation* parent, unsigned short handle, VertexAnimationType animType,
393                        VertexData* targetData, TargetMode target = TM_SOFTWARE);
394
395                /** Get the type of vertex animation we're performing. */
396                VertexAnimationType getAnimationType(void) const { return mAnimationType; }
397
398                /** Creates a new morph KeyFrame and adds it to this animation at the given time index.
399                @remarks
400                It is better to create KeyFrames in time order. Creating them out of order can result
401                in expensive reordering processing. Note that a KeyFrame at time index 0.0 is always created
402                for you, so you don't need to create this one, just access it using getKeyFrame(0);
403                @param timePos The time from which this KeyFrame will apply.
404                */
405                virtual VertexMorphKeyFrame* createVertexMorphKeyFrame(Real timePos);
406
407                /** Creates the single pose KeyFrame and adds it to this animation.
408                */
409                virtual VertexPoseKeyFrame* createVertexPoseKeyFrame(Real timePos);
410
411                /** This method in fact does nothing, since interpolation is not performed
412                        inside the keyframes for this type of track.
413                */
414                void getInterpolatedKeyFrame(Real timeIndex, KeyFrame* kf) const {}
415
416                /// @copydoc AnimationTrack::apply
417                void apply(Real timePos, Real weight = 1.0, bool accumulate = false,
418                        Real scale = 1.0f);
419
420                /** As the 'apply' method but applies to specified VertexData instead of
421                        associated data. */
422                virtual void applyToVertexData(VertexData* data,
423                        Real timePos, Real weight = 1.0,
424                        const PoseList* poseList = 0);
425
426
427                /** Returns the morph KeyFrame at the specified index. */
428                VertexMorphKeyFrame* getVertexMorphKeyFrame(unsigned short index) const;
429
430                /** Returns the pose KeyFrame at the specified index. */
431                VertexPoseKeyFrame* getVertexPoseKeyFrame(unsigned short index) const;
432
433                /** Sets the associated VertexData which this track will update. */
434                void setAssociatedVertexData(VertexData* data) { mTargetVertexData = data; }
435                /** Gets the associated VertexData which this track will update. */
436                VertexData* getAssociatedVertexData(void) const { return mTargetVertexData; }
437
438                /// Set the target mode
439                void setTargetMode(TargetMode m) { mTargetMode = m; }
440                /// Get the target mode
441                TargetMode getTargetMode(void) const { return mTargetMode; }
442
443                /** Method to determine if this track has any KeyFrames which are
444                doing anything useful - can be used to determine if this track
445                can be optimised out.
446                */
447                virtual bool hasNonZeroKeyFrames(void) const;
448
449                /** Optimise the current track by removing any duplicate keyframes. */
450                virtual void optimise(void);
451
452                /** Clone this track (internal use only) */
453                VertexAnimationTrack* _clone(Animation* newParent) const;
454
455        protected:
456                /// Animation type
457                VertexAnimationType mAnimationType;
458                /// Target to animate
459                VertexData* mTargetVertexData;
460                /// Mode to apply
461                TargetMode mTargetMode;
462
463                /// @copydoc AnimationTrack::createKeyFrameImpl
464                KeyFrame* createKeyFrameImpl(Real time);
465
466                /// Utility method for applying pose animation
467                void applyPoseToVertexData(const Pose* pose, VertexData* data, Real influence);
468
469
470        };
471
472
473}
474
475#endif
Note: See TracBrowser for help on using the repository browser.