Terrain Generation through Tectonic Uplift and Fluvial Erosion
Solo (2018)

Introduction

I was goofing around in Shadertoy when I came across a really cool looking erosion algorithm, around November of 2018. At this point, I was pretty comfortable with noise functions in shaders, but this was something very new, to me! It also reminded me of some stunning examples by Loren Schmidt which are unfortunately buried on twitter and I can no longer find them. I played around with it a bit and did this shader (also as a first foray into ray-marching), but the shader approach was somewhat unsatisfying, since it is tied to the resolution of a texture and requires some tricks to implement moving quantities.

A couple of weeks later I found this paper and decided to implement it, since it worked directly on meshes. It worked surprisingly well, and gave me a decent foundation from which to deviate if I ever need to. This is the result.


How does it work?

The algorithm is roughly as follows:

  1. Create a tectonic lift map (basically a heightmap with the different "growth rates" of the terrain (mountains will be areas with higher growth, etc.)); I used simple perlin noise for this, but you read the paper for other examples, like a "depression line" to simulate an ancient river which forms a canyon;
  2. Create a Voronoi Diagram of points spread over the terrain (I used a simple Poisson distribution to keep distances fairly uniform but still maintain a "natural" randomness and avoid artifacts of an orthogonal grid);
  3. Compute the river basins (and link them to simulate "lake overflow"); see figure on the right;
  4. Compute that water flow to each voronoi cell (based on the aggregated area of the cells that transport water into it);
  5. Apply the stream power equation (given in the paper).
This is basically it. This short description hopefully gives you a rough idea of how it works, though I recommend looking into the paper if you want more details.

It also runs surprisingly quickly. I limited myself to 65 000 vertices, since that's what Unity's meshes allow, and it took less than a minute to run, even without any particular care of optimization. It's also very flexible, since you can apply iterations individually (for more or less erosion) and the initial heightmap gives you control over the rough features of the terrain (a mountain here, a plain there, etc.).

It was also cool that I had some familiarity with Voronoi diagrams from the Voronoi Tilings project, since I could just reuse the algorithms without much friction, and it is surprising where apparently idiosyncratic experiments turn out to be applicable in completely unrelated areas!


Rendering

I didn't do much work on the rendering, but beyond pure terrain, but you can see some examples below. Since you can compute the water flow between the voronoi points, you can use that information to color the mesh. It's not obvious which amount of water counts as a "river" (you can see the second picture having too low a threshold, fixed in the third). Still, with some experimentation, you can get fairly good looking results - and, of course, better if you touch it up by hand later. And, either way, they certainly look more natural than the pure techniques using noise!

You can also get some very natural-looking patterns like those of Van de Graaf Generators (not to be confused with the amazing band van DER graaf generator or veins. These are also similar but "sharper" than Diffusion-limited Aggregation patterns.