Terrain Generation II: Features & Structures

Last time we talked about heightmaps and how the world is divided into regions. This time we're going to talk about many different features that come together to give Fableforge's terrain more diversity!


An intertwined cave system.

Fableforge generates caves pretty easily. For caves, 3D value noise is used. I like using value noise instead of simplex noise because it creates long, more linear, caves with sharp changes in direction. Simplex noise will give you caves with more gradual changes in direction.

Caves are generated in our code easily by defining a threshold for blocks to not spawn. In code it'll look something like this,

float caveNoise = GetNoise(x, y, z);
if (caveNoise > minThreshold && caveNoise < maxThreshold)

This is used within a loop over the y-axis. If we are not within the cave threshold we place whatever block we need to place at that position.

This gives us some simple caves for now. In the future this code will be extended to create much more interesting caves with their own unique environments depending on what region they are in. This could mean different structures spawning inside caves, different surface blocks, flora, or lakes of water or lava.

Cliffs, Overhangs, & Floating Islands

Small overhangs protruding from a cliff over a shallow lake.

To generate cliffs, overhangs, and floating islands we do pretty much the same thing as we do with caves. We use 3D value noise for here too, as well as an erosion threshold. The difference here now is that we do not go below the base heightmap (see part 1)!


A shallow river cuts through a forest.

Rivers are generated using simplex fractal noise. Just like caves and overhangs we use a threshold. This threshold will tell us where in the heightmap do we carve out a river. Rivers follow a pretty simple formula,

Height = River floor + (height from river floor * erosion mod)

The value of the erosion mod decreases the closer you get to the midpoint of the min and max threshold values.

One drawback to this method is that the width of your rivers is quite dependent on the 'height from river floor' variable. You'll get narrow rivers if they decide to generate in a mountainous region, and wide rivers if they generate in low altitude terrain.


A dense forest under a partly cloudy sky.

Trees are generated using simplex fractal noise. Each region will give their trees a certain density for them to spawn. Then they'll use the simplex fractal noise to add on top of that base density to give variable spawn rates within each region.

If a position meets the requirement for spawning a tree so far, a random number will generate. If that random number is above a certain value then we can spawn the tree!

This can apply to any type of structure, not just trees. The code is there to use it for things like buildings (but of course buildings will need to follow their own set of rules for spawning).

The trees are created using a voxel asset editor called MagicaVoxel. They are then imported into Unity and the terrain system reads them and stores each model's data for use when generating the terrain.

Each region will choose some of these trees to add to their terrain. They also decide what types of leaves are used, and the chance for each tree to spawn. Regions will also give each type of leaves a certain chance to spawn.

That wraps it up for this part of the terrain generation series. Next time we'll talk about how Fableforge handles different 'climates' to create even more diversity in each region!