It is not uncommon in computer graphics and modelling to want to use a random function to make imagery or geometry appear more natural looking. The real world is not perfectly smooth nor does it move or change in regular ways. The random function found in the maths libraries of most programming languages aren't always suitable, the main reason is because they result in a discontinuous function. The problem then is to dream up a random/noisy function that changes "smoothly". It turns out that there are other desirable characteristics such as it being defined everywhere (both at large scales and at very small scales) and for it to be band limited, at least in a controllable way.
The most famous practical solution to this problem came from Ken Perlin back in the 1980's. His techniques have found their way in one form or another into many rendering packages both free and commercial, it has also found its way into hardware such as the MMX chip set. At the bottom of this document I've included the original (almost) version of the C code as released by Ken Perlin and on which most of the examples in the document are based.
The basic idea is to create a seeded random number series and smoothly interpolate between the terms in the series, filling-in the gaps if you like. There are a number of ways of doing this and the details of the particular method used by Perlin need not be discussed here. Perlin noise can be defined in any dimension, most common dimensions are 1 to 4. The first 3 of these will be illustrated and discussed below.1 Dimensional
A common technique is to
create 1/fn noise which is known to occur often in natural
processes. An approximation to this is to add suitably scaled harmonics
of this basic noise function.
For the rest of this discussion the Perlin noise functions will be
referred to as Noise(x) of a variable x which may
a vector in
1, 2, 3 or higher dimension. This function will return a real (scalar) value.
A harmonic will be Noise(b x) where "b" is some positive number
greater than 1, most commonly it will be powers of 2.
While the Noise() functions can be used by themselves, a more common
approach is to create a weighted sum of a number of harmonics of
these functions. These will be refered to as NOISE(x)
and can be defined as
The following shows increasing harmonics of 1 dimensional Perlin noise along with the sum of the first 8 harmonics at the bottom. In this case a and b are both equal to 2. Note that since in practice we only ever add a limited number of harmonics, if we zoom into this function sufficiently it will become smooth.
The following show the same progression but in two dimensions. This is also a good example of why one doesn't have to sum to large values of N, after the 4th harmonic the values are less than the resolution of a grey scale image both in terms of spatial resolution and the resolution of 8 bit grey scale.
As earlier, a and b are both set to 2 but note that there are an infinite number of ways these harmonics could be added together to create different effects. For example, if in the above case one wanted more of the second harmonic then the scaling of that can be increased. While the design of a particular image/texture isn't difficult it does take some practice to become proficient.3 Dimensional
Perlin noise can be created in 3D and higher dimensions, unfortunately it is harder to visualise the result in the same way as the earlier dimensions. One isosurface of the first two harmonics are shown below but it hardly tells the whole story since each point in space has a value assigned to it.
Perhaps the most common use of 3D Perlin noise is generating volumetric textures, that is, textures that can be evaluated at any point in space instead of just on the surface. There are a number of reasons why this is desirable.
It means that the texture need not be created beforehand but can be computed on the fly.
There are a number of ways the texture can be animated. One way to to translate the 3 dimensional point passed to the Noise() function, alternatively one can rotate the points. Since the 3D texture is defined everywhere in 3D space, this is equivalent to translating or rotating the texture volume.
The exact appearance of the texture can be controlled by either varying the relative scaling of the harmonics or by adjusting how the scalar from the Perlin functions is mapped to colour and/or transparency.
It gets around the problem of mapping rectangular texture images onto topologically different surfaces. For example, the following texture for a sun was created using 3D noise and evaluating the points using the same mapping as will be used when the texture is mapped onto a sphere. The result is that the texture will map without pinching at the poles and there will not be any seams on the left and right.
The above describes a way of creating a noisy but continuous function. In normal operation one passes a vector in some dimension and the function returns a scalar. How this scalar is used is the creative part of the process. Often it is can be used directly, for example, to move the limbs of virtual character so they aren't rigid looking. Or it might be used directly as the transparency function for clouds. Another fairly common application is to use the 1D noise to perturb lines so they look more natural, or to use the 2D noise as the height for terrain models. 2D and 3D perlin noise are often used to create clouds, a hint of this can be seen in the sum of the 2D Noise() functions above.
When the aim is to create a texture the scalar is used as an index into
a colour map, this may either be a continuous function or a lookup table.
Creating the colour map to achieve the result being sought is a matter
of skill and experience. Another approach is to use NOISE() functions
as arguments to other mathematical functions, for example, marble effects
are often made using cos(x + NOISE(x,y,z)) and mapping that to the desired
In order to effectively map the values returned from the noise functions one needs to know the range of values and the distribution of values returned. The original functions and therefore the ones presented here both have Gaussian like distributions centered on the origin. Noise() returns values between about -0.7 and 0.7 while NOISE() returns values potentially between -1 and 1. The two distributions are shown below.
The possibilities are endless, enjoy experimenting.
An Image Synthesizer
Computer Graphics, 1985, 19 (3), pp 287-296.
Donald Hearn and M. Pauline Baker
Computer Graphics, C-Version, 1997, pp 362-378.
Live Paint: Painting with Procedural Multiscale Textures
Computer Graphics, Volume 28, Number 3.
David Ebert, et al (Chapter by Ken Perlin)
Texturing and Modeling, A Procedural Approach
AP Professional, Cambridge, 1994.
Perlin, K., Hoffert, E.
Computer Graphics (proceedings of ACM SIGGRAPH Conference), 1989, Vol. 22, No. 3.