Computer animation involves continuously modifying something about an object on the screen. This can be its position, color, or even the overall shape (by modifying multiple points at once). This article will explain the details involved in making your own animations in a program.
Any animation can be broken up into pieces, such that the animation smoothly progresses from one to the next. If you are trying to animate a car driving down a city street, for instance, you can break up the animation into straight forward driving, turns, and pauses as the car waits at a light.
We can define the start and end states of each of these as a "keyframe", and can describe the entire animation using the keyframes alone.
Now that we have defined a set of keyframes, we can simply switch from one to the next, but this will result in very jerky animation. We can smooth out the animation by calculating intermediate frames whose positions are interpreted based on the desired position between the two states. This process is called "tweening" in the animation industry, the word being a shortened form of "in-betweening" or calculating the frames "in between" two keyframes.
The most straightforward way to implement tweening is to create a function that accepts 3 parameters: starting value, ending value, and position. The position is a percentage representing how close the value is to start or end. At 0%, the output value is exactly at the starting value; at 100%, it is exactly at the ending value; at 50%, it is exactly in the middle.
A simple calculation is as follows, assuming "position" is a value from 0 to 1:
It is easy to perform tweening in 2 or even 3 dimensions – it simply involves computing the inbetweens separately for each dimension. This allows us to easily write a tweening function that supports 2D or 3D points without putting in significantly more effort.
The above tweening function is a simple linear tween. However, we can use other functions as well – if we want the animation to start out slowly and then speed up near the end, we can use an exponential function, and if we want a 2-dimensional object moving along a circle, we can use a modified form of the circle equation. This is outside the scope of this tutorial but is an interesting topic nonetheless.
How do we actually animate something on the screen? In its basic form, an animation is just a loop that:
- computes the values of the objects on the screen (by incrementing the parameter in the tweening function mentioned above)
- draws them, and
- waits for a predetermined amount of time (a delay) in order to time the animation
The animation's frame rate – or number of frames per second – can be changed by adjusting the aforementioned delay; a higher framerate (lower delay) will result in a smoother animation but demands more from the computer. We must also compensate by incrementing the tweening parameter less, otherwise the animation will speed up and slow down. If we double the frame rate, we must halve the increase in the parameter.
In a multitasking operating system, there is no guarantee that the animation will be exact – it's not uncommon for the animation to be delayed by several frames. If we base the animation on a real-time clock instead of merely incrementing for every cycle of the animation loop, the animation will be much more consistent – our object will move across the screen in the exact same amount of time, even though it may skip rendering a few frames here and there. This is aptly named "frame skipping".
The drawing methods in many programming languages clear out the screen before drawing anything, in order to prevent the previous frame from "bleeding through". Since animation involves many continuous updates to the screen, however, this can result in a noticeable flicker as the screen is cleared and redrawn multiple times in a second. The solution to this problem is double buffering.
As the name implies, "double buffering" involves rendering all objects to a second off-screen buffer and then rendering the contents of the buffer to the screen all in one go. This will eliminate flicker since there is only one drawing operation taking place.
Many programming languages and frameworks have built-in ways of activating double
buffering; in Visual Basic or C#, for instance, it's enough to set the
property of a Form. If this is not supported, it's possible to manually implement
it as follows:
Method Paint(Graphics g)
img = new image, g2 = new graphics context from img
Draw img to screen's graphics context g
Method Paint2(Graphics g)
Perform the actual rendering here
So there you have it – computer animation demystified. These techniques are used in my Computer Puppetry project.