Drew Mokris
EECS 487: Interactive Computer Graphics
Special Assignment
October, 2005

2D Vector Graphics: Macromedia Flash

Table of Contents:

Introduction

For my EECS 487 special assignment, I would like to talk about 2D vector graphics on the web, specifically, Macromedia Flash.  I run a Flash-based website, spinnerdisc.com, which features all-original Flash animation content.  Brendan Blanco, president of U of M's SIGGRAPH chapter, has been bugging me to teach a Flash workshop, so hopefully this topic is sufficiently graphics-related for this assignment.

I began learning how to use Flash about a year and a half ago, during my summer vacation.   I picked up a book, namely, Macromedia Flash MX 2004 for Windows and Macintosh : Visual QuickStart Guide, and taught myself.  Some of what I've learned about Flash (and mentioned in this paper), comes from this book.

Flash is sometimes shrugged off as a toy program, but it is a great tool for 2D animation, and also comes packaged with its own scripting language.   The system is optimized for web-delivery, and because it is purely 2-Dimensional, it does not exercise many of the topics we've discussed in class, but it does lend itself to some interesting technical discussion.

Scalable Vector Graphics

Flash can be used as a paint program, much like Adobe Photoshop.  In fact, it has a complete layer-system, very similar to Photoshop's.  There is, however, one important difference: Flash uses vector graphics, rather than bitmapped graphics.

In a paint program like Photoshop, or Macromedia Fireworks, when a line is drawn, an algorithm is used to map this line to pixels, choosing which pixels to color in (in class, we used the Midpoint Line Drawing Algorithm to rasterize lines in this way).  This double array of color values is what represents the image in a bitmapped photo.  Thus, when one zooms into a bitmap, they will see the pixel blocks, as no image information is saved below a certain resolution level.

In a vector graphics system, like Flash, a line is stored by its equation in the coordinate system.  This equation is used to rasterize the pixels that a viewer sees at runtime.  This means that no matter how much a Flash-drawn image is magnified, the viewer will never see a blocky or jagged image.   Here is a cartoon drawing of one of my dogs as a demonstration:


In a way, this is similar to our rasterization in OpenGL.  In our project, we rasterized the 3D model every frame.  When doing so, we used the vertex positions to recalculate the new pixel positions, and then interpolated colors accordingly.  An OpenGL model is not encoded as a series of pixel values, but rather a series of vertex positions and colors.  When zooming into a model, one would not see the jagged pixel blocks because the image was being re-rasterized every frame.

There are however, limitations to this method of drawing in 2-dimensions. Because every curve is encoded by a equation instead of pixel values, Flash does not lend itself well to creating textured images.  To create an area with a complex texture in Flash, many curves would have to be encoded, and the filesize would grow much more quickly than it would using a bitmap imaging program.

Keyframe Animation

Another important feature of Flash is its temporal dimension.  Flash uses a frame-based timeline to allow users to create animations.  It mimics the animation techniques of "by-hand" animators, and even borrows some of the terminology.

In Flash, a keyframe is used to represent a key portion of the animation.   In hand-drawn animation, a keyframe might be the beginning of a small sequence.  The end of the sequence is specified by another keyframe, and then in-between animators, or "tweeners" fill in the rest.

With flash, we also use keyframes to represent the beginning and end of a sequence, but we also have a processor at our disposal.  With a computer, it is very easy to interpolate between two frames of animation:

Flash can interpolate changes in scale, color, and opacity (and it will do so linearly, unless specified otherwise).  This ability is directly inspired by hand-animation techniques, but it attempts to use computational methods to automate a portion of the process.

Masking

One of my favorite features of Flash is its ability to create layer masks.   Masking is a feature that allows one to partially hide a layer by defining shapes on the layer above it.  I have a cartoon series called "Tiny Plaid Ninjas" (see www.spinnerdisc.com/TPN.html, for the three current episodes) that uses this technique extensively.  Part its style lies in the noticeably stationary plaid fills used to colorize the characters.  Here, I show how this is done:



This is just one fun thing that can be done with layer masks.  The above demonstration makes use of static masks (i.e.: masks that are hardcoded before runtime).  Flash also has the ability to create dynamic masks.

Using Actionscript, Flash's built-in scripting language, we can duplicate a movie clip, and set it to mask another movie clip below it.  I used this technique to create this fun demonstration (click anywhere on the image below):




See the ripple?  If not, keep clicking.

To create this, I first found a suitable bitmapped image on Google (this one resides at http://www.eeb.uconn.edu/Courses/EEB271/Boraginaceae/Hydrophyllum%20leaf.jpg), imported it into Flash, and then I created two versions of it.  The first version was unchanged, and sat on the bottom layer of the movie.  Above this, I put a slightly enlarged and shifted version of the same image (and named it "leaf_image").   Then, I needed a mask.  For the ripple, I created this animation using shape-tweens:


This movieclip, which I named "ripple", is then duplicated (on every mouseDown event in the area of the window), moved to the location of the click, and then set to mask "leaf_image".  The actionscript looks like this:

  onClipEvent (mouseDown) {
     if(!_global.ripple_playing){
        // This puts the new ripple above everything else:
        _root.ripple.duplicateMovieClip("ripple"+_global.i, _global.i);
        _root["ripple"+_global.i]._x = _xmouse + 300;
        _root["ripple"+_global.i]._y = _ymouse + 200;
        _root.leaf_image.setMask(_root["ripple"+_global.i]);
        _global.i++;
     }
  }

Thus, the photo referred to as "leaf_image" is actually invisible unless the user has clicked on the screen.  Doing so will create a mask that will show the shifted image in the area of the ripple, creating the effect.

This code, however, exposes two of my simplifying assumptions.  First, I assume it is not necessary (at least for this small demo) for ripples to be deleted after they have finished their animation.  And second, I limited it so that only one ripple can be playing at a time (using a global bool called "ripple_playing").  I did this because of Flash's limitations with dynamic masks: only one movie clip can act as a mask for another at one time (I'm still searching for a hack around this).

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

In summation, Macromedia Flash utilizes vector-based graphics to deliver interactive animations to the web.  Using the timeline, the program can make some simplified animations more easily by "tweening", that is, interpolating changes to a symbol across two keyframes.  Another powerful tool is masking, whereby only parts of an image are displayed (when inside a shape-area, or mask).  This, combined with actionscript, makes Flash a surprisingly great 2D tool for any programmer or artist.


Sources Cited