Node-based Evaluation Part 1 - Noise Functions

What is noise?

Everyone is familiar with the concept of noise as an unwanted sound. Readers with a background in electrical engineering or physics might be familiar with a more technical definition: A mostly unwanted random addition to a signal. For example, a random addition to an audio signal is audible as static, while a random addition to an image is visible as grain. However, in some contexts, noise is not an unwanted error, but instead a desirable property of a function. That is, we specifically construct functions that have a noisy component, for various purposes. Noise introduces a random component to a function, which is exactly what we need if we want to generate pseudo-random terrain.

What types of noise are there?

Naturally, there are multiple types of noise. Indeed, any function that has a noisy component could itself be classified as noise. The most basic noise functions behave very similar to the audio and video noises mentioned above. One of the most well-known classes of noise is white noise. White noise has three properties:

  • All samples are uncorrelated
  • The mean of the samples is zero
  • The variance of the samples is finite

A common variant of white noise is uniformly distributed white noise, where all possible values have the same likelihood of occurring. A perfect random number generator would thus create uniformly distributed white noise. For example, the picture below depicts uniform white noise between 0 and 255:

Of course, different distribution functions yield different white noises; a normal distribution yields Gaussian white noise, and so on. While these noises have their applications, we are interested in creating terrain. For this, we do not wish for the noise values to be uncorrelated, because good terrain needs at least some level of coherence. Luckily, there are other types of noises we can turn to, which will be examined in detail below.

Perlin Noise

In 1997, a computer scientist by the name of Ken Perlin won an Academy Award for Technical Achievement for developing the so-called Perlin noise. Perlin noise, at the most basic level, is a gradient noise. That is, a lattice is laid over the space in which the noise should be generated. Then, random gradients are assigned to the lattice points, and interpolated in the space between. There also is a value noise version of Perlin noise, which consists of assigning values to the lattice points, and then interpolating these values. This version is easier to generate, but produces a lower-quality noise. The pictures below depict 2D gradient noise. In the first picture, the noise value is presented unaltered, while the second picture depicts maximal white (#FFFFFF) for high noise values, and maximal black (#000000) for low noise values.

From the right picture, the grid nature of Perlin noise is clearly visible. A possible approach to reduce this could be adding value noise to the gradient noise.

Taking it to the third dimension, and extracting a surface from the noise where it equals 0.1 results in the following terrain:

Worley Noise

Another continuous type of noise is Worley noise, named after Steven Worley, who developed it in 1996. In Worley noise, seeds are randomly distributed in space. The value of the noise at a given point is the distance to the closest of these randomly distributed seeds. Higher order versions of Worley noise are obtained by defining the noise value as the distance to the nth-closest point.

Fractal Noise

Fractal noise can be seen as an extension to noise. Instead of simply sampling the noise function at one point, we define a factor $$k$$, a depth $$d$$, and then evaluate the noise function $$f$$ as follows: $$!\sum_{i=0}^d (k^{-i}\cdot f(k^i\cdot x))$$ That is, we sample ever higher frequencies of the noise, but the weight in the sum decreases as the frequency increases. For Perlin noise, a higher frequency corresponds with a smaller lattice, while for Worley noise, it corresponds with seeds being more tightly packed. The result of the fractalization process is a more detailed noise.

For illustration, have a look at the fractalized Perlin noises (normal and thresholded) below:

Why do we want noise?

Without some sort of noise, we would not be able to generate multiple objects (multiple textures, multiple terrains) from the same function. To obtain a virtually limitless supply of different results, we have to have some sort of random component. However, as was stated earlier, simply adding uncorrelated noise to the equation will oftentimes not produce the desired results; therefore, we turn to the more sophisticated continuous noises. Furthermore, noise mimics a natural process of erosion - taking some coarse initial structure, and changing it little by little.

What is lacking?

Looking at the pictures of the 3D Perlin noise above shows that these simple noises are not enough by themselves. Perlin noise might make for nice, if a bit bland cave systems, but it cannot, by itself, be used to generate mountains, valleys and all the other interesting terrain features one might want to use. While the different noise types are all interesting in their own regard, ideally we want to combine different noises with arithmetic operations of some sort. For example, we might want to scale the input in one direction of the noise, to produce elongated structures. Or we might want to use the output of a Perlin noise function and use it as an input for one of the dimensions of a Worley noise function. Especially in the context that these connections should be definable by scripts and mods later on, we cannot simply hardcode them. Therefore, we need a system to express these connections. We will take a look at this system in the next article. Stay tuned, folks!