Chapter 16 Animation
An animated image is simply a whole lot of similar images strung together. We will procedurally generate animated images by taking a transformation and applying it over a series of individual frames. For example, if we want a ball to roll across the screen, we could frame that as a
move
command that is applied increasingly over time. We can think about this as if we’re adding an extra argument to move, representing the amount of the transformation to apply.move 400 0 0 0
move 400 0 0 0.25
move 400 0 0 0.5
move 400 0 0 0.75
move 400 0 0 1
Here we have the move command applied first at 0%, then in 25% increments until we get to 100%. The entire animation would take place over 5 frames.
Section 16.1 Knobs
In MDL, we will create this effect using a new type of variable called a knob. A knob is an optional parameter to any transformation command.If a knob name is present at the end of the transformation, it means that transformation is designed to be applied incrementally over some number of frames.
We will define the behavior of the knob in a new MDL command:
vary
that looks like this:vary knob start_frame end_frame start_value end_value
This says modify the value of
knob
between frames start_frame
and end_frame
so that it changes from start_value
to end_value
. Here is an example of creating and using a knob:move 400 0 0 knobby vary knobby 0 5 0 1
These two commands would create the series of
move
commands shown above.Some important things to keep in mind about how
vary
works in MDL.- You could have multiple vary commands for the same knob, as long as they don’t overlap in frames.
start_frame
should always be less thanend_frame
.end_frame
should always be less than or equal to the total number of frames.- The value can increase or decrease over time.
- The value range can be bounded by any floating point values.
- The frame and value ranges are inclusive.
Section 16.2 Implementing Animation in MDL
In addition to knobs and the
vary
command, we’ll have 2 other new commands:frames x
: Set the total number of frames for the animation.basename s
: Set the base file name for each frame file.
In order to produce an animation, we will go through the operations list three times.
Subsection 16.2.1 Animation Pass 0
Pass 0 is designed to both check if animation code is present at all, and set the initial parameters for the animation. This deals specifically with the
frames
and basename
commands, while also looking for the presence of vary
. Specifically:- Set
frames
andbasename
to be used throughout your code generator. - If
vary
is present, butframes
is not, this should be considered an MDL compiler error to be caught by your code generator, handle it accordingly. - If
frames
is preset, butbasename
is not, print a warning, and set the name to be used to some default value.
Subsection 16.2.2 Animation Pass 1
This is the bulk of the new work for animation. In this pass, we will compute all the knob values for every frame and store them in a data structure to be used when we actually draw each frame.
Create an array/list, where each index represents a frame. In turn, each index will contain a list of the knobs and their values for that frame. When you see the
vary
command, compute how it modifies knob values, and add entries in the knob table for each frame covered in the vary
command. Use a simple linear interpolation for the change (i.e. total_change/frames ). The knob list for the example at the beginning of this chapter might looks something like this in python:[[{'knobby': 0.0}], [{'knobby': 0.25}], [{'knobby': 0.5}], [{'knobby': 0.75}], [{'knobby': 1.0}]]
Subsection 16.2.3 Animation Pass 2
This is the normal drawing loop with 3 potential changes (depending on if the frames is greater than 1). * Ignore
frames
, basename
and vary
commands, as they would have been taken care of in passes 0 and 1. If frames is 1, do nothing differently from the non-animation code generator.If there are more than 1 frame:
- Before iterating over the operations list, go through the knob values computed from pass 1. Update the symbol table accordingly with each knob value.
- Go through the operations, when a knob is present, use the value stored in the symbol table to modify the values of the transformation.
- Ignore the
display
andsave
commands, no one wants to have these things run all the time. - After drawing each frame, save it. Use the basename followed by a number (leading 0s are very useful, see the assignment for tips on adding them).
- After drawing all the frames, stitch them together into an animated gif, more on that below.
Section 16.3 Dealing with frames and animated gifs
You will be generating a lot of images. You should create a directory to store all the frames so they don’t overrun your code directory. To turn these individual frames into a gif, we will use 2 utilities from the imagemagick suite:
$ animate
Will display an animation based on the files given as parameters. You can individual list files like this: $ animate frame0.png frame1.png frame2.png
or, the better option, use the *
character. This will only work if your files all have the same start to their names. It will stitch them together in the same order that they appear when running $ ls
, which is why I suggest using at least 1 leading 0 when naming the frames. animate
should also be used when displaying an animated gif. Using the display
command is not advised.$ convert
can be used to make animated gifs from multiple files. If you give convert multiple files and specify the output format as a gif, it will automatically create an animated gif. Working similar to animate
in terms of the ordering of files. There is an extra argument which you may want to use called -delay
it helps specify the framerate.- Normally, we think of framerate in Frames Per Second (fps). So 24 fps would mean 24 frames every second, this is the standard for film-based movies. 30 fps is the standard for TV shows (at least in the US, 25 for the rest of the world). 60 fps is a common HD framerate.
- gifs measure frames a little differently, counting delays between frames in 1/100 second units. So we tend to think of gifs not in fps but in delay between frames, which is actually seconds per frame. To turn that into fps, just invert the value.
-delay t
will put at/100
second delay between each frame. So ift
= 20, there will be 1/5 second delay between frames or 5 fps. A delay of 1.7 is close to 60fps, 4.1 is close to 24fps, 3.3 is close to 30fps.- An example of using
convert
on a bunch of images that begin with the name rolling:$ convert rolling* -delay 1.7 rolling.gif