# Eroding Fractal Terrains with Virtual Raindrops

A long while back I added a very simplistic fractal terrain simulator to Visions of Chaos. I had an idea to try and add erosion simulation into the existing code to get some more realistic terrain shapes.

Generating the inital terrain

There are many ways to generate a terrain height array. For the terrain in this post I am using Perlin noise.

This is the 2D Perlin Noise image…

…that is extruded to the following 3d terrain…

An alternative method is to use 1/f Perlin Noise that creates this type of heightmap…

..and this 3D terrain.

Simulating erosion

Rather than try and replicate some of the much more complex simulators out there for wind and rain erosion (see for example here, here and here) I experimented with the simplest version I could come up with.

1. Take a single virtual rain drop and drop it to a random location on the terrain grid. Keep track of a totalsoil amount which starts at 0 when the drop is first dropped onto the terrain.
2. Look at its immediate 8 neighbors and find the lowest neighbor.
3. If no neighbors are lower deposit the remaining total soil carried and stop. This lead to large spikes as the totalsoil was too much. I since changed the drop rate to the same as the fixed depositrate. Technically this removes soil from the system, but the results are more realistic looking terrain.
4. Pick up a bit of the soil from the current spot (lower the terrain array at this point).

soilamount:=slope*erosionrate;
totalsoil:=totalsoil+soilamount;
heightarray[wx,wy]:=max(heightarray[wx,wy]-soilamount,0);

5. Move to the lowest neighbor point.
6. Deposit a bit of the carried soil at this location.

deposit:=soilamount*depositrate/slope;
heightarray[lx,ly]:=heightarray[lx,ly]+deposit;
totalsoil:=max(totalsoil-deposit,0);

7. Goto 1.

Repeat this for millions of drops.

The erosion and deposit steps (4 and 6 above) simulate the water flowing down hill, picking up and depositing soil as it goes.

To add some wind erosion you can smooth the height array every few thousand rain drops. I use a simple convolution blur every 5000 rain drops. This smooths the terrain out a little bit and can be thought of as wind smoothing the jagged edges of the terrain down a bit.

Erosion Movie

Here is a sample movie of the erosion process. This is a 13,500 frame 4K resolution movie. Each frame covers 10,000 virtual raindrops being dropped. This took days to render. 99% of the time is rendering the mesh with OpenGL. Simulating the raindrops is very fast.

and here are screenshots of every 2000th frame to show the erosion details more clearly.

Future ideas

The above is really just a quick experiment and I would like to spend more time on the more serious simulations of terrain generation and erosion. I have the book Texturing and Modeling, A Procedural Approach on my bookshelf and it contains many other terrain ideas.

Jason.

## 3 responses to “Eroding Fractal Terrains with Virtual Raindrops”

1. I have been looking around for an easy to implement erosion automaton, and seeing this, I may have found it. One question: for depostion, is it supposed to be soilamount*depositrate/slope, or did you mean totalsoil*depositrate/slope?

• softologyblog says:

Yes, that is correct. soilamount is how much soil the raindrop picks up. totalsoil is the total amount of soil the drop is carrying.

Here is the snippet of code I use for when the drop finds a lower spot next to it on the terrain.

``````
if foundlowerpoint=true then
begin
//find the slope between the water drop and where it ran to
run:=sqrt(sqr(lx-wx)+sqr(ly-wy));
rise:=heightarray[wx,wy]-heightarray[lx,ly];
slope:=rise/run;
//remove a little bit of "soil" from the source spot
//soilamount:=heightarray[wx,wy]/heightarray[lx,ly]*0.5;
//soilamount:=(heightarray[wx,wy]-heightarray[lx,ly])/255*50;
soilamount:=slope*erosionrate;
totalsoil:=totalsoil+soilamount;
//wash away some soil
heightarray[wx,wy]:=max(heightarray[wx,wy]-soilamount,0);
//deposit a fraction of the "total soil" being carried at the new spot
deposit:=soilamount*depositrate/slope;
heightarray[lx,ly]:=heightarray[lx,ly]+deposit;
totalsoil:=max(totalsoil-deposit,0);
//move the raindrop to the lower spot
wx:=lx;
wy:=ly;
end
```
```
• Thanks for the clarification! After some work, thanks to you, I finally have a satisfactory erosion function. I couldn’t thank you more. I’ve labored fruitlessly for weeks, even trying to go from the bottom up by fumbling through fluid dynamics, your post here is not only effective but actually incredibly easy to understand.