2020-05-05

Perlin Noise

Overview

Perlin Noise, created by Ken Perlin, is a type of randomness used in computer graphics.
It’s used everywhere, from creating textures, or building landscapes.
Its algorithm is pretty simple to implement and it gives great results.

Algorithm

  1. Input coordinates in the form of (x, y).
  2. Find the (4) nearest integer points that surround the coordinates.
  3. Get random values seeded by the points.
  4. Interpolate between each of these values.
  5. Loop through the noise function several times with differing frequencies and amplitudes.
  6. Average noise by total possible sum of amplitudes.

Code

// Pseudo-random number generator
function rand_2d(_x, _y) {
    random_set_seed(_x * 123.456 + _y * 456.789)
	return random(1)
}

// Noise function
function noise_2d(_x, _y) {
    // Getting integer points that contain the coordinate
    var _x1 = floor(_x), _x2 = _x1 + 1;
    var _y1 = floor(_y), _y2 = _y1 + 1;

    // Determining interpolation by getting smooth-stepped distance from points
    var _xFrac = _x - _x1, _yFrac = _y - _y1;

    // Get random values and interpolate
    var _value1 = lerp(rand_2d(_x1, _y1), 
                       rand_2d(_x2, _y1), 
                       _xFrac);
    var _value2 = lerp(rand_2d(_x1, _y2), 
                       rand_2d(_x2, _y2), 
                       _xFrac);
    return lerp(_value1, _value2, _yFrac);
}

// Perlin Noise function 
// Detail - How many iterations (keep this a low-ish number for performance)
// Roughness - Noise strength scaling each iteration
function perlin_2d(_x, _y, _detail=4, _roughness=0.5) {
    var _value = 0;
    var _sum = 0;
    var _strength = 1;
    for (var _i = 0; _i < _detail; _i++) {
        _value += (noise_2d(_x, _y) * 2 - 1) * _strength; // Remapped from -1 to 1 for easier calculations
        _sum += _roughness;
        _strength *= _roughness;
        _x *= 2; _y *= 2; // Shift coordinates after each iteration
    }
    _value /= _sum;
    return (_value * 0.5 + 0.5); // Return remapped back from 0 to 1
}

Example

Example Image Here, I rendered a image of generated Perlin noise values with default arguments, with pure black being 0, and pure white being 1.
Note, generating this image as a example is really inefficient, calling the function 262144 times all at once. Use this function sparingly.

Final Thoughts

There’s tons to be improved and played with when you go back to refactor this code. Try using a smoothstep function for distances. After that, you can use this however you want, whether it’s generating terrain, or making interesting textures.

Thanks for reading! -AH