Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - Wes

Pages: [1]
1
Programming / Open-Source Perlin Noise C++ Library
« on: June 24, 2016, 07:03:35 PM »
Here is a C++ class for generating Perlin Noise. It is strongly based on Ken Perlin's java reference (found here http://mrl.nyu.edu/~perlin/noise/)
The source code can be downloaded from github at https://github.com/WesOfX/perlin-noise.
Before I go into detail, here are some demos:

1 Octave, 8 Frequency


7 Octaves, 3 Frequency, 0.5 Peristence


3 Octaves. 32 Frequency, 0.5 Persistence (Thresholded to look like caves)


The API centers around a class named Generator. The declaration is as follows:

Code: [Select]
// A reference Perlin noise generator
class Generator{
// Permutation vector for pseudo-random numbers
std::vector<unsigned char> permutation;

public:
// Creates Perlin noise generator with reference permutation vector
Generator();

// Creates Perlin noise generator with a custom seed
Generator(unsigned int seed);

// Returns noise value between -1.0 and 1.0
double get(double x, double y, double z) const;

private:
// Functions for interpolating noise
static double lerp(double t, double a, double b);
static double fade(double t);
static double grad(int hash, double x, double y, double z);
};

To use this class, you simply construct an object and use the "get" function to generate noise. Here is an example:

Code: [Select]
// Create reference Perlin generator
Generator generator();
 
// Print noise at 55, 99, 0
std::cout << generator.get(55, 99, 0) << std::endl;
 
// Create new noise with new seed
generator = Generator(42);
 
// Print new noise at 55, 99, 0
std::cout << generator.get(55, 99, 0) << std::endl;

For convenience, I have created an additional class for generating fractal Perlin Noise in bulk. (Especially useful for procedural map generation in roguelikes) It has a constructor which accepts parameters for noise frequency, number of octaves, and persistence. The declaration is as follows:

Code: [Select]
// A 2D array of doubles containing noise with easy access methods
class Noise{
// 2D Array of doubles containing noise
std::vector<double> map;

// Dimensions of array
unsigned short width, height;

public:
// Creates empty noise map
Noise();

// Constructor that resizes map and populates it with noise
Noise(
unsigned short width,  // Number of columns
unsigned short height, // Number of rows
double frequency,      // Frequency of noise features
unsigned int octaves,  // Number of octaves (halving frequency)
double persistence,    // Compounding weight of octaves
unsigned int seed      // Seed for Perlin noise engine
);

// Returns a double from the map at the desired location
// Values returned are between -1.0 and 1.0
// If the location does not exist, 0.0 is returned
double get(unsigned short x, unsigned short y) const;

// Resizes the noise map and populates it with noise
void generate(
unsigned short width,  // Number of columns
unsigned short height, // Number of rows
double frequency,      // Frequency of noise features
unsigned int octaves,  // Number of octaves (halving frequency)
double persistence,    // Compounding weight of octaves
unsigned int seed      // Seed for Perlin noise
);

private:
// Sets the double at the provided location to the value provided
void set(unsigned short x, unsigned short y,  double value);

// Resized the double array (Invalidates current data)
void resize(unsigned short width, unsigned short height);
};


To use this class, use the constructor to generate the noise and the "get" function to access the noise. Here is an example:

Code: [Select]
// Generate noise with generation constructor
Noise noise(
800,  // width
600,  // height
6.5,  // frequency
3,    // octaves
0.75, // persistence
42    // seed
);

// Print noise at 55, 99 using get function
std::cout << noise.get(55, 99) << std::endl;

// Generate new noise with generate function
noise.generate(
800,  // width
600,  // height
6.5,  // frequency
3,    // octaves
0.75, // persistence
9001  // new seed!
);

// Print new noise at 55, 99 using get function again
std::cout << noise.get(55, 99) << std::endl;

The demo images were generated with the following code using a ppm image library (https://github.com/WesOfX/ppm-image):
Code: [Select]
int main(){
// Image size
static constexpr unsigned short width = 512, height = 512;

// Final image that will be saved
PPM::Image image(width, height);

// Noise that will be applied to image
Perlin::Noise noise(
width,
height,
4.0, // Frequency
6,   // Octaves
0.5, // Persistence
0    // Seed
);

// Apply noise to image
for(unsigned short y = 0; y < height; y++){
for(unsigned short x = 0; x < width; x++){
// Convert noise value to 24 bit color value
auto value = (unsigned char)(((noise.get(x, y) + 1) / 2) * 255);

// Set pixel color to value
image.set(x, y, PPM::Color(value, value, value));
}
}

// Save noise image
image.write("Noise.ppm");
}

If you have any questions, feel free to post.
I you wish to read Ken Perlin's reference, it is located at http://mrl.nyu.edu/~perlin/noise/
The source is available on github at https://github.com/WesOfX/perlin-noise
Demo images created with https://github.com/WesOfX/ppm-image
Thank you :)

Pages: [1]