Generic Bootstrap Blog

(Serial No. 02fb0b13175bd913)

Creative Commons License

One dimensional Perlin(-like) noise for the mathematically impaired

 » 2016-12-05 08:07:59 | git log

Over the past week or so I’ve been trying to implement a gradient noise function, a task that has been a particularly frustrating experience. There are many pages that describe Perlin noise and friends, but as someone with minimal formal training in mathematics I found most of them to be scarcely better than gibberish. I’m about to try to give the explanation I wish I had a week ago, but if you still don’t get it there will be some public domain code later on which you’re free to copy as desired.

Initially I was going to attempt an introduction to coherent and gradient noise so this page was as gentle as possible, but there’s plenty already out there on this topic and I’m unlikely to best any of them. Check out any of the following links if you need a refresher:

Please note that my expertise in this field is non-existent. There seems to be a lot of confusion around what does and doesn’t qualify as Perlin noise, so whilst the algorithm I’ll describe borrows heavily from Ken Perlin’s writing I will be referring to it as “gradient noise” for the rest of this post.

Here’s the code, adapted from Ken Perlin’s implementation of Perlin noise in C:

// To the extent possible under law, the person who associated CC0 with this
// work has waived all copyright and related or neighboring rights to this work.
// http://creativecommons.org/publicdomain/zero/1.0/
class GradientNoise {
    const int N_GRADIENTS = 256;
    double[] gradients = new double[N_GRADIENTS];

    public double sample (double point) {
        var left_gradient_index = (int) point % N_GRADIENTS;
        var right_gradient_index = (left_gradient_index + 1) % N_GRADIENTS;

        var left_grad_offset = point - (int) point;
        var right_grad_offset = left_grad_offset - 1;

        var prod_left = left_grad_offset * gradients[left_gradient_index],
            prod_right = right_grad_offset * gradients[right_gradient_index];

        // S-curve weighting from revised Perlin noise
        var sx = 6 * Math.pow (left_grad_offset, 5)
            - 15 * Math.pow (left_grad_offset, 4)
            + 10 * Math.pow (left_grad_offset, 3);

        //      linear interpolation                       scale to range 0-1
        return (prod_left + sx * (prod_right - prod_left)) / 2 + 0.5;
    }

    public GradientNoise () {
        for (var i = 0; i < gradients.length; i++)
            gradients[i] = Random.double_range (-1, 1);
    }
}

In our GradientNoise class, we create an array of unit-length gradients. Each index in the array represents an integer point on our number line. The value of N_GRADIENTS was selected arbitrarily.

The sample() function is where the magic happens. Here’s the breakdown:

$$6t^5 - 15t^4 + 10t^3$$

And that’s it! I’m a long way from able to give any guarantees with respect to desirable properties, so be warned that this variant may well be both slower and poorer in its output. All I can say is that it looks like continuous noise, and that’ll do for me.

Please feel free to leave a comment noting corrections, suggestions, thoughts. Thanks for reading!