In this post, I will show how the reference implementation of Improved Perlin Noise can be rewritten to yield an aperiodic noise function.
The reference implementation for Improved Perlin Noise (which can be found on Ken Perlin’s website here), is given (in Java) as:
The reference implementation makes use of a permutation table (omitted for brevity)
to build an 8-bit hash for eight corners of the unit cube surrounding the given input
coordinate. The permutation table is a fixed size of 256 but actually repeated to
conveniently avoid buffer overflow errors.
To ensure that we don’t overflow this table, the modulus operator is first applied
to the input coordinates. We can think of this as an initial hashing function:
A consequence of this is that the reference implementation repeats for every
256 units.
The first step in removing this repetition is to apply a better initial hashing
function, that makes use of the full precision range of the input value. For
example, we could choose to reuse the permutation table to perform a Pearson Hash
of the input value:
We could then change the first three lines of the noise function to apply this
better hashing scheme instead:
However, this isn’t enough. The following lines that make use of the X,Y and Z
values make a very important assumption on the initial hashing function used to
generate them:
Whilst the modulus operator has this property, our new hashing function doesn’t.
We can see how this affects the computation of the gradient hashes by expanding
one of them out:
For the positive corners of the unit grid we are adding 1 to the X, Y, and Z
terms but these terms are the results of the initial hashing function, and will
therefore only work if our initial hashing function maintains the assumption
stated above.
In breaking this assumption, we must rewrite these terms as well. We’ll start
by computing the hash of the positive corners too:
Then we can rewrite these these terms such that, for example, the expression:
p[ p[ p[ X + 1 ] + Y + 1 ] + Z + 1 ]
becomes:
p[ p[ p[ XX ] + YY ] + ZZ ]
After some factorisation, here is the resultant function (in C++):
Whilst this is more expensive than the original implementation, this should go to
demonstrate a technique that can be used to remove the 256 unit repetition in the
reference implementation.