Skip to main content

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 than end_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 and basename to be used throughout your code generator.
  • If vary is present, but frames is not, this should be considered an MDL compiler error to be caught by your code generator, handle it accordingly.
  • If frames is preset, but basename 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 and save 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. animateshould 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 a t/100 second delay between each frame. So if t = 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