## Heightmap Generation

### Noise Generation

**Language**: C++

This code sample demonstrate perlin noise generation. The final result is the sum of several coherent noises of varying frequencies and scale.

## Code sample

### Header

namespace noiselib{ /** * Return a value in a discrete 2D white noise given by seed at a particular coordinate. * Consequently, the value is fully determined by x,y and seed. */ double randNoiseDouble(int x, int y, int seed); /** * Return a value in a continuous 2D noise given by seed at a particular coordinate. * Consequently, the value is fully determined by x,y and seed. * The function use a gradient method to generate noise which is spatially * pseudo-uniform and coherent. */ double randGradientNoiseDouble(double x, double y, int seed); /** * Return a value in a 2D Perlin noise given by seed at a particular coordinate. * Consequently, the value is fully determined by x,y and seed. * The function basically sum several gradient noise at different frequencies. */ double randPerlinNoise(double x, double y, int seed, int nbrOctave, double persistence); }

### Implementation

/** * These constants are used by the randNoiseDouble function */ const int NOISE_P_X = 1619; const int NOISE_P_Y = 31337; const int NOISE_P_SEED = 1013; /** * A simple cos lookup table */ double cosValue[16] = {1.0,0.9238,0.7071,0.3826,0,-0.3826,-0.7071,-0.9238, -1.0,-0.9238,-0.7071,-0.3826,0,0.3826,0.7071,0.9238}; /* * The dot product of two vector */ double dotProduct(double vx, double vy, double wx, double wy){ return vx*wx+vy*wy; } /** * A weigth function for polynomial interpolation */ double easeCurve(double t){ return 6*pow(t,5)-15*pow(t,4)+10*pow(t,3); } /** * Linear interpolation between two value */ double linearInterpolation(double x0, double x1, double t){ return x0+(x1-x0)*t; } /** * Interpolate between four values, using ease curves. */ double biLinearInterpolation(double x0y0, double x1y0, double x0y1, double x1y1, double x, double y){ double tx = easeCurve(x); double ty = easeCurve(y); double u = linearInterpolation(x0y0,x1y0,tx); double v = linearInterpolation(x0y1,x1y1,tx); return linearInterpolation(u,v,ty); } /** * Return a value in a discrete 2D white noise given by seed at a particular coordinate. * Consequently, the value is fully determined by x,y and seed. */ double noiselib::randNoiseDouble(int x, int y, int seed){ int n = ( NOISE_P_X * x + NOISE_P_Y * y + NOISE_P_SEED * seed) & 0x7fffffff; n = (n >> 13) ^ n; n = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff; return 1.0 - (double)n/1073741824; } /** * Return a value in a continuous 2D noise given by seed at a particular coordinate. * Consequently, the value is fully determined by x,y and seed. * The function use a gradient method to generate noise which is spatially * pseudo-uniform and coherent. */ double noiselib::randGradientNoiseDouble(double x, double y, int seed){ //Get the top left border coordinate int x0 = (x > 0.0? (int)x: (int)x - 1); int y0 = (y > 0.0? (int)y: (int)y - 1); //Local coordinate double xl = x-x0; double yl = y-y0; //We associate a vector with each corner, by computing a random angle. //We use an integer value in order to use the cos lookup table, cosValue. //The vector are dependant of x and y. This is essential in order to obtain a coherent noise. int n00 = (int)((randNoiseDouble(x0, y0, seed)+1)*8); int n10 = (int)((randNoiseDouble(x0+1, y0, seed)+1)*8); int n01 = (int)((randNoiseDouble(x0, y0+1, seed)+1)*8); int n11 = (int)((randNoiseDouble(x0+1, y0+1, seed)+1)*8); //Compute a value for each corner using dot product between the corner vectors and the local coordinates double s = dotProduct(cosValue[n00], cosValue[(n00-4)%16], xl, yl); double u = dotProduct(-cosValue[n10], cosValue[(n10-4)%16], 1.0-xl, yl); double v = dotProduct(cosValue[n01], -cosValue[(n01-4)%16], xl, 1.0-yl); double w = dotProduct(-cosValue[n11], -cosValue[(n11-4)%16], 1.0-xl, 1.0-yl); //Interpolate the value return biLinearInterpolation(s,u,v,w,xl,yl); } /** * Return a value in a 2D Perlin noise given by seed at a particular coordinate. * Consequently, the value is fully determined by x,y and seed. * The function sum several gradient noise at different frequencies. */ double noiselib::randPerlinNoise(double x, double y, int seed, int nbrOctave, double persistence){ //We start from a 0 value. double px = 0.0; //Then add the noises for(int oct = 0; oct<nbrOctave; oct++){ double xr = x * pow(2.0,oct); double yr = y * pow(2.0,oct); px = px + pow(persistence,oct) * randGradientNoiseDouble(xr,yr,seed+oct); } return px; }