Many people have used random number generators in their programs to create unpredictability, make the motion and behavior of objects appear more natural, or generate textures. Random number generators certainly have their uses, but at times their output can be too harsh to appear natural. This article will present a function which has a very wide range of uses, more than I can think of, but basically anywhere where you need something to look natural in origin. What's more it's output can easily be tailored to suit your needs.
If you look at many things in nature, you will notice that they are fractal. They have various levels of detail. A common example is the outline of a mountain range. It contains large variations in height (the mountains), medium variations (hills), small variations (boulders), tiny variations (stones) . . . you could go on. Look at almost anything: the distribution of patchy grass on a field, waves in the sea, the movements of an ant, the movement of branches of a tree, patterns in marble, winds. All these phenomena exhibit the same pattern of large and small variations. The Perlin Noise function recreates this by simply adding up noisy functions at a range of different scales.
To create a Perlin noise function, you will need two things, a Noise Function, and an Interpolation Function.
Introduction To Noise Functions
A noise function is essentially a seeded random number generator. It takes an integer as a parameter, and returns a random number based on that parameter. If you pass it the same parameter twice, it produces the same number twice. It is very important that it behaves in this way, otherwise the Perlin function will simply produce nonsense.
Here is a graph showing an example noise function. A random value between 0 and 1 is assigned to every point on the X axis.
By smoothly interpolating between the values, we can define a continuous function that takes a non-integer as a parameter. I will discuss various ways of interpolating the values later in this article.
Definitions
Before I go any further, let me define what I mean by
amplitude and
frequency. If you have studied physics, you may well have come across the concept of amplitude and frequency applied to a sin wave.
The wavelength of a sin wave is the distance from one peak to another. The amplitude is the height of the wave. The frequency is defined to be 1/
wavelength.
In the graph of this example noise function, the red spots indicate the random values defined along the dimension of the function. In this case, the amplitude is the difference between the minimum and maximum values the function could have. The wavelength is the distance from one red spot to the next. Again frequency is defined to be 1/
wavelength.
| Sin Wave | | Noise Wave |
Creating the Perlin Noise Function
Now, if you take lots of such smooth functions, with various frequencies and amplitudes, you can add them all together to create a nice noisy function. This is the Perlin Noise Function.
You can see that this function has large, medium and small variations. You may even imagine that it looks a little like a mountain range. In fact many computer generated landscapes are made using this method. Of course they use 2D noise, which I shall get onto in a moment.
You can, of course, do the same in 2 dimensions.
Some noise functions are created in 2D
|
Adding all these functions together produces a noisy pattern.
|
Persistence
When you're adding together these noise functions, you may wonder exactly what amplitude and frequency to use for each one. The one dimensional example above used twice the frequency and half the amplitude for each successive noise function added. This is quite common. So common in fact, that many people don't even consider using anything else. However, you can create Perlin Noise functions with different characteristics by using other frequencies and amplitudes at each step. For example, to create smooth rolling hills, you could use Perlin noise function with large amplitudes for the low frequencies , and very small amplitudes for the higher frequencies. Or you could make a flat, but very rocky plane choosing low amplitudes for low frequencies.
To make it simpler, and to avoid repeating the words Amplitude and Frequency all the time, a single number is used to specify the amplitude of each frequency. This value is known as
Persistence. There is some ambiguity as to it's exact meaning. The term was originally coined by Mandelbrot, one of the people behind the discovery of fractals. He defined noise with a lot of high frequency as having a low persistence. My friend Matt also came up with the concept of persistence, but defined it the other way round. To be honest, I prefer Matt's definition. Sorry Mandelbrot. So our definition of persistence is this:
frequency = 2i
amplitude = persistencei
Where
i is the
i
th noise function being added. To illustrate the effect of persistence on the output of the Perlin Noise, take a look at the diagrams below. They show the component noise functions that are added, the effect of the persistence value, and the resultant Perlin noise function.
Frequency | 1 | | 2 | | 4 | | 8 | | 16 | | 32 | | | Persistence = 1/4 | | + | | + | | + | | + | | + | | = | | | Amplitude: | 1 | | 1/4 | | 1/16 | | 1/64 | | 1/256 | | 1/1024 | | result | | | Persistence = 1/2 | | + | | + | | + | | + | | + | | = | | | Amplitude: | 1 | | 1/2 | | 1/4 | | 1/8 | | 1/16 | | 1/32 | | result | | | Persistence = 1 / root2 | | + | | + | | + | | + | | + | | = | | | Amplitude: | 1 | | 1/1.414 | | 1/2 | | 1/2.828 | | 1/4 | | 1/5.656 | | result | | | Persistence = 1 | | + | | + | | + | | + | | + | | = | | | Amplitude: | 1 | | 1 | | 1 | | 1 | | 1 | | 1 | | result | |
Octaves
Each successive noise function you add is known as an
octave. The reason for this is that each noise function is twice the frequency of the previous one. In music, octaves also have this property.
Exactly how many octaves you add together is entirely up to you. You may add as many or as few as you want. However, let me give you some suggestions. If you are using the perlin noise function to render an image to the screen, there will come a point when an octave has too high a frequency to be displayable. There simply may not be enough pixels on the screen to reproduce all the little details of a very high frequency noise function. Some implementations of Perlin Noise automatically add up as many noise functions they can until the limits of the screen (or other medium) are reached.
It is also wise to stop adding noise functions when their amplitude becomes too small to reproduce. Exactly when that happens depends on the level of persistence, the overall amplitude of the Perlin function and the bit resolution of your screen (or whatever).
Making your noise functions
What do we look for in a noise function? Well, it's essentially a random number generator. However, unlike other random number generators you may have come across in your programs which give you a different random number every time you call them, these noise functions supply a random number calculated from one or more parameters. I.e. every time you pass the same number to the noise function, it will respond with the same number. But pass it a different number, and it will return a different number.
Well, I don't know a lot about random number generators, so I went looking for some, and here's one I found. It seems to be pretty good. It returns floating point numbers between -1.0 and 1.0.
function IntNoise(32-bit integer: x)
x = (x<<13) ^ x;
return ( 1.0 - ( (x * (x * x * 15731 + 789221) + 1376312589) & 7fffffff) / 1073741824.0);
end IntNoise function
|
Now, you'll want several different random number generators, so I suggest making several copies of the above code, but use slightly different numbers. Those big scarey looking numbers are all prime numbers, so you could just use some other prime numbers of a similar size. So, to make it easy for you to find random numbers, I have written a little program to list prime numbers for you. You can give it a start number and an end number, and it will find all the primes between the two. Source code is also included, so you can easily include it into your own programs to produce a random prime number.
Primes.zip
Interpolation
Having created your noise function, you will need to smooth out the values it returns. Again, you can choose any method you like, but some look better than others. A standard interpolation function takes three inputs,
a and
b, the values to be interpolated between, and
x which takes a value between 0 and 1. The Interpolation function returns a value between
a and
b based on the value
x. When
x equals 0, it returns
a, and when
x is 1, it returns
b. When
x is between 0 and 1, it returns some value between
a and
b.
Looks awful, like those cheap 'plasmas' that everyone uses to generate landscapes. It's a simple algorithm though, and I suppose would be excusable if you were trying to do perlin noise in realtime.
function Linear_Interpolate(a, b, x)
return a*(1-x) + b*x
end of function
|
| |