Professional Documents
Culture Documents
An Object Oriented Approach To Animation
An Object Oriented Approach To Animation
Animation
By Yatin S. Shelke
Simply put, an Object Oriented Animation application defines various classes, creates the instances of these classes and performs
operations on the object instances. Below, we'll explain some of the essential abstractions that you can use to create your own
computer animations.
This article assumes that you have basic familiarity with the principles of object-oriented programming in C++. If you don't know
C++, first check the C++ Made Easy tutorial, especially the sections on classes and inheritance.
class GraphicObject {
protected:
virtual void refresh() = 0;
public:
virtual void draw() = 0;
virtual void reposition(Vector position) = 0;
virtual void displace(Vector position) = 0;
virtual void rotate(Vector axis, double angle) = 0;
virtual void scale(double proportion) = 0;
virtual void linear_shear(Vector axis, Vector shear_displacement) = 0;
virtual void planar_shear(
Vector axis1, Vector axis2, Vector shear_displacement) = 0;
};
class PositionalGraphicObject : public virtual GraphicObject {
protected:
Vector position;
public:
Vector get_position();
void set_position(Vector p);
};
class CompositeGraphicObject {
protected:
List* graphic_object_list;
public:
CompositeGraphicObject(List*);
void add_graphic_object(GraphicObject* graphic_object);
void delete_graphic_object(GraphicObject* graphic_object);
};
Camera Abstraction
The Camera is an essential abstraction for an animation engine. The camera maps objects in an animation to the rectangular
animation display window. The camera determines what parts of the animation are visible on the screen based on its location and
other parameters. Intuitively, a simple animation camera is a hypothetical lens that has the ability to clearly focus any number of
objects, located at arbitrary distances in its field of view, to a single rectangular screen. Most video game animation engines use
this kind of simple camera abstraction. This kind of camera is different from a camera lens or the human eye, which focus on only
part of a scene (as determined by the focal length). 3D animated movies like Ratatouille or Cars, unlike games, need a camera
similar to the human eye in order to shift focus between near and far objects.
For 3D perspective view animations (most contemporary video games), the Camera is defined by its position and orientation in the
animation (virtual) world. When a 3D Cartesian coordinate system is used, the camera is defined by 3 vectors - position, direction
of view, and upward orientation vector. Imagine yourself in the center of a room with your head oriented straight up and looking
straight. Your position in the room, the direction you are facing and the orientation of your head is analogous to the camera's
position, direction of view, and upward orientation vector. Moving around the room is like changing the position of the animation
camera. Turning your head in different directions - left, right, up, down, turning around etc. is like changing the direction of view
and upward orientation vector. To understand why a separate view direction and upward orientation vector are needed, imagine
tilting your head to your left (without turning your neck). The direction of view remains same in this case, but the upward
orientation is changed. Similarly turning your head to the left without tilting it causes the direction of view to change, but not the
upward orientation. There is a one-to-one mapping from the triplet {position, direction-of-view, upward-orientation} to the
contents of the field of view.
In a 3D game, the player's viewpoint moves around the virtual world when the animation engine moves and orients the animation
camera.
Although the camera is not drawn as an object on the screen, it is nonetheless a worthy candidate to inherit from class
GraphicObject. Its implementation of GraphicObject::draw() will position and orient the camera in the virtual world, allowing the
rest of the visible objects to be drawn correctly onto the screen.
Here's psuedocode that demonstrates a possible definition of class Camera:
Frustum Abstraction
The frustum is a concept closely related to the camera. It defines the clipping planes for the field of view. It is of the shape of a
square pyramid, except part of the top of the pyramid is cut off. To understand the frustum better, imagine yourself looking at a
small rectangle in front of you, with a much larger rectangle behind this small rectangle, such that the sides of the rectangles are
parallel to each other. If your eye were the apex of a pyramid with the larger rectangle as its base, then the frustum is the part of
this pyramid between the small rectangle and the big rectangle. If the small rectangle represents the video screen as a window into
the animation world, then you can only see things inside the frustum on the screen; anything outside it is simply out of your field of
view. The clipping planes of the frustum are the planes that contain the faces of the frustum. Diagram 1 gives a 3D representation
of the frustum.
The camera defines all possible points in space that can be mapped to the screen. The frustum defines all the points that actually
do get mapped to the screen. The process of using the frustum to define these points is known as frustum culling. The camera is
located exactly at the apex of the pyramid described above, and its direction of view is the vector from the tip of the pyramix to the
center of the base and perpendicular to the near and far rectangles. The camera's upward orientation is parallel to one of the sides
of the rectangle. You can see the camera in Diagram 1.
Diagram 1: Frustum 3D Representation
The dimensions of the frustum are usually set only once at the beginning of the animation application. However, it is one of the
inputs given to the animation engine, and therefore should be abstracted to keep the engine platform/library independent.
A possible definition of class Frustum is given in pseudo code.
class Frustum {
private:
double near; // z coordinate of near rectangle with respect to camera
double far; // z coordinate of far rectangle with respect to camera
double right; // x coordinate of right side of near rectangle with respect to camera
double left; // x coordinate of left side of near rectangle with respect to camera
double top; // y coordinate of top side of near rectangle with respect to camera
double bottom; //y coordinate of bottom side of near rectangle with respect to camera
};
FrameState CubeAnimationObject::get_next_frame()
{
if (current_frame < last_frame - 1) {
// displace the cube by deltaX pixels each frame that it moves
cube->displace( Vector( 0, deltaX ) ;
}
. . .
cube->draw();
. . .
}
It is very common to find animation objects in movies/animations/games that repeat an animation effect continuously, such as for
a continuously rotating object, or even a continuously repeating scene. On the other hand, some animations stop after the last
frame is displayed. In video games, there are other ways an animation can play out, for example, on pressing a key, a blinking
object stops blinking—a continuously repeating animation that gets stopped in its tracks. In some cases an animation can play in
reverse. For example, in the game DOOM, when monsters are killed, their bodies disintegrate into pieces that collect in a pile at the
place the monster was killed. Sometimes, these monsters get revived. In this case, the animation of the disintegration of the
monster's body is played back exactly in reverse sequence. The above examples illustrate the need for more abstract operations on
the Animation Object. The abstract operations on an Animation Object can be summarized as follows:
• AnimationObject::get_next_frame() : to play the animation forward (first frame to last)
• AnimationObject::get_previous_frame() : to play the animation in reverse (last frame to first)
• AnimationObject::pause() : to pause the animation
• AnimationObject::resume() : to resume a paused animation
• AnimationObject::rewind() : to rewind the animation and start playing from first frame
One issue that must be addressed is how the animation engine determines which of the above calls must be made next. For
example, after a call to AnimationObject::get_next_frame(), it is possible that for a repeating animation, the last frame was
reached, and the next call must be AnimationObject::rewind(). However, if this was not the last frame, then
AnimationObject::get_next_frame() must be called next.
One obvious, but bad, solution is that the animation engine keeps track of the frame number for each of its animation objects and
somehow knows what to do for each frame of each animation object. This would completely break the abstract relation between
animation engine and animation object! A much better alternative is for the animation object to track of its frames because it
knows best what to do for the next frame. In this case, the animation object must return information to the engine about what to
do next. One way to do this is to return an enumerated value to represent instructions to the animation engine. The enumeration
FrameState is described in pseudocode below along with a possible declaration of the abstract class AnimationObject.
enum FrameState {
// tells the caller of the AnimationObject method what to do after the call
PLAY_NEXT_FRAME, // play next frame (start play or resume paused)
PLAY_PREVISOUS_FRAME, // play the previous frame
STOP, // stop playing the animation object
PAUSE, // pause playing the animation object
REPEAT // rewind the animation object
};
class AnimationObject {
protected:
List* graphic_object_list;
int start_frame = 0;
int total_frames;
public:
virtual FrameState get_next_frame() = 0;
virtual FrameState get_previous_frame() = 0;
virtual void pause() = 0;
virtual void resume() = 0;
virtual void rewind() = 0;
};
A real example of an animation engine that implements these operations is a DVD player. This animation engine has one currently
playing Animation Object (the scene or chapter being played), that contains one Graphic Object per frame of the animation, i.e. the
image of the scene to be displayed on the screen for that frame. Subsequent calls to AnimationObject::get_next_frame() on the
Animation Object load the next frame's Graphic Object and call the method GraphicObject::draw() on it. These Animation Object
operations are performed on the DVD player by pressing keys on the DVD remote control. When you press the PLAY button on the
remote control, you are really asking the DVD player's animation engine to call AnimationObject::get_next_frame() continuously.
When you press the PAUSE or STOP button, you are really calling AnimationObject::pause(). The STOP button additionally stops the
animation engine completely. This additional stop step is not an operation on the Animation Object, rather, it is an operation on the
animation engine itself. The PLAY button also maps to AnimationObject::resume(), asking the player to continue calling
AnimationObject::get_next_frame() from where it was paused. The STEP BACK button is calling AnimationObject::rewind() to
rewind to the frame of the Animation Object i.e. the scene being played. The STEP FORWARD button is really asking the animation
engine to replace the current Animation Object by the Animation Object for the next scene and start calling
AnimationEngine::get_next_frame() on the new current Animation Object. The REWIND button is asking the player's animation
engine to make calls to AnimationObject::get_previous_frame() at different frequencies (1x, 2x, 4x and so on). Similarly the FFWD
button is asking the engine to make calls to AnimationObject::get_next_frame() at those different frequencies. Whenever you are
wondering about interface of the Animation Object abstraction, think of your DVD player and its remote control!
As another example, the animation camera can also be animated, and this animation can be implemented via a Camera Animation
Object. To animate the camera, an Animation Object will not have a drawable (visible) kind of Graphic Object to manipulate,
instead, it will have to manipulate the camera triplet {position, direction, up}. Note that all such Animation Objects need to
manipulate exactly one global camera, as one animation can have only one camera. (I honestly don't know how a spider manages
to see with 8 eyes, but if the animation engine were a spider, it would have to do with just one eye. Further, I would certainly not
want to teach animation to a spider.)
Article 2 will how Animation Objects are contained in Layers. Although the discussion so far implicitly assumes that the animation
engine calls the methods of AnimationObject directly, a better design is to have the Animation Object contained in a "Layer", and its
methods to be called via the Layer container object. Article 3 will discuss how layers, layer folders and animation objects are used
in an animation engine. It will also discuss how to break up an animation into layers for more modularity.
Summary
A Graphic Object is an abstraction for anything that contributes to the content of a single frame of animation. A Graphic Object can
be visible on the screen, such as objects on the screen, or it is something invisible, but that affects the rest of the objects that are
visible, such as a Camera Graphic Object. Most Graphic Objects require a "position" property, while some do not need a "position"
such as the background Graphic Object.
An Animation Object is an abstraction for the extension of a Graphic Object across a range of frames. An Animation Object contains
one or more Graphic Objects. The animation application can consist of one or more Animation Objects. The method
AnimationObject::get_next_frame() performs computations necessary to get its list of Graphic Objects drawn to the display. Other
methods on the Animation Object cause it to pause, resume, rewind or reverse.
An animation application or game implementation can become very complex simply due to the large number of Graphic and
Animation Objects involved, even ignoring all the game logic and drawing and interaction of each piece of the animation/game,
making an object oriented approach useful for managing the complexity. The next article discusses how the concepts ofFrames,
Layers and Layer Folders help organize of the multitude of things that need to be drawn and animated in your game.
Continue to Part 2: Frames, Layers and Layer Folders
Top of Form
Join our mailing list to keep up with the latest news and updates about Cprogramming.com!
Name
Bottom of Form
-----