Procedural noise functions return smoothly varying results as calculated from spatial coordinates (as the spatial coordinate changes so does the value). The derivatives of procedural noise functions can be useful in many different ways.
– analytical bump/normal mapping
– interesting fractal effects
– calculating entirely new noise types
Noise derivatives can be calculated in a number of ways. Ken Perlin gives an example where derivatives are calculated numerically using finite differencing (5.6). An advantage to this is the noise function can be any arbitrarily complex function. Disadvantages are that the noise function needs sampling 3 times and some fixed epsilon value needs to be chosen (eg 0.0001). Hugh Malan shows that for realtime use derivatives can be baked into a texture along with the original value (20.3.1). Although very efficient the disadvantage with this is we’re now locked into a fixed resolution which makes general use problematic. Morten Mikkelsen shows that GPU hardware derivative units can be used, which is a very nice and efficient solution, but the result suffers from grainy artifacts due to the 2×2 sampling strategy used by derivative hardware.
Another approach is to calculate the derivatives analytically. That is, the procedural noise function calculates both the result and the derivative mathematically in a single call. This has the advantage of only needing to be called once and also being robust when sampled at any scale.
Given the advantages/uses of procedural noise derivatives I’m surprised analytical derivatives have not received much attention at all. I went hunting and found Stefan Gustavson’s work on simplex noise derivatives in C++, Giliam de Carpentier’s work on 2D Perlin noise derivatives and Milo Yip’s post regarding 3D perlin noise derivatives. With that I went about implementing them myself. As a result the noise library now contains common noise functions (value, perlin, cellular, hermite and simplex) which also return analytical derivatives.
Here are some screenshots showing some common procedural noise functions with their corresponding derivatives. Please note that all images have been normalized to a 0.0->1.0 range for ease of viewing. In reality the noise values range from -1.0->1.0 and noise derivatives can have any range but generally somewhere around -3.0->3.0
Classic Perlin Noise “Value”, “DerivX” and “DerivY” (notice grid line artifacts)
Hermite Noise “Value”, “DerivX” and “DerivY” (notice grid line artifacts greatly reduced)
Simplex Perlin Noise “Value”, “DerivX” and “DerivY” (notice absence of any grid-aligned artifacts)
In a previous post I describe a fast 32-bit hash function which I’ve been using as the basis for all noises documented on this site. Recently I have made some changes to it resulting in…
- Improved flexibility
- A slight improvement in randomness
- A larger possible domain
- The possibility of a 4D hash function
For anyone interested in the inner workings, the change is that the input coordinate is first scaled before offsetting the domain. This has allowed for a larger range of precision for the hashing process. As with the previous hash function, here is some GLSL code which implements the new 32bit hash function to calculate pseudo random 0.0->1.0 hash values for the 4 corners of a 2D integer grid cell.
vec4 FAST32_2_hash_2D( vec2 gridcell )
// gridcell is assumed to be an integer coordinate
const vec2 OFFSET = vec2( 403.839172, 377.242706 );
const float DOMAIN = 69.0;
const float SOMELARGEFLOAT = 32745.708984;
const vec2 SCALE = vec2( 2.009842, 1.372549 );
vec4 P = vec4( gridcell.xy, gridcell.xy + 1.0 );
P = P - floor(P * ( 1.0 / DOMAIN )) * DOMAIN;
P = ( P * SCALE.xyxy ) + OFFSET.xyxy;
P *= P;
return fract( P.xzxz * P.yyww * ( 1.0 / SOMELARGEFLOAT ) );
The new hash function is slightly slower than the old one so I have left all current noises unchanged. But given that the new function allows for 4D hashing I have written some new 4D Value and 4D Classic Perlin noises. Complete source for the improved hash function and these new noises can be found on the GitHub repository.
It is always great to show an image at the end of a post, but it is hard to show the benefits of a 4D noise given that the images are not animated. One great use of 4D noise is through domain distortion (instead of applying a 3D noise over a 3D surface, use a 4D noise and feed an additional noise into the 4D dimension). The following image shows such an effect applied to the surface of a planet : )
Planet rendering showing a distorted fractal
I have been working with analytical noise derivatives lately and it turns out the analytical derivative of classic perlin noise can get rather involved.
Ken Perlin solved this problem in simplex noise by using radial kernel summation rather than interpolation to combine the gradient results. It occurred to me this idea can be applied back to classic perlin noise and as a result here’s two modifications to classic perlin noise.
Classic Perlin Surflet Noise
The first modification is simply the replacement of interpolation with radial kernel summation as done in simplex noise. The result is a noise which looks almost identical but has an easily computable analytical derivative.
Classic Perlin Surflet Offset Noise
After applying the first modification I realized we can now jitter ( randomly offset ) the gradient points to help break the fixed grid structure of classic perlin noise.
An animated gif comparing these changes with the original can be seen here. An example implementation can be found here.
Quintic Hermite Interpolation allows us to interpolate a value with respect to 3 variables. Its position, velocity and acceleration. In mathematical terms this translates to the function and its 1st+2nd derivative. More information on Quintic Hermite Interpolation can be found here.
Recall from a previous post that we require an interpolation function to have a 2nd derivative of 0.0 at the start+end points in order to be continuous for bump mapping. This is where Quintic Hermite Interpolation is useful. It allows us to explicitly use 0.0 for the start+end acceleration which will generate a C2 continuous curve. It also allows us to supply whatever we want for velocity giving us control of the gradient at grid lattice points. If the gradient vectors are normalized we get a look very similar to that of Classic Perlin noise. Here are some initial observations…
I have uploaded initial 2D+3D implementations of Hermite and ValueHermite Noise to the GitHub repository. ( like ValuePerlin, ValueHermite is a uniform blend between Value and Hermite noise )
2D+3D sampling of Hermite Noise
2D+3D sampling of ValueHermiteNoise
In 2001 Ken Perlin introduced a new type of gradient noise called Simplex Noise. The document can be found here. It is essentially his original gradient noise mapped onto a simplex grid. The term “Simplex” means the simplest possible primitive which can occupy space. In 2D it is a triangle and in 3D it is a tetrahedron ( 4-sided pyramid ). A simplex grid is a grid structure made of these primitives.
There are four distinct improvements his new noise had over his classic.
- A simplex primitive has far fewer verticies than its square/cube equivalent in 2D, 3D and higher dimensions which reduces algorithm complexity.
- It allows for an easily computable analytic derivative
- The simplex structure reduces axis-aligned artifacts
- It lends itself to an efficient hardware implementation
Stefan Gustavson has made some great contributions to Simplex Noise over the years. Most notably these are…
- Writing a much clearer description of Simplex Noise in his “Simplex Noise Demystified” document.
- Along with Ian McEwan providing GLSL implementations of Simplex Noise at WebGLNoise.
- Providing an implementation of Simplex Noise with analytical derivatives here.
I have been experimenting with implementing this and other noise types over simplex grids. As a result I have uploaded 3 new noise types to the GitHub repository.
The first is Simplex Perlin Noise in 2D and 3D. I have made two improvements over what has been supplied by Perlin and Gustavson. The first is a fix to a bug in the 3D surflet math which would cause discontinuities along the simplex faces, as can be seen here. The second is providing accurate scaling values to correctly scale the noise to a strict -1.0->1.0 range.
2D+3D sampling of Simplex Perlin Noise ( simplex gradient noise )
The second is Simplex PolkaDot Noise in 2D and 3D. The simplex grid packs the dots more tightly than the square/cube version which gives the noise a slightly different look.
2D+3D sampling of Simplex PolkaDot Noise
The final is Simplex Cellular Noise in 2D and 3D. I’ve used some optimization ideas as described in a previous post on Cellular Noise so it runs very efficiently. And given the reduced complexity in higher dimensions it could run a lot faster than its cube grid alternative. The problem is a simplex grid packs the points much more tightly in space than a cube grid which reduces area for the verticies to move. This reduces variance leading to a repetitive looking noise. Nonetheless it is still visually pleasing and well defined so I have included it into the code repository.
One final note is that I experimented with taking additional points into account ( other than the immediate corner verticies of the simplex ) to allow for more variance. The results were positive ( as can be seen here ) but costly and would only be of benefit in higher dimensions ( eg 3 or 4 ).
2D+3D sampling of Simplex Cellular Noise
I’ve uploaded three new noise types to the GitHub repository. The first is a PolkaDot style noise in both 2D and 3D which generates smooth falloff dots at random sizes, intensities and locations over a uniform grid. ( There’s even a one-line modification which can give square dots instead : ) )
2D+3D sampling of PolkaDot Noise
The second is a 2D Stars noise with behavior similar to the PolkaDot noise but which also allows for the possibility that a dot/star be not drawn. This can generate a sparse distribution of dots which look very suitable for a starry sky.
Sample of 2D Stars Noise
The third is a noise made more for fun. It is called “cubist” noise due to it resembling a cubist painting style. The problem is that it contains sharp discontinuities and also a possible range of +-infinity which must be arbitrarily clamped ( eg +- 1.0->5.0 ), so it is unfit for displacement or distortion but should produce some interesting results when used for texturing.
2D+3D samlping of Cubist Noise
Cellular Noise is a noise basis which mimics a voronoi diagram. It was first proposed by Steven Worley in his 1996 paper “A Cellular Texture Basis Function” and has been used extensively by the graphics community ever since.
Stefan Gustavson has been doing some great work with optimized GPU Cellular Noise lately at http://webstaff.itn.liu.se/~stegu/GLSL-cellular/. The usual implementation of 2D Cellular Noise searches over 9 jittered points on a 3×3 grid to find the closest point. Stefan has optimized it to work with 4 jittered points on a 2×2 grid. This reduces the work significantly but can create artifacts which show as discontinuities.
I will be using noise in my procedural modeler to create displaced surfaces as well as for solid texturing which mean discontinuities are unacceptable. So I have decided to continue on from Stefan’s work and create an optimized GPU Cellular Noise which is free from discontinuities.
The artifacts in Stefan’s implementation come from the possibility that closest jittered points may exist outside the 2×2 search region ( which is why Worley uses 3×3 ). We can eliminate this by reducing the jitter size ( eg from +-0.5 to +-0.25 ) so there can be no way a closest point can exist outside the 2×2 search region. I did some calculations and found in 2D this distance is +-0.25 and in 3D it is +-0.16666666. The problem with reducing the jitter distance to such a small amount is the noise has very little variation and the grid structure becomes apparent.
To fix this I use a cubic function to push the randomly placed points outwards to the extremes of the jitter window. The result is an acceptable-looking artifact-free GPU Cellular Noise which runs at an acceptable speed. I have uploaded 2D+3D implementations to the GitHub repository. I have left the original functionality proposed by Stefan in as an option in case the artifacts are acceptable for your own use.
2D+3D sampling of Cellular Noise
My next step with this is to explore one of Stefan’s other ideas. In 2D this is to sample things in a 2.5D manner where the points are jittered over the 2D grid as normal, but also jittered in a 3rd dimension. A 2D slice is then taken through the center of the 3rd dimension to sample the noise. This would add more variance to the 2D noise. The same can be done in 3D. Jittering would still need to be restricted to ensure a continuous signal but variance may be good enough that cubic weighting is not needed.