How to Use Perlin Noise in Your Games
Page 1 of 4
<1 | 2 | 3 | 4>
Single-page view
How to Use Perlin Noise in Your Games

This article originally appeared in Dev.Mag Issue 20, released in February 2008

Perlin noise is the foundation of many procedural texture and modelling algorithms. It can be used to create marble, wood, clouds, fire, and height maps for terrain. It is also very useful for tiling grids to simulate organic regions, and blending textures for interesting transitions. In this article I will explain how to implement Perlin noise, and how you can use it in your games.

Implementation

Written in its concise mathematical form, the Perlin noise generation seems daunting, but it is actually easy to implement. There are two steps:

  1. Generate a number of arrays containing "smooth" noise. Each array is called an octave, and the smoothness is different for each octave. (See the first 7 images in Figure 1).
  2. Blend these together. The result is the last image in Figure 1.

That's it! Let's look at each of these two steps.

Figure 1
Figure 1

Generating Smooth Noise

First, you need to create an array with random values between 0 and 1. This array must be the same size as the array of Perlin noise you need.

generateUniformNoise()
{
	baseNoise[][]; //an array for our uniform noise
	for(i = 0; i < width; i++)
		for(j = 0; j < height; j++)
			//random float between 0 and 1
			baseNoise[i][j] = random();
	return baseNoise;
}

For creating the kth octave, sample the noise array at every point (i*2k, j*2k) , for all i, j, and interpolate the other points linearly. The value 2k is called the wave length of that octave, and the value 1/2k is called the frequency.

The following pseudo C snippet shows how the kth octave is generated:

generateSmoothNoise(baseNoise, k)
{
	samplePeriod = 1 << k; // calculates 2 ^ k
	sampleFrequency = 1.0f / samplePeriod;
	for(i = 0; i < width; i++)
	{
		//calculate the horizontal sampling indices
		sample_i0 = (i / samplePeriod) * samplePeriod;
		sample_i1 = sample_i0 % width; //wrap around		
		horizontal_blend = (i – sample_i0) * sampleFrequency;
		for(j = 0; j < height; j++)
		{
			//calculate the vertical sampling indices
			sample_j0 = (j / samplePeriod) * samplePeriod;
			sample_j1 = (sample_j0 + 1) % height; //wrap around
			vertical_blend = (j – sample_j0) * sampleFrequency;
			//blend the top two corners			
			top = interpolate(baseNoise[sample_i0][sample_j0], 
				baseNoise[sample_i1][sample_j0], horizontal_blend);
			//blend the bottom two corners
			bottom = interpolate(baseNoise[sample_i0][sample_j1],
				baseNoise[sample_i1][sample_j1], horizontal_blend);
			//final blend
			smooth[i][j] = 
				interpolate(top, bottom, vertical_blend);
		}
	}
	return smooth;
}

The following function returns a linear interpolation between two values. Essentially, the closer alpha is to 0, the closer the resulting value will be to x0; the closer alpha is to 1, the closer the resulting value will be to x1.

interpolate(x0, x1, alpha) //alpha lies between 0 and 1
{
	return (1 – alpha) * x0 + alpha * x1;
}

There are a variety of interpolation schemes; the best one to use depends on your application.

See here for some common interpolation schemes.

Blending the Arrays

To make the final array, you add weighted values of all the smooth noise arrays together. The weight used for each octave is called the amplitude.

Any values can be used for the amplitudes, with different effects. A good starting point is to use a weight of 0.5 for the first octave, 0.25 for the next octave, and so on, multiplying the amplitude with 0.5 in each step. In this scheme, the value 0.5 is called the persistence of the noise.

After you have added all the noise values, you should normalise it by dividing it by the sum of all the amplitudes, so that all noise values lie between 0 and 1.

generatePerlin(baseNoise, octaveCount)
{
	smooth[]; //an array of 2D arrays containing
	persistance = 0.5f;
	//generate smooth noise
	for(i = 0; i < octaveCount; i++)
		smooth[i] = generateSmoothNoise(baseNoise, i);
	perlinNoise[][]; //an array of floats initialised to 0
	
	amplitude = 1.0f;
	totalAmplitude = 0.0f;
	//blend noise together
	for(k = 0; k < octaveCount; k++)
	{
		amplitude *= persistance;
		totalAmplitude += amplitude;
		
		for(i = 0; i < width; i++)
			for(j = 0; j < height; j++)
				perlinNoise[i][j] += smooth[k][i][j] * weight;
	}
	//normalisation
	for(k = 0; k < octaveCount; k++)
	{
		perlinNoise[i][j] /= totalAmplitude;
	}
	return perlinNoise;
}

In practice smooth noise arrays are not actually created; rather, the noise is calculated and added to the final array on the fly. How this is done is not shown here; check out the link at the end of the article for a link to example code.

Perlin noise can sometimes look diluted. For many applications this is fine; however, sometimes you might want something a bit more dramatic. This can easily be achieved in one of the following ways:


  • Increase the contrast as a post-processing step using image editing software.
  • Use a higher persistence (0.7 is good for 6 octaves), and skip the normalisation step. Just make sure to clamp your final values to 1.

The first method is better when you want tight visual control. The second method is more convenient as it is part of the creation process and can hence be better automated.



Words from the readers
You are quite correct. I've amended the article, thank you for pointing this out.
Posted by Chippit at 12:56:57 on 07 December 2009
top = interpolate(baseNoise[sample_i0][sample_j0],
baseNoise[sample_i1][sample_j1], horizontal_blend);
is wrong. Should be
top = interpolate(baseNoise[sample_i0][sample_j0],
baseNoise[sample_i1][sample_j0], horizontal_blend);
(0,0)->(1,1) is a diagonal.
Posted by david at 18:46:28 on 04 December 2009
As with most of our tutorials, this one can be applied in whichever environment you like, and is less about building 'engines' as it is about making content for whichever engine you happen to be using.

While this particular tutorial is more abstract than most, its implementation is not limited to any particular language, engine or environment, and can be applied wherever it is needed. It's up to you to decide where, in this case, though a later piece on Poisson sampling will give you a few ideas.

As for getting started, there's no concrete answer. The Dev.Mag-endorsed way involves signing up and posting on the Game.Dev forums (http://forums.tidemedia.co.za/nag/forumdisplay.php?f=9). Further than that and you'll have to be more specific. Sign up there and ask around.
Posted by Chippit at 17:26:16 on 20 May 2009
Hi Gaming Fanz

I just want to know, these tutorials are they about developing game engines from scratch and if they are where can a person start (do you need a framework i.e TGE)
Posted by Mozira at 16:55:49 on 20 May 2009
Have your say: