Solarian Programmer

My programming ramblings

Perlin noise in C++11

Posted on July 18, 2012 by Paul

The code for this post is on GitHub:

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

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 #include "PerlinNoise.h"
3 ...
5 	PerlinNoise pn;
6 	double noise = pn.noise(0.45, 0.8, 0.55);
8 ...

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 // Generate a new permutation vector based on the value of seed
 2 PerlinNoise::PerlinNoise(unsigned int seed) {
 3 	p.resize(256);
 5 	// Fill p with values from 0 to 255
 6 	std::iota(p.begin(), p.end(), 0);
 8 	// Initialize a random engine with seed
 9 	std::default_random_engine engine(seed);
11 	// Suffle  using the above random engine
12 	std::shuffle(p.begin(), p.end(), engine);
14 	// Duplicate the permutation vector
15 	p.insert(p.end(), p.begin(), p.end());
16 }

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:

 2 PerlinNoise::PerlinNoise(unsigned int seed) {
 3 	int indx = 0;
 4 	p.resize(256);
 6 	// Fill p with values from 0 to 255
 7 	std::generate(p.begin(), p.end(), [&indx] {return indx++;});
 9 	...
10 }

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 class ppm {
 2 	...
 4 public:
 5     //arrays for storing the R,G,B values
 6     std::vector<unsigned char> r;
 7     std::vector<unsigned char> g;
 8     std::vector<unsigned char> b;
10     ...
12     ppm();
13     //create a PPM object and fill it with data stored in fname
14     ppm(const std::string &fname);
15     //create an "epmty" PPM image with a given width and height;the R,G,B arrays are filled with zeros
16     ppm(const unsigned int _width, const unsigned int _height);
17     //read the PPM image from fname
18     void read(const std::string &fname);
19     //write the PPM image in fname
20     void write(const std::string &fname);
21 };

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 #include <cmath>
 2 #include "ppm.h"
 3 #include "PerlinNoise.h"
 5 int main() {
 6 	// Define the size of the image
 7 	unsigned int width = 600, height = 450;
 9 	// Create an empty PPM image
10 	ppm image(width, height);
12 	// Create a PerlinNoise object with a random permutation vector generated with seed
13 	unsigned int seed = 237;
14 	PerlinNoise pn(seed);
16 	unsigned int kk = 0;
17 	// Visit every pixel of the image and assign a color generated with Perlin noise
18 	for(unsigned int i = 0; i < height; ++i) {     // y
19 		for(unsigned int j = 0; j < width; ++j) {  // x
20 			double x = (double)j/((double)width);
21 			double y = (double)i/((double)height);
23 			// Wood like structure
24 			n = 20 * pn.noise(x, y, 0.8);
25 			n = n - floor(n);
27 			// Map the values to the [0, 255] interval, for simplicity we use
28 			// tones of grey
29 			image.r[kk] = floor(255 * n);
30 			image.g[kk] = floor(255 * n);
31 			image.b[kk] = floor(255 * n);
32 			kk++;
33 		}
34 	}
36 	// Save the image in a binary PPM file
37 	image.write("result.ppm");
39 	return 0;
40 }

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:

Perlin noise

A typical Perlin noise obtained with my permutation vector:

Perlin noise with modified permutation vector

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

Wood like texture 1

A wood like Perlin noise obtained with my permutation vector:

Wood like Perlin noise with modified permutation vector

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:



Show Comments