next up previous
Next: About this document Up: VMD Workshop Previous: The VMD Command Language

Making a Movie

This section describes how to take a sequence of images from the display and combine them to form a movie. There are several steps to this process, including:

Please note that this section can be viewed online at:
http://www.ks.uiuc.edu/ ulrich/movie.txt
If you launch netscape and visit this page, you will be able to cut and paste code examples into the VMD console.

What will you show?

There are many aspects of your research which might benefit from a movie of your system. You could, for instance, rotate the model around the Y axis to lend a sense of depth that a single image doesn't give. You could also show the results of an MD simulation or change transparency parameters to dissolve a molecular surface slowly from the display. These examples will be shown below, and there are are many other possible movies you might want to make.

Writing Animation Frames and Merging Them into a Movie

Once you've come up with a concept, you'll need some way to schedule the sequence of events in your movie. You could try to do it by hand, but that would get very tedious. Another alternative is to record a log file and play it back, but this is rarely smooth. The best bet is to come up with a script that does what you want automatically.

For example, here is a simple script to rotate the molecule around the screen vertical (the "Y" axis), 20 degrees at a time, returning to its original position at the beginning.

        for {set i 0} {$i < 360} {incr i 20}  {
                rotate y by 20
        }

For each of these rotations, you'll want to save the image on the screen to a file. This is done with the rendering commands. The fastest option is to take the image directly from the screen with the snapshot renderer. After you have the full sequence of images, you can then use one of several external programs to produce the movie. These programs usually require that the image file names fit the pattern prefix index suffix where the prefix and suffix don't change, and the index is a zero-filled value starting at 0 and increasing by 1 for each image. In other words, these are valid:

        snap.0000.rgb  snap.0001.rgb ... snap.0242.rgb  
        i0.rle  i1.rle  i2.rle  i3.rle

but these are usually not

        snap.0000.rgb  snap.0002.rgb ....
        i0.rle  i1.rle  ... i9.rle  i10.rle   (i.e. 1 digit to 2)
        a.gif b.gif c.gif

Also, if you stay with the recommended form, then you can always sort your list without a problem. For example, you might otherwise get a list of files like "i1.rle, i10.rle, i2.rle, ...." since alphabetically 1 < 10 < 2.

You can write files from VMD in this format using the format command. It uses a convention from C that will automatically generate zero-filled numbers if you tell it how many digits are available. You'll almost never generate more than 9999 images, so lets assume there are 4. Then an example of the format command is:

vmd > format "%04d" 5

Info) 0005

The following script adds the code needed to keep track of successive filenames. You can still see the original example in it, but there are four more lines added to keep track of the frame number and generate the filename.

        set frame 0
        for {set i 0} {$i < 360} {incr i 20} {
                set filename snap.[format "%04d" $frame].rgb
                render snapshot $filename
                incr frame
                rotate y by 20
        }

If you enter this code into VMD and then type ls snap.*.rgb you should see a list of the 18 images just created.

snap.0000.rgb  snap.0004.rgb  snap.0008.rgb  snap.0012.rgb  snap.0016.rgb
snap.0001.rgb  snap.0005.rgb  snap.0009.rgb  snap.0013.rgb  snap.0017.rgb
snap.0002.rgb  snap.0006.rgb  snap.0010.rgb  snap.0014.rgb 
snap.0003.rgb  snap.0007.rgb  snap.0011.rgb  snap.0015.rgb

You could also use programs like display, xv, or ipaste to look at a few of the files and verify that they have different images.

Lets turn this into a QuickTime movie using SGI's mediaconvert program. Start it up. Under File choose Select Input File. A file browser will appear. Choose snap.0000.rgb. Once the browser closes, click on Numbered Images. New options will be displayed, which are used to select the desired images to turn into a movie.

Here's where the file naming convention comes into play. On the entry box for File Template: replace the 0000 with ####. This will tell the program that those characters are the ones that can change. Your 18 images are numbered from 0 to 17, so change the value of End: to 17.

Now go over to File Format: in the center of the right side and choose QuickTime. There are different ways of setting up a QuickTime file so click on the arrow to the right of Video Parameters. A new menu will appear so that you may choose the compression method. Choose RLE, since we believe it compresses best for computer graphics. (Anyone want to suggest otherwise?) There's a slider there that lets you choose the degree of compression - the more compressed it is, the worse the image but the smaller the final movie file. Don't worry about this now, but you might want to see which values get better or worse results for you.

All that is left is to press the Start button in the lower right and wait for the file outfile.mov to be created. To view the file, use movieplayer on the SGIs or xanim. The latter is available on most X-based machines. That's it, you've made a movie!

Putting Movies on the World Wide Web

Now that you have put together an interesting movie, you may want to see it on a web page as an inline animated GIF. There are many ways to do this, but the easiest is to use convert from the ImageMagick tools.

        convert -delay 10 -loop 4 snap.*.rgb movie.gif

This routine produces a file called movie.gif with the option that when it is finished it will loop back to the beginning. Actually, it will loop four times and stop, except that Netscape doesn't stop looping. The delay value is the amount of time to wait between updates, in 1/100ths of a second, so the delay here is 1/10 of a second.

The image file can be used and viewed just like any other GIF file, but the best way to see it is in a web viewer like Netscape Navigator. Create the file movie.html and add the line This is an image: img src=movie.gif to it. Use the browser to open the HTML file, and you should see the rotating image.

The downfall with this image is that it is too large, so the display is slow. You can use one of many graphics tools to reduce the size of the images, or you could start the whole process over again but with a smaller display.

Other Helpful Movie Scripts

Here are some other standard scripts you might want to test out. As a note, remember that when you write these scripts you don't have to be too concerned about speed as that can easily be increased when piecing together the final images into the movie.

Suppose you want to make a movie of the complete trajectory for the top molecule. The following is a script that steps through each of the frames, one by one.

        # get the number of frames in the movie
        set num [molinfo top get numframes]
        # loop through the frames
        for {set i 0} {$i < $num} {incr i} {
                # go to the given frame
                animate goto $i
        }

Adding two lines of commands to save the image on the screen yields:

        # get the number of frames in the movie
        set num [molinfo top get numframes]
        # loop through the frames
        for {set i 0} {$i < $num} {incr i} {
                # go to the given frame
                animate goto $i
                # take the picture
                set filename snap.[format "%04d" $i].rgb
                render snapshot $filename
        }

However, once you start changing code to take the pictures and save them to disk, you will probably start to wish there was a better way, since otherwise you have to keep track of the current frame number, the current filename, etc. Luckily there is a better way. We've written a routine called take_picture which simplifies the example code to:

        # get the number of frames in the movie
        set num [molinfo top get numframes]
        # loop through the frames
        for {set i 0} {$i < $num} {incr i} {
                # go to the given frame
                animate goto $i
                # take the picture
                take_picture
        }

Every time take_picture is called, it takes a picture and saves it to a file using the current picture number. It then increments that value by 1. The default setting of take_picture uses the snapshot renderer option, but it can be made to call any of the other renderers. Since some of these renderers require another step to turn the information into an image, another parameter lets you run a UNIX command to process the output file. Finally, the default parameter for the format command is animate.%04d.rgb but that can also be changed if necessary. Below is the script itself, followed by some examples of how to use the different parameters. You'll want to copy and paste this into the VMD text window, or save it in a file and source it when needed.

proc take_picture {args} {
  global take_picture

  # when called with no parameter, render the image
  if {$args == {}} {
    set f [format $take_picture(format) $take_picture(frame)]
    # take 1 out of every modulo images
    if { [expr $take_picture(frame) % $take_picture(modulo)] == 0 } {
      render $take_picture(method) $f
      # call any unix command, if specified
      if { $take_picture(exec) != {} } {
        set f [format $take_picture(exec) $f $f $f $f $f $f $f $f $f $f]
        eval "exec $f"
      }
    }
    # increase the count by one
    incr take_picture(frame)
    return
  }
  lassign $args arg1 arg2
  # reset the options to their initial stat
  # (remember to delete the files yourself
  if {$arg1 == "reset"} {
    set take_picture(frame)  0
    set take_picture(format) "./animate.%04d.rgb"
    set take_picture(method) snapshot
    set take_picture(modulo) 1
    set take_picture(exec)    {}
    return
  }
  # set one of the parameters
  if [info exists take_picture($arg1)] {
    if { [llength $args] == 1} {
      return "$arg1 is $take_picture($arg1)"
    }
    set take_picture($arg1) $arg2
    return
  }
  # otherwise, there was an error
  error {take_picture: [ | reset | frame <number>| format <string> | \
method <renderer> | modulo <number>]}
}
# to complete the initialization, this must be the first function
# called.  Do so automatically.
take_picture reset

The current pattern for the file format is ./animate.%04d.rgb but if you need more than 9999 images you should change the 4 to be the maximum number of digits you'll need (and we would like to know if you are making any movies with that many images). For instance, if the files should be called image.00000.rgb through image.12345.rgb then you should change the pattern as follows:

        take_picture format image.%05d.rgb

You can also use this option to specify the directory for the output files. This is important because the images might take up a lot of space and you'll want to use a scratch space with more room.

        take_picture format /scratch/disk2/snap.%04d.rgb
Suppose you wanted to use Raster3D to make the images instead of just taking the snapshot. Before any of the other calls to take_picture, you'll want to do something like:

        take_picture format animate.%04d.r3d
        take_picture method Raster3d
        take_picture exec {render < %s -sgi %s.rgb}

The first line changes the file extension to .r3d so it is less confusing when you see the file name some time in the future. The second line changes the rendering method to Raster3D.

Of course, this just produces a Raster3D input file, which itself still needs to be rendered. The third line is used after the Raster3D information is saved to a file so that it will be automatically converted to an image file. The %s is automatically replaced by the current filename (just like in the Render form) and the whole string is executed by the UNIX shell. In this case, it calls the Raster3D renderer to convert the .r3d file into a .rgb file.

There are several other options, but the only other one you might use is,

        take_picture reset

which returns all options to their default values, eg. resets the image number to 0, returns the rendering method to snapshot, etc.

Examples

Now that the take_picture script has been explained, here are a couple more interesting ways to make movies that might prove useful.

Here's something I thought was fun. It starts off with a full surface representation that fades away to show an underlying tube representation. It works by changing the value of the transparency from 1 to 0. The surface color is transparent, but since the value is 1, it is really opaque. As the value decreases, the opaque tube in the center appears.

Since this depends on having two different representations, here is the code to set up the example structure. It uses the remote downloading feature of VMD to get the BPTI structure from the PDB FTP server. If this doesn't work, just use any structure you have handy.

        # if this doesn't work, use one of your own structures
        mol pdbload 9pti
        mol modselect 0 top protein
        mol modcolor 0 top index
        mol modstyle 0 top tube

        mol addrep top
        mol modselect 1 top protein
        mol modcolor 1 top resname transparent
        mol modstyle 1 top surf

Now that everything is loaded, here's the script to make the movie

        # take control of the updating
        display update off
        for {set i 1.0} {$i >= 0.0} {set i [expr $i - 0.05]} {
                # change the opacity of the transparent colors
                for {set color 17} {$color < 34} {incr color} {
                        color change alpha $color [expr $i*$i]
                }
                # and of the color scale
                for {set color 66} {$color < 98} {incr color} {
                        color change alpha $color [expr $i*$i]
                }
                # force the update
                display update
                # and take the picture
                take_picture
        }
        # return the alpha values to the default value
        for {set color 17} {$color < 34} {incr color} {
                color change alpha $color 0.3
        }
        # for the color scale as well
        for {set color 66} {$color < 98} {incr color} {
                color change alpha $color 0.3
        }
        # turn the normal updating back on
        display update on

Experienced script writers may ask why we used "[expr $i*$i]" instead of $i ? This was purely an esthetic choice based on our belief that the colors were not becoming transparent quickly enough.


next up previous
Next: About this document Up: VMD Workshop Previous: The VMD Command Language

Andrew Dalke
Tue Feb 18 12:18:10 CST 1997