 |
|
|
By the time you read this, there will no doubt be several
tutorials on integrating Macromedia Flash MX
with Macromedia Director MX. My article presents
a slightly less glamorous marriage of the two: accessing
Macromedia Flash MX for features of the ActionScript
language that are either not available or not easily
reproduced in Lingo. In order to illustrate the convenience
and power of these two languages coming together, I
examine a sample application
that generates Perlin noise to create a cloud texture
for
use in Director Shockwave Studio.
Examining Perlin noise
What is Perlin noise exactly? Simply
put, it's a way of making patterns from pseudo-random numbers.
This
concept
was first
introduced by Ken Perlin 1 and
is therefore named after him. Chances are
you've probably seen or heard of Perlin noise before if
you hang out with any 3D artists, although they might not
call it by that name. Perlin noise represents one kind
of procedural texture—a texture that is
generated by code rather than by a paint package:
|
| |
 |
| |
Procedural
textures
are powerful because they are easy to generate
and don't take up space until they are converted into
bitmap form. Since any good Shockwave 3D developer is always
on the lookout for ways to save space, this seemed like
a great idea. So I decided to create some Perlin noise
of my own with the eventual goal of creating some clouds
for a 3D shooter. The completed clouds are pictured above
(without the shooter code, for simplicity's sake). The
eventual engine for the entire game, including animated
cloud maps
and parallax cloud scrolls, will be featured at the Director
Online User's Group (DOUG) in the future.
The very first problem you face in creating textures from
Perlin noise is how to create the noise
itself.
Although Perlin noise (and any
textures derived from them) look random, they are not.
This is important to realize because you actually want
to be able to generate the same texture more than once.
In particular,
it's easy to animate textures based on this approach by
changing their seed values ever so slightly over time.
If it
were all based on calls to the random() method, the
illusion would be lost.
Writing a pseudo-random number
generator
What you really need is a pseudo-random number generator
so that you can produce noise that looks random but always
yields the same values when given the same input. While
researching this article, I stumbled upon an example
of this technique in Special Effects Game Programming
with DirectX by Mason McCuskey 2,
which referenced two sites by Hugo Elias 3,
4.
In turn, these sites presented a great implementation of
a pseudo-random generator whose author is, unfortunately,
unknown.
This, and most other, implementations of pseudo-random
number generation operate by performing an operation
known as a bit-shift, which is unavailable in
the standard Lingo language. (There are probably ways to
code around
this
but in the MX world there is no need to.) Bit shift operators
are part of the standard language of Macromedia Flash
MX and we can call ActionScript from Macromedia Director
MX
with ease. The code to generate our noise is presented
below:
The
following code represents the core of the pseudo-random
number generator. This is written in Macromedia Flash
MX because Macromedia Flash offers a much more complete
math engine and access to direct bit shift operators:
|
| |
perlin = new Object();
perlin.Noise2D = function (x, y) {
x = Number(x);
y = Number(y);
n = x + y * 17;
n = (n<<13) ^ n;
return ( 1.000 - ( (n * (n * n * 15731 + 789221) +
1376312589) & 0x7FFFFFFF) / 1073741824.0);
} |
| |
Note: This
pseudo-random number generator first appeared on Elias's
wonderful website article about Perlin noise
and was republished in McCuskey's Special Effects Game
Programming with Direct X.
The
complete script for Perlin noise is available in the downloadable
file.
It doesn't particularly help that we have the
ability to create random things in Macromedia Flash MX
because
Shockwave Studio is only available in Director MX, and
our goal is to produce textures usable in Director Shockwave
Studio. The
Macromedia
Flash MX file containing the above script was imported
into Macromedia Director MX. Specifically, the script
is attached to Frame 1 of the Macromedia Flash MX file,
which contains no other buttons, objects, or symbols.
In order for a Macromedia Flash file to
play successfully in Macromedia Director MX (and thus in
order
to reach Frame
1 and execute
the script) the file must be on the Stage and must be
"visible." I put that word in quotes because although
it must
technically be visible, there are in fact two ways around
this limitation:
- Uncheck the box in the
Property inspector that tells Macromedia Flash MX
to render the image of the associated sprite onto the
Stage.
This
does make the sprite render but because there is
nothing to draw it
has no effect.
- Simply slap the Macromedia Flash MX sprite on the
Stage, leave
its direct-to-stage property false (because performance
is not an issue to create a single frame, nonanimating
movie),
and then cover it with your Shockwave 3D sprite.
This sprite will almost always be rendered direct-to-stage.
Using either
technique, the Macromedia Flash MX sprite
is technically playing on the Stage and thus executes
its scripts. However, it is not visible as a part of the
movie.
Creating an image from the code
Now we can generate
images. The following code uses the
simplest possible mechanism for doing so, which is the
Noise2D function from the previous
ActionScript example:
|
| |
on Noise2D me, w, h
flashObj = gFlashSprite.getVariable("perlin", false)
if not voidP(flashObj) then
flashObj.maxH = w
flashObj.maxV = h
theImage = Image(w, h, 32)
repeat with iHeight= 0 to h
repeat with iWidth = 0 to w
sRand = flashObj.Noise2D(iWidth, iHeight)
cIntensity = ((1.000 + sRand)*128)
theColor = rgb(cIntensity,cIntensity,cIntensity)
theImage.setPixel(iWidth, iHeight, theColor)
end repeat
end repeat
return theImage
else
put "Error retrieving flash object"
end if
end
|
| |
| This code doesn't
generate good-looking textures but it does create a very
nice, if pixelated,
noise pattern. What you need next is the ability to
create a smoothed version of the noise pattern to interpolate
from
one pixel to the next and average the values. The final implementation
creates a Lingo object that provides wrapper classes to several
functions created in the ActionScript. A diagram of these
wrappers, and the other functions created in the Lingo object
for texture creation, appears below: |
| |
 |
| |
Creating the
texture
Now that you can create several types of noise, the
only thing
left
to do is to make the actual texture. This is accomplished
by using the same noise pattern at several different "octaves"—meaning
that the texture repeats a different number of times
depending on which layer it's on. The layers are added
to one another with exponentially decreasing weights of
influence. For more chaotic patterns, use different seeds
in the noise maps for the various levels.
|
| |
|
| 1 |
Generate
the noise. In the final implementation, there is
no call to basic noise from within Macromedia Director
MX. The
ActionScript contains methods for Noise2D, SmoothNoise2D,
InterpolatedNoise2D, and even PerlinNoise2D if you
have the clock cycles to waste on full octave generation.
Generally speaking, SmoothNoise2D is good enough.
|
| |
|
| |
 |
| |
|
| 2 |
Smooth
the noise. This is the texture produced by a call
to SmoothNoise2D, as opposed to Noise2D within the
Macromedia Flash
MX object. Note that in the smoothed texture, both
the lights and darks are less pronounced and there
is also less focus than the basic noise pattern:
|
| |
|
| |
 |
| |
|
| 3 |
Add noise together
at multiple octaves:
|
| |
|
| |

|
| |
|
| |
You do this in various
routines all inside the "PerlinClouds" Lingo
script in the sample movie. Specifically, the stitched
textures are created using the StitchImage handler,
layered through the use of the MakeCloudBase and AddImage handlers,
subtracted from a solid color in the CalcCloudImage handler,
and finally post-processed in the PostBlur handler.
This is quite a lot of manipulation to produce a
single, high quality texture, but it's worth it in
the end.
There are two points here worthy of mentioning.
First, nearly all of the steps performed operate
in real-time
except for the actual generation of the first noise
image. Second, alpha maps are generated concurrently
in these handlers alongside the color textures
using a 32-bit color depth. A more complete implementation
would likely allow for the individual customization
of width, height, color depth, and so on. |
|
| |
Note: The
noise function in this demo will fail on texture generation
larger than 32 x 32 pixels because the seeds are not set
up to return values in a valid range beyond that size.
Here are some things to consider when using this approach:
- What is the target speed of the client's machine? Would
it be better to pregenerate the textures at authoring time?
- How many layers of multitexturing can the 3D hardware
of the client machine handle?
- Noise generation isn't real-time, but much of the image
compositing and actual texture creation are. Consider
splitting the creation of the noise from the other
elements and
using pregenerated noise but real-time image compositing
to produce several different textures from the same base.
- Are there checks in place to make sure that a texture
is not generated at too high a level of detail? Or will
all
generated pixels have space to render on screen?
What's next
Now that you have some good Perlin-style textures to
work with, what's left to do with them? The possibilities
are
endless. Perlin texture mapping in two- and three-dimensional
space is an effective technique for generating many different
effects. A few common uses include clouds, marbles,
slimes, dirts, and stuccos. Each of these materials
is somewhat repetitive, but visually appears random.
Each can be represented easily by the patterns produced
with pseudo-random noise:
|
| |
 |
| |
There is an
almost limitless number of possibilities for the use of
these
techniques
in 3D worlds. That they do not operate real-time (yet)
is of small concern—the noise can be generated
while other parts of a world are loading so that it's
all ready
to go when the user begins to navigate the scene. Another
alternative is to use these scripts in authoring mode.
This pregenerates the textures before shipping a world
in which bandwidth is less of an issue, such as on a
CD project or in downloaded native executables.
Perlin noise and other procedural generators
are powerful techniques. They are a powerful addition
to the Shockwave 3D world because they generate
textures from code instead of pictures. Many of these techniques are possible
now that ActionScript code can be called directly from within Director MX.
Previously, operations such as this would have required an Xtra to extend the
Lingo language. In this article's example, the bit shift operators were a compelling
reason to develop the pixel-generation routines in ActionScript in conjunction
with the powerful imaging features available through Lingo.
The integration
and availability of the entire ActionScript language from within the Lingo
environment is a powerful tool. Don't discount it by thinking
it's only useful for getting vector-based content into
Director MX. |
| |
Source
files
Download the source code for this tutorial here: |
| |
| |
| |
Additional reading |
| |
- Perlin, Ken. "Coherent
Noise Functions Over 1, 2, and 3 Dimensions" (cited
November 22, 2002).
- Perlin, Ken. "Making
Noise." Presentation from the Game Developers
Conference, 1991 (cited November 22, 2002).
- Perlin, K. "An Image Synthesizer," SIGGRAPH
85, pp. 287-296.
- Perlin, K. and E. Hoffert, "Hypertexture," SIGGRAPH
89, pp. 253, 262.
- Foley et al. Computer
Graphics Principles and Practice in C, Second Edition.
Addison-Wesley, Reading, Massachusetts: 1996. pp. 1015–1018.
- Peachey, D.R., "Solid Texturing of Complex Surfaces," SIGGRAPH
85, pp. 279–286.
- Rogers, David F. Procedural Elements for Computer Graphics,
McGraw-Hill, 1985.
- Upstill, Steve. The Renderman Companion: A Programmer's
Guide to Realistic Computer Graphics. Addison-Wesley,
Reading Massachusetts: 1990.
- Mine, Antoine, and Fabrice Neyret. "Perlin
Textures in Real Time Using OpenGL." Technical
Report RR-3713, INRA, France, June 1999 (cited November
10, 2002).
- Akenine-Moller, Tomas, and Eric Haines. Real-Time Rendering,
Second Edition. AK Peters, Natick: Massachusetts:
2003. pp. 126–129.
- McReynolds, Tom, David Blythe, Brad Grantham, and Scott
Nealson. "Advanced
Graphics Programming Techniques Using OpenGL." SIGGRAPH
99 (cited December 11, 2002).
|
| |
| References |
| |
1 Ebert,
Davis S., et al. Texturing
and Modeling: A Procedural Approach, Third Edition. Morgan Kaufmann
Publishers, San Francisco: 2002.
2 McCuskey, Mason. Special
Effects Game Programming with DirectX. Premiere
Press, Cincinnati: 2002.
3 Perlin
Noise by Hugo Elias
(cited November 21, 2002).
4 Cloud
Cover by Hugo Elias
(cited November 21, 2002). |
| |
| |
|
About
the author
Andrew Phelps is an assistant professor at the Rochester
Institute of Technology, in Rochester, NY. He is the founding
faculty member of the Game Programming Concentration within
the Department of Information Technology and his work in
games programming education has been featured in The
New York Times, CNN.com, USA Today, National
Public Radio, and several other articles and periodicals.
He also regularly
publishes in the Director Online User's Group (DOUG) on
topics related to graphics, rendering, and 3D worlds, including
the popular D3DISO series. He maintains a website featuring
his work as an educator, artist, programmer, and game addict,
and currently teaches courses in multimedia programming,
game engine development, 2D and 3D graphics, web design,
and information technology theory. He can be reached at amp@it.rit.edu. |
| |
| |
|
|
|