From: Andrew Dalke (dalke_at_ks.uiuc.edu)
Date: Fri Feb 14 1997 - 12:56:27 CST

  We held our first VMD workshop yesterday and the day before for
people here at the UIUC campus. We covered the main topics found in
VMD and included some of the VMDTech postings from the last few weeks.
We've put most of the files on our web server at
http://www.ks.uiuc.edu/Research/vmd/workshop/ so others can have
access to it. It isn't in a too usable shape now, but we'll fix it up
this afternoon and add the needed structure and trajectory files.

One of the new things on it is a tutorial on how to make movies. This
week's VMDTech article, then, is about how to do just that. VMDTech,
for those people who joined the mailing list in the last week, is a
weekly article we write for the list concerning some topic of VMD that
we believe will be helpful to most users.

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

                        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:

 o Deciding what to put in your movie
 o Writing an animation sequence from VMD
 o Saving each still image to a file
 o Using another program to convert the images to a
               correct movie format

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

                        What will you show?

  There are many things from which to make 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 can show the
results of an MD simulation or change transparancy parameters to
dissolve the 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 method, you'll need some way to schedule
the sequence of events. You could try to do it by hand, but that gets
very tedious. The best is to come up with a script that does what you
want automatically. You could record a log file and play it back, but
it is rarely smooth.

  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 use one of several 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 i2.rle ... i9.rle i10.rle
        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, ...."

You can get that form with 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 assume there are 4. Then

        vmd > format "%04d" 5

        Info) 0005

The following code adds the code needed to keep track of successive
filenames. You can see the original example still in it, but there
are four more lines added to keep 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 then enter '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.rgb.rgb
snap.0003.rgb snap.0007.rgb snap.0011.rgb snap.0015.rgb

You could use a program like display, xv or ipaste to look at a few of
the files and verify they have different images. We suggest 'display'
from the ImageMagick tools at
http://www.wizards.dupont.com/cristy/ImageMagick.html

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 and let you 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 "mediaplayer" on the SGIs or xanim from
ftp://ftp.x.org/contrib/applications/ . 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 {\sf convert} from
the ImageMagick tools.

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

The 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 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 (with the Open->File
option), and you should see the rotating image.

  The downfall with this image is 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 can 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. 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 the 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 your code to take the pictures and
save it 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, and the current filename, etc. There is. 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. You can also have it save only every nth image, so the
pictures it saves might be numbers 0, 5, 10, 15, ... . Its default
setting uses the 'snapshot' renderer option, but it can be made 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 be changed as need be. Following is the script itself, then
will be 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 can change the pattern like this:

        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 Raster3D input file, which needs to be
rendered. The third line is used after the Raster3D information is
saved to a file so it is 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 the options to their default values, eg. resets the
image number to 0, returns the rendering method to snapshot, etc. You
must remember to use this when you make a mistake and need to start
over, otherwise the images will continue counting from where you left
off.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

                        More 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 then causes that to fade away and show the 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.

        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 opaquicity of the transparent colors
                for {set color 17} {$color < 34} {incr color} {
                        color change alpha $color [expr $i*$i]
                }
                # and the transparent color scale (66 to 97)
                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
        }
        # turn the normal updating back on
        display update on

Why is there a "[expr $i*$i]" instead of just using $i ? Because the
colors didn't seem to get transparent fast enough. It was purely an
esthetic choice.

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

  As a hint for those who hadn't figured it out yet, I think VMD's
scripting language is one of my favorite features :) If you have
ideas, suggestions or comments for the next VMDTech, please mail them
to the list or to vmd_at_ks.uiuc.edu,

                                                Andrew Dalke
                                                dalke_at_ks.uiuc.edu