Simulating Erosion: An experiment

Coding Expeditions with Maurits
6 min readNov 15, 2020

Recently, I watched Sebastian Lague’s video on simulating erosion. However, his approach generated a 2 dimensional heightmap. At the same time, I was playing satisfactory and enjoying the beautiful terrain. However, this terrain was carefully designed by a human, could it be possible to procedurally generate this diverse terrain? I decided to give it a try.

A screenshot showcasing Satisfactory’s beautiful terrain.

My first attempt

I wanted the possibility overlaps and caves, perhaps even the beautiful sky arches from Satisfactory. Thus, a 2D heightmap was not going to be enough. Instead, I decided to use a 3D grid, witch each cell being a number between 0 and 1 representing how much sediment was in that cube. Then the result was rendered with marching cubes.

The first algorithm was very simple. Drop a “raindrop” at a random point in the terrain. The drop travels to the neighboring point with the lowest sediment. Subtract some sediment. Repeat until the drop stops, then start another drop.

The result of algorithm 1, at least there is no shortage of overhangs.

The algorithm in this state had some problems. Drops would tend to go down too fast, carving holes in the interior, while leaving the surface to flat. Since many drops would tend to take the same route, it tended to generate rough, jagged terrain, not smooth spaces suitable for gameplay. Water droplets tended to double back on themselves since sediment from their previous positions where subtracted.

Algorithm 2

Algorithm 2 made many small improvements. A drop would finish it’s whole path before subtracting sediment from all places at once, to prevent it effecting itself. Rain drops entirely enclosed in terrain would slow down much faster, to prevent long underground cracks. Subtracting sediment would have a small area of effect to smooth the terrain more, and attract other drops from a larger radius.

The biggest difference though was the hardness function. Every cell had a generated hardness, computed through simplex noise. Any effect would be divided by the hardness level. This simulates how many real-life terrain features are caused by a difference in hardness between different types of rock. It took a bit of work to balance the effect to that the result would not just be the noise function, as all soft rocks where gone and all hard rocks didn’t. However, when sufficiently subtle this created more interesting terrain.

The hardness method had another use though. I made rock harder the deeper you go. This is to prevent too deep canyons and holes in the terrain. Now drops prefer going more horizontally.

Terrain generated with algorithm 2. Blue line is a raindrop. Colors represent hardness.

The changes paid off. Now the terrain is a lot smoother and flatter. However, now it has become, well, boring. There are no longer any interesting features, like caves. There are no steep mountain sides. You can’t even clearly see the water path. There are a couple of mesa’s, so the 3d nature did pay off. I need a way to strike the balance between realistic and interesting.

Another problem is the large holes that develop around the center of the terrain. Even if the hardness is very high, if many drops have nowhere to go they will continue to make hole slowly continue to grow deeper.

The opposite happens round the edges. With the new radius subtract, edges of the map tend to stay elevated more since there are less voxels surrounding them. When a drop passes the edge, it tends to subtract from the inner side more then the outer side, thus creating a slope inwards. This in turn prevents more drops from crossing the edge worsening the effect.

Algorithm 3

This version changes the way that sediment is subtracted, to prevent the asymmetry around the edges and prevent holes. Instead of subtracting for every point in the path, this version recalculates a series of points to be equally-distant segments. This prevents the speed of the drop from effecting how the path is drawn. Specifically, when a drop “falls” after reaching the edge, it will subtract along it’s entire path from the edge to the ground, counteracting the asymmetric subtracting at corners.

Additionally, I double the subtraction strength of drops if they reach an edge.

Result of algorithm3, coloring is for steepness now.

The result generates steeper terrain, but more importantly has the edge be the lowest, rather than the highest point.

Final Algorithm

At the end I changed the subtraction algorithm more so water drops that do not reach the edge don’t subtract past their halfway point at all.

Additionally, I added a “cleanup” function that removes any completely isolated floating terrain.

Also, I added trees, flowers and grass, to make it all a bit more fun:

Terrain with trees and grass.

The algorithm still generates deep canyons, but they tend to follow a somewhat realistic watershed path, and have a gradual downwards slope so that higher areas are reachable, which would be important if this was ever used in a game. There are occasional sky-bridges, but not enough to be unrealistic. I didn’t meet my goal of creating a map of similar quality as Satisfactory, but I’m pretty close.

If you want to play with the code yourself, it can be found here.

Future Additions

While I’m pretty happy with the result, there needs to be a lot more work if the terrain should actually be used in a game.

The world is currently really small. The computation cost scales to the fourth power of the terrain size, thus a 64 by 64 grid is the best my computer could handle in a realistic time. However, in a actual game world this would be much too tiny. Maybe there is a way to generate the terrain on loose segments and then stich them together. Maybe you can first generate the whole map at a very low resolution then repeat at a much finer level for smaller parts. I’m open to suggestions, or feel free to experiment with my code yourself.

A major strength in Satisfactory is all the different biomes with radically different geometry. There need to be plains, mountains, islands, deserts, swamps, and much more. Thus, the generator needs to be customizable so that many distinct types of terrain can be generated. These different types need to be able to smoothly meet, and of course the water shed and rivers can pass through many types of terrain.

Despite my additions in V4, the edge is still ugly. Right now I model the edge as a sheer cliff of infinite depth, but is that what you want? It might be better to consider the area as an island, surrounded by ocean. Thus water will fall only upto the sea level. It might even be possible to simulate the erosion caused by the waves, and get realistic beaches and lagoons.

I might expand on these ideas later, but feel free to give it a try yourself. I found this to be a very interesting exercise, and I learned a lot doing this. There seems to be surprisingly little research in this area, but I don’t think the task is impossible. If a few bright minds keep coming up with new ideas, procedural realistic terrain generation might not be far away.