Recipe 8.11.
Creating Perlin Noise
Problem
You
want to create random
organic effects, such as
clouds, smoke, or water.
Solution
Use the perlinNoise( ) method of the
BitmapData class.
Discussion
Like the noise( ) method, perlinNoise( ) creates random
patterns on a bitmap. However, Perlin noise uses an algorithm that
produces smooth, organic-looking textures. It was created by Ken
Perlin for creating textures
in the movie Tron. These textures
are perfect for use as explosions, smoke, water, and many other
natural-looking effects, and since they are generated by an
algorithm, they require much less memory than bitmap-based
textures. The usage is as follows:
bitmap.perlinNoise(baseX, baseY, octaves, seed, stitch, fractal,
channels, grayscale, offsets);
The first six parameters are necessary; the
final three are optional. Since there are so many parameters to
consider, let's create a simple example and then see what each one
does. The following code creates a bitmap, applies Perlin noise to
it and then displays it:
bitmap = new BitmapData(stage.stageWidth, stage.stageHeight, false, 0xff000000);
bitmap.perlinNoise(100, 100, 1, 1000, false, false, 1, true, null);
var image:Bitmap = new Bitmap(bitmap);
addChild(image);
Add this code to a new class, and run it to see
a simple Perlin noise pattern. See Figure 8-1 for an
example of what you should see. Now you can start changing
parameters and see what effect the changes have.
First off, baseX and baseY determine the size of the
pattern. Here they are set to 100 each. Try changing baseX
to 200 and baseY to 50 and see how that stretches out the
noise horizontally. Already you can see that it looks a bit like
rippling water, as you can see in Figure 8-2.
The octaves parameter is an integer
that determines how many iterations of noise to create. More
octaves makes more detailed noise, and of course take longer to
produce.
The seed parameter works exactly like
the seed in the noise( ) method. If you specify the same
seed each time you run the program, you get the same noise
pattern. Setting this to a random number gives you a different
pattern each time.
The stitch parameter, when set to
true, makes the left and right, and top and bottom sides
of the pattern match up. This allows you to make a small bitmap and
tile it, such as in a bitmap fill from the drawing API, as shown in
the following example:
bitmap = new BitmapData(100, 100, false, 0xff000000);
bitmap.perlinNoise(100, 100, 2, 1000, true, false, 1, true);
graphics.beginBitmapFill(bitmap);
graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
graphics.endFill( );
Here, the bitmap is 100x100, and the
stitch parameter is set to true in the
perlinNoise( ) call. The bitmap is used as a bitmap fill and
tiles seamlessly.
When set to true, the fractal parameter results in the
edges of the gradients being smoothed out more. To see it in
action, start with this code:
bitmap = new BitmapData(stage.stageWidth, stage.stageHeight,
false, 0xff000000);
bitmap.perlinNoise(200, 100, 5, 1000, false, false, 1, true, null);
var image:Bitmap = new Bitmap(bitmap);
addChild(image);
After you see the image that creates, change
fractal to TRue:
bitmap.perlinNoise(200, 100, 5, 1000, false, true, 1, true, null);
Notice the difference that made (see Figure
8-3)? This parameter is useful for making things like cloud or
fog, as you can see by the example, which is already starting to
look like clouds.
The next two parameters, channel and grayscale, work exactly like
they do in the noise( ) method. The channel can be any of
the following: 1, 2, 4, or 8, representing the red, green, blue,
and alpha channels, respectively. 1 has been used in the examples
so far, for brevity, but it is recommended that you use the static
properties of the BitmapDataChannel class: RED, GREEN, BLUE, and ALPHA, to avoid typos.
Of course, if you set grayscale to
TRue, it doesn't matter which color channel you specify,
as the resulting image will be grayscale. However, if you set it to
false and specify one or more color channels, you can
create colored patterns. The next example creates some red
clouds:
bitmap.perlinNoise(200, 100, 5, 1000, false, true,
BitmapDataChannel.RED, false, null);
The following code produces a multicolor pattern
by using all three color channels:
bitmap.perlinNoise(200, 100, 5, 1000, false, true,
BitmapDataChannel.RED |
BitmapDataChannel.GREEN |
BitmapDataChannel.BLUE,
false, null);
You can also make Perlin noise on the alpha
channel, which is useful for creating transparent cloud effects or
fog.
The final parameter is offsets. This is an array of
Point objects. Each point specifies how much a single octave
is offset on the X- and
Y-axes. If your Perlin noise
has more than one octave, you probably want to make an array of
points equal in length to the number of octaves, and include the
same point for each element. Otherwise, each octave scrolls
differently, or not at all. Of course, you can use this for some
interesting parallax effects. The following example shows a
two-octave Perlin noise pattern scrolling on the X-axis:
package {
import flash.display.Sprite;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.events.Event;
import flash.geom.Point;
public class Clouds extends Sprite {
private var _bitmap:BitmapData;
private var _xoffset:int = 0;
public function Clouds( ) {
_bitmap = new BitmapData(stage.stageWidth, stage.stageHeight,
true, 0xffffffff);
var image:Bitmap = new Bitmap(_bitmap);
addChild(image);
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
public function onEnterFrame(event:Event):void {
_xoffset++;
var point:Point = new Point(_xoffset, 0);
// use the same point in both elements
// of the offsets array
_bitmap.perlinNoise(200, 100, 2, 1000, false, true,
1, true, [point, point]);
}
}
}
See Also
Recipes 8.5
, 8.6,
8.7
, 8.8,
8.9,
and 8.10
for other ways to add graphical content to a bitmap.
|