1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
|
#ifndef ANIMATED_CHARACTER_H_
#define ANIMATED_CHARACTER_H_
#include <mingfx.h>
#include <string>
#include <map>
#include "motion_clip.h"
#include "pose.h"
#include "skeleton.h"
/** An AnimatedCharacter combines a hierarchical Skeleton of bones with one or
more Poses that specify how the bones are currently positioned in space. The
Poses can be stored in the form of a MotionClip, and this allows for animated
playback. Example:
~~~
AnimatedCharacter bob;
MotionClip jump_motion;
void MyGraphicsApp::InitOpenGL() {
std::vector<std::string> search_path;
search_path.push_back("./data");
// Load a skeleton for bob
bob.LoadSkeleton(Platform::FindFile("bob.asf", search_path));
// Load a walking motion and tell bob to start playing it back on repeat
MotionClip walk1;
walk1.LoadFromAMC(Platform::FindFile("human_walk.amc", searchPath_), bob.skeleton_ptr());
bob.Play(walk1);
// Load a jumping motion clip to use later...
jump_motion.LoadFromAMC(Platform::FindFile("human_jump.amc", searchPath_), bob.skeleton_ptr());
}
void MyGraphicsApp::UpdateSimulation(double dt) {
// Advances bob to the next frame of the animation
bob.AdvanceAnimation(dt);
}
void MyGraphicsApp::DrawUsingOpenGL() {
// Draws bob using his current pose (i.e., whatever pose was setup during
// the last call to bob.AdvanceAnimation()
bob.Draw(model_matrix, view_matrix, proj_matrix);
}
void MyGraphicsApp::OnButtonPressed() {
// Imagine we want bob to jump every time a button is pressed, this overlays
// a jumping mocap clip on top of bob's current motion. Once the jump is
// played back once, bob returns to his previous motion.
bob.OverlayClip(jump_motion, 50);
}
~~~
*/
class AnimatedCharacter {
public:
/** Creates an animated character with a skeleton loaded from the specified
file */
AnimatedCharacter(const std::string &asf_filename);
/** Creates an animated character with an empty skeleton. The skeleton must
be loaded with LoadSkeleton() before the character can be animated. */
AnimatedCharacter();
virtual ~AnimatedCharacter();
/** Loads a skeleton from the specified file. The ASF file format is the
only format supported.*/
void LoadSkeleton(const std::string &asf_filename);
/** Clears the current motion queue and starts playing the specified motion
clip immediately. The clip will automatically repeat when finished.*/
void Play(const MotionClip &motion_clip);
/** Adds the specified motion clip to end of the current play queue. If the
queue is currently empty, then the motion will start playing immediately.
If the queue is not empty then the motion will start playing after all the
previously added clips finish playing.*/
void Queue(const MotionClip &motion_clip);
/** Removes all motion clips from the current queue and resets the current
pose to the default pose of the skeleton.*/
void ClearQueue();
/** Assuming the character is currently in the middle of an animation, this
function briefly interrupts that current motion in order to play a new
motion clip. Use this to apply new behaviors on command. In a game where
you press the 'A' button to punch, you could call this function to overlay
a punching motion clip on top of the current base motion of the character.
We call this an "overlay" rather than simply "insert" because the function
also interpolates between the current motion clip and the overlay clip so
that there is a smooth transition in the motion. You can control how smooth
the transition is by setting the num_transition_frames parameter. A larger
number will create a longer, smoother transition. num_transition_frames are
used both to "fade in" the overlay motion and to "fade it out". If you have
an overlay_clip that is 300 frames long and num_transition_frames=50, then
the first 50 frames of the overlay_clip will be blended with the next 50
frames of the motion clip that the character is currently using. Then, the
middle 200 frames of the overlay_clip will be played on their own. Then,
the final 50 frames of the overlay_clip will again be blended with the next
50 frames of the character's current motion clip to "fade out" the overlay.
*/
void OverlayClip(const MotionClip &overlay_clip, int num_transition_frames);
/** You must call this function to advance the frame of the current motion
clip. Pass the elapsed time since the last call to AdvanceAnimation in the
dt (delta t) argument. The number of frames to advance is determined based
on the real-world elapsed time, and is determined by the character's frames
per second (fps). For example, if the character is set to have a fps=120,
and the dt since the last frame is 1/120 seconds, then the character will
advance 1 frame. If the fps=120 and the dt=1/60, then the character will
advance 2 frames, etc..*/
void AdvanceAnimation(double dt);
/** Draws the character using the supplied matrices. If use_absolute_position
is true, then the character's root position will be set using the absolute
position in the root transformation matrix for the current pose. If it is
false, then the relative change in */
void Draw(const Matrix4 &model_matrix, const Matrix4 &view_matrix, const Matrix4 &proj_matrix,
bool use_absolute_position=true);
Skeleton* skeleton_ptr();
void set_fps(int fps);
int fps();
private:
void CalcCurrentPose();
void DrawBoneRecursive(const std::string &bone_name, const Matrix4 &parent_transform,
const Matrix4 &view_matrix, const Matrix4 &proj_matrix);
// Raw skeleton data
Skeleton skeleton_;
// Raw character motion data
std::vector<MotionClip> motion_queue_;
// "frames per second" - we assume all clips in the playlist are played back at the same rate
int fps_;
// time since we last advanced to the next frame in the clip
double elapsed_since_last_frame_;
// current frame to display from motion_queue_[0]
int current_frame_;
// if we are overlaying a clip on top of the main motion, this holds that clip
MotionClip overlay_clip_;
// current frame to display from overlay_clip_
int overlay_frame_;
// number of frames used to fade-in and fade-out the overlay clip
int overlay_transition_frames_;
// cached value of the current pose
Pose pose_;
// the accumulated relative translations from frame-to-frame, not used when
// drawing with absolute position turned on.
Matrix4 accum_translation_matrix_;
// for drawing the character
QuickShapes quick_shapes_;
};
#endif
|