This blog post details how the Perlin noise algorithm was reused to add more detail to terraced terrains generated by Terraced Terrain Generator (TTG). It is part of a series that documents the development process of TTG, containing the following posts:

The problem

Although the terraced terrains generated by TTG were great (particularly after the addition of custom terrace heights on version 1.1.0), something still felt off. The generated terrains don’t exactly pass as real-life ones. An example is the best way to understand the problem at hand. Take the following terrain, with a feature frequency of 0.055:

Even though it looks quite nice, it is quite feature-poor and its edges are quite smooth, far from natural-looking. How can we change the generation parameters to obtain more detail? Given that the level of detail is a generation parameter (a.k.a. feature frequency), we can try increasing it. Let’s give it a try. If we increase the feature frequency of the terrain above to 0.7, we get the following terrain:

The terrain above is definitely feature-rich, but it has two problems. First, if you look closely, you will notice that the features are relatively smooth and none of them resembles erosion, random land formations, pits, etc. Second, there is a lot of repetition. It seems like the terrain above was generated by creating an island terrain, copying and pasting it dozens of times side by side. Tweaking other generation parameters might help a bit, but only gets us so far.

Ideally, we would like to have more details and variation within the terrain features; not just copies of the same features, over and over again. It would be nice to be able to create, for example, a terrain with a large portion of water with some bays and a detailed, feature-rich land with large beaches containing some peninsulas and islands, a dense forest with some clearings and rocky mountains with signs of erosion. In short, it would be great to have more imperfect, natural-looking terrain.

The behavior described above is a characteristic of the noise algorithm chosen by TTG: Perlin noise. This sample graphical representation of a Perlin noise output is a great way to gain some insight on what is going on:

Perlin noise example

Notice how the features (white and black areas) are of comparable size. There are no large areas, neither black nor white. Similarly, there are no small but abrupt color changes; the clusters are always surrounded by a gradient. Finally, the shape of the features is mostly round, with smooth transitions between them.

These characteristics reflect on the generated terrains. Clusters (either mountains or valleys) are of similar size, there are no abrupt changes of height and their shape is mostly round, with smooth edges. In other words, there is a general lack of detail within the terrain features.

The solution

There is a well-known strategy to eliminate this problem: Perlin noise octaves. The general idea is to apply multiple passes of Perlin noise algorithm, each one with a higher frequency than the previous one, but with a lower “strength”. The outcome is a noise that resembles and preservers the shape of the original one, but with finer, more localized detail. When applied to terrain generation, it potentially generates more natural-looking terrains—depending on parameter values.

Perlin noise octaves can be implemented as different iterations (or passes) using a for loop. Each iteration represent an octave and will apply the Perlin noise algorithm with slight different frequency and “strength” (often called “amplitude”), based on the values of the previous octave. Initially, the amplitude is set to 1 (representing 100%) and the frequency is set to the terrain’s base frequency. At the end of each iteration, the frequency is increased by multiplying itself by a constant factor (often called lacunarity, greater than 1) and the amplitude is decreased by multiplying itself by another constant factor (often called persistence, less than 1). This process is repeated as many times as the desired number of octaves.

The function below uses Perlin noise octaves to calculate the height of a vertex based on its coordinates and the number of octaves to be applied. It is a slightly modified version of the original code introduced on TTG’s generation step 3. The values of the base frequency, persistence and lacunarity are constant for demonstration purposes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
static float GetHeight(float x, float y, uint octaves, Vector2[] offsets)  
{  
    float height = 0;  
    var amplitude = 1f;  
    var frequency = 0.055f;  
    const float persistence = 0.5f;  
    const float lacunarity = 2.5f;  
    for (var i = 0; i < octaves; i++)  
    {       
       var offset = offsets[i];  
       var filterX = x * frequency + offset.x;  
       var filterY = y * frequency + offset.y;  
       var noise = Mathf.PerlinNoise(filterX, filterY);  
       height += amplitude * noise;  
       frequency *= lacunarity;  
       amplitude *= persistence;  
    }  
  
    return height;  
}

A fairly similar function is used in TTG’s code, with parameterized values instead of hard-coded ones.

The outcome

The GIF below displays the usage of Perlin noise octaves, with four terrains: the terrain we’ve been using as an example in this section, and three other ones; each one with an increasing number of Perlin noise octaves, from 1 to 3 (check the left bottom corner of the image for octave count). All terrains were generated with a persistence of 0.375 and a lacunarity of 2.52.

A looping gif displaying 4 different terrains, with increasing Perlin noise octaves count, from 0 to 3

The value of the octaves is clear: they add detail without changing the scale of the terrain, delivering a more natural-looking outcome. That’s exactly what we were looking for.

Conclusion

Perlin noise octaves are a simple, yet quite satisfactory solution for adding more detail to terraced terrains. This feature shipped as part of TTG 1.2.0, where both the API and the helper component were updated to support Perlin noise octaves. On the next release, I plan to add spheres as a basic terrain shape, allowing terraced planets to be created using TTG.