Perlin noise in C++11
Posted on July 18, 2012 by Sol

The code for this post is on GitHub: https://github.com/sol-prog/Perlin_Noise.

Ken Perlin’s noise function is the building block of many texture generation algorithms, you can use it to create realistically looking materials, clouds, mountains etc … The first version of this function was developed in 1988 and it is still used in various graphical libraries. In 2002 the author has published an improved version of his noise function.

I searched the Internet for a C++ implementation of the improved Perlin noise function, while obviously available in various libraries I didn’t found this implemented as a ready to use class. Also there seems to be a general confusion between what is a Perlin noise function, some websites confuse the Perlin noise function with FBM (Fractal Brownian Motion).

In the end I’ve found a Java reference implementationn of the improved Perlin function written by Ken Perlin himself. Converting this to C++11 was pretty straightforward.

Here is the class definition of my Perlin noise implementation:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class PerlinNoise {
	// The permutation vector
	std::vector<int> p;
public:
	// Initialize with the reference values for the permutation vector
	PerlinNoise();
	// Generate a new permutation vector based on the value of seed
	PerlinNoise(unsigned int seed);
	// Get a noise value, for 2D images z can have any value
	double noise(double x, double y, double z);
private:
	double fade(double t);
	double lerp(double t, double a, double b);
	double grad(int hash, double x, double y, double z);
};

The highlighted method from the above code allows the user to generate his own Perlin like function by creating a new permutation vector.

If you want to use the reference Perlin noise all you have to do is to create a PerlinNoise object in your code and call the noise member function:

1
2
3
4
5
6
7
8
#include "PerlinNoise.h"

...
	
	PerlinNoise pn;
	double noise = pn.noise(0.45, 0.8, 0.55);

...

The reference implementation uses a 3D form of the Perlin function, if you want to use this on a 2D domain you can simply ignore the third argument to the noise function. Geometrically, using a constant value for z can be seen as making a section trough the unit cube, so it make sense to keep this fixed for 2D images. You can also use the z channel for nice animation effects if you consider z as being the time of the animation.

If you want to create your own Perlin like function you could use a different version of the permutation array, which is basically a shuffled vector of integers from 0 to 255. I couldn’t resist the temptation of adding this capability to the PerlinNoise class:

  • Start by generating an ordered sequence of integers from 0 to 255, we’ll store this in a C++ vector.
  • Initialize a random number generator with a particular seed (you will want to save this number if you want to be able to repeat the obtained effect).
  • Shuffle the ordered vector from the first step using the random engine initialized in the second step.

Here is the C++11 code that implements the above algorithm:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// Generate a new permutation vector based on the value of seed
PerlinNoise::PerlinNoise(unsigned int seed) {
	p.resize(256);

	// Fill p with values from 0 to 255
	std::iota(p.begin(), p.end(), 0);

	// Initialize a random engine with seed
	std::default_random_engine engine(seed);

	// Suffle  using the above random engine
	std::shuffle(p.begin(), p.end(), engine);

	// Duplicate the permutation vector
	p.insert(p.end(), p.begin(), p.end());
}

Thanks to mttd (see Comments) I’ve simplified a bit the above code using std::iota instead of std::generate and a lambda. This is the old version of the above member function:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// Generate a new permutation vector based on the value of seed
PerlinNoise::PerlinNoise(unsigned int seed) {
	int indx = 0;
	p.resize(256);

	// Fill p with values from 0 to 255
	std::generate(p.begin(), p.end(), [&indx] {return indx++;});

	...
}

In order to test this implementation of Perlin noise we’ll need an image I/O library. A few months ago I wrote a small PPM class that let’s you load, modify and save images in the PPM format. I’ll include here, for completeness, a part of the class definition, the complete code is on the Github repository:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
class ppm {
	...

public:
    //arrays for storing the R,G,B values
    std::vector<unsigned char> r;
    std::vector<unsigned char> g;
    std::vector<unsigned char> b;

    ...

    ppm();
    //create a PPM object and fill it with data stored in fname
    ppm(const std::string &fname);
    //create an "epmty" PPM image with a given width and height;the R,G,B arrays are filled with zeros
    ppm(const unsigned int _width, const unsigned int _height);
    //read the PPM image from fname
    void read(const std::string &fname);
    //write the PPM image in fname
    void write(const std::string &fname);
};

Let’s write a small test program that will fill an image with Perlin noise and will save this as a PPM file on the disk:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <cmath>
#include "ppm.h"
#include "PerlinNoise.h"

int main() {
	// Define the size of the image
	unsigned int width = 600, height = 450;

	// Create an empty PPM image
	ppm image(width, height);

	// Create a PerlinNoise object with a random permutation vector generated with seed
	unsigned int seed = 237;
	PerlinNoise pn(seed);

	unsigned int kk = 0;
	// Visit every pixel of the image and assign a color generated with Perlin noise
	for(unsigned int i = 0; i < height; ++i) {     // y
		for(unsigned int j = 0; j < width; ++j) {  // x
			double x = (double)j/((double)width);
			double y = (double)i/((double)height);

			// Wood like structure
			n = 20 * pn.noise(x, y, 0.8);
			n = n - floor(n);

			// Map the values to the [0, 255] interval, for simplicity we use 
			// tones of grey
			image.r[kk] = floor(255 * n);
			image.g[kk] = floor(255 * n);
			image.b[kk] = floor(255 * n);
			kk++;
		}
	}

	// Save the image in a binary PPM file
	image.write("result.ppm");

	return 0;
}

For illustration purposes I’ve created a few images with the above code using the reference Perlin noise function and the permutation vector obtained with a seed = 237 (I chose 237 for no particular reason, you can use any positive integer number here, just record it in case you obtain some nicely looking textures and you want to be able to regenerate them at a later time).

A typical Perlin noise obtained with the reference permutation vector:

Figure_7_R

A typical Perlin noise obtained with my permutation vector:

Figure_7_P

A wood like Perlin noise obtained with the reference permutation vector:

Figure_8_R

A wood like Perlin noise obtained with my permutation vector:

Figure_8_P

The effect of using a different permutation vector is more pronounced in the last set of images.

If you are interested in reading more about procedural texture generations and various noise functions, you could read Texturing and Modeling: A Procedural Approach by D. S. Ebert, F. K. Musgrave, D. Peachey, K. Perlin, S. Worley:

If you are interested in learning more about the new C++11 syntax I would recommend reading The C++ Programming Language by Bjarne Stroustrup.

or, Professional C++ by M. Gregoire, N. A. Solter, S. J. Kleper 2nd edition:

blog comments powered by Disqus