Accessibility
 
Home / Developer Center / Director Developer Center /

Director Article

Icon or Spacer Icon or Spacer Icon or Spacer
Andrew Phelps
 

Generating Perlin noise with Director MX


For those of you not in the know, Perlin noise and its various derivatives and enhancements are used throughout the 3D games industry to provide more realistic and better looking 3D worlds by adding grease, grime, dirt, and dust to objects so they don't look too "clean." This article focuses on building Perlin style noise from within the Macromedia Director MX environment.

In writing this article, I made use of code adapted from several sources. I provide references at the end, as well as further reading and ideas for incorporating Perlin noise into more complete applications. To use the sample files, or to follow these techniques, you'll need both Macromedia Director MX and Macromedia Flash MX.


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:

 
Example of Perlin noise
 

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:
 
Wrapper classes Lingo object
 

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.

   
  Noise 2D
   
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:

 

 

  Smooth noise 2D
 

 

3

Add noise together at multiple octaves:

   
 

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:

 
Examples of Perlin 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:
 
Windows   Macintosh
Download the sample file director_file.zip (191K)   Download the sample file director_file.sit (160K)
Download the sample file flash_file.zip (4K)   Download the sample file flash_file.sit (6K)
 

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.