Real-time Planet-scale Erosion

Published January 11, 2023
Advertisement

The past few weeks I have been working on adding erosion simulation to my planet generator/renderer, which you can read more about in this blog post. I wasn't confident that this could actually be done, but I believe to have some success in this area.

200km sized river drainage networks

The general idea of the terrain generation is to recursively generate hierarchical FBM noise, transform that noise into some nice looking shapes, then apply edits to that elevation data to implement things like destruction, impact craters, volcanos, and other unique geological features. Then, an erosion algorithm is applied to the result to add nice erosion features.

I used the erosion algorithm from the paper “Fast Hydraulic Erosion Simulation and Visualization on GPU” by Mei et al. (2007). This is relatively simple and fast. The paper does have some problems though that prevent a basic implementation from working well. It does not include slippage weathering to enforce slip angles, and perhaps the biggest problem is that it does not include the fluid depth as part of the sediment transport capacity calculation. This means that a tiny stream and huge river have the same sediment capacity, as long the slope and velocity is the same. LOL, what an oversight. I think the authors mis-read the paper they cite, because the cited paper does indeed include fluid depth (as symbol q = v*h). Fixing this issue means that it is much easier to form ravines and other erosion features, because there is a feedback loop that causes more erosion where there is more fluid.

The hierarchical erosion algorithm works by applying the following steps at each LOD:

  1. Take parent LOD and interpolate/upscale the part corresponding to the tile. Noise, elevation, fluid depth, sediment, and fluid velocity are all transferred from parent to child.
  2. The key to making it work well (i.e. fluid flow) across tiles is to copy in the border regions from neighboring parent tiles before upscaling. This creates limited cross-tile communication, and also helps with continuity issues between tiles. There are still some seams between LODs, but these are caused by the smaller LODs being more eroded.
  3. Add white noise to the upscaled parent noise.
  4. Convert resulting noise to a fancy terrain shape by applying some math functions to warp the noise.
  5. Apply erosion from parent, which is stored as the difference between the eroded and uneroded elevation maps. This gets interpolated and added to the higher-resolution noise-derived elevation from the child.
  6. Apply other terrain edits (e.g. impact craters).
  7. Erode the terrain elevation, with the simulation state initialized to the interpolated data from the parent. I do only 16 time steps, which takes 2.1 ms per 61x61 tile, with heavy SIMD optimizations.
  8. Calculate the difference between the eroded and original uneroded terrains. This is stored so that it can be used in the child tiles to apply the erosion recursively.

Some unsolved issues are how to generate better global structure in the drainage networks. Basic noise elevation produces lots of tiny watersheds. I added a hack that deliberately fills in local minima, and this helps quite a bit (producing the image above). It's still not quite what I would like, where all points on a continent drain to an ocean. I can hopefully resolve this global structure problem once I focus more on tectonic simulation, which will produce better looking continents and more realistic drainage systems.

It's hard though, because so few time steps are done that it's impossible to have much in the way of emergent phenomena. Eventually, real continents produce elevations with very few local minima, but this is created over hundreds of millions of years of erosion, not just 16 time steps. So, I have to find some efficient way to enforce this global structure.

Overall though I'm very happy with the results so far. There is still a lot of tuning to the algorithms, and eventually all of the algorithm parameters will be controlled automatically by unique planet conditions (e.g. gravity, precipitation, materials, fluid type). Performance is acceptable. It takes about 2 seconds to generate the scene, but then movement is fairly smooth after that as long as you don't move too fast. Once I make the generation asynchronous and multithreaded, it should work quickly without any stuttering at all. Memory usage is reasonable, just about 300MB total for typical quality settings (including the generated meshes).

3 likes 5 comments

Comments

JoeJ

Awesome! This puts the procedural universe dream to a new level. \:D/

I would be very curious about the singualrities. I guess you use a cube map tiling, so at 8 points there meet 3 tiles instead 4 as usual. Did this cause you serious additional work or problems?
I consider to do such 2D simulations on the surface of quadrangulated meshes, and expect it would cause noticeable artifacts on singular vertices, forcing me to factor in the parametric stretch into the simulation.
But i rather hope i can get far enough with full but slow 3D simulation, not really having time left to work on another simulator…

The biggest issue i see on your results are the axis aligned rivers.
To avoid axis snapping, i have extended the papers proposals with considering all 8 neighbors of a cell, instead just 4. With proper weighting.
I have tested this with a drop of water, ensuring the waves it causes form a true circle, which it did after the extension.
It gave better quality, but cost almost doubled as well.
Maybe a cheaper hack would be to use noise so some parts are more resistant to erosion than others, forcing the water to take more random paths.

But it's a minor issue. I'm much more excited to see this first attempt of doing proper procedural modeling in real time. It's day and night compared to the old standards based on mixing various noise patterns and hoping something natural pops out.
True progress! :D

January 11, 2023 08:27 AM
Aressera

@JoeJ: I would be very curious about the singualrities. I guess you use a cube map tiling, so at 8 points there meet 3 tiles instead 4 as usual. Did this cause you serious additional work or problems?

It's not that bad at the moment, though there are still some special cases to deal with on the vertices and some edges of the cube. This is really tedious to get right for all points on the sphere, so I haven't done it yet. The step that copies in the data from the parent tile neighbors helps to cover up the seams in most cases, because I also copy in the difference between the noise elevation and eroded elevation. As the LOD increases, the seam gets reduced due to the neighbor copying at each step.

The biggest issue i see on your results are the axis aligned rivers.
To avoid axis snapping, i have extended the papers proposals with considering all 8 neighbors of a cell, instead just 4. With proper weighting.

Indeed, I actually implemented this last night right after posting this blog, and it does completely remove any axis alignment of the erosion features. Yeah, it's about half as fast, but the quality improvement seems to be worth it.

January 11, 2023 06:38 PM
JoeJ

It does not include slippage weathering to enforce slip angles

Problems like this, e.g. causing deep gullies at local minima, found quite a number of creative hacks across implementations.

The WebGL project i have linked last time for example used to calculate curvature. This way you can identify valleys or peaks, and decide which parts erode how much. Pretty cheap and useful.

To deal with related issues on a larger scale, i came up with some hack to model static forces, to prevent valleys becoming too deep, or peaks becoming too steep.
Imagine we have some island. Then we could calculate a SDF from the shoreline inwards. Like a Photoshop filter, this gives us some plastic 3D effect of raising hight away from the shoreline.
I have used this height as a kind of threshold to avoid the mentioned issues. The SDF calculation isn't instant, but refines over time each update, so it could be realtime.
But still quite expensive, and just to mention.

Another thing i did is using cubic texture filter for advection. Also quite costly, but can help with axis alignment and high frequency noise.

Interesting: I found advection of the sediment is not really needed. I got very nice results alone with diffusing the sediment as well.

It feels much more a matter of creativity than attempt to do correct simulation. It's black magic and parameter tweaking hell. You may have a very good idea, but you might not notice because you missed the proper parameters to show the advantage.
Or, even worse: You have nice results, but forget to save the parameters. And then you spend hours in desperate attempts to reproduce those former results after some time.
This happened a LOT to me. I have wasted days on that. : )

January 11, 2023 08:50 AM
Aressera

@JoeJ: Problems like this, e.g. causing deep gullies at local minima, found quite a number of creative hacks across implementations. The WebGL project i have linked last time for example used to calculate curvature. This way you can identify valleys or peaks, and decide which parts erode how much. Pretty cheap and useful.

I did encounter this issue as well, where a steep slope would produce an effect similar to edge enhancement in image processing, with a deep hole at the bottom, and a ridge/peak at the top. I used the local extrema “smoothing” approach from the WebGL erosion project (might be the same one you mention), and this seems to mostly fix the issue, but not completely.

Another thing i did is using cubic texture filter for advection. Also quite costly, but can help with axis alignment and high frequency noise.

Yikes! I have implemented nearest neighbor and bilinear interpolation, but even bilinear is very slow. The above results are generated with nearest neighbor. Are you talking about velocity or sediment advection?

Interesting: I found advection of the sediment is not really needed. I got very nice results alone with diffusing the sediment as well.

Hmm currently I am actually removing most of the sediment from the simulation completely (when going from parent to child tile), which intensifies the erosion features. I haven't been able to retain the sediment from parent to child and still get nice looking results. I guess in reality, most of the sediment flows to the ocean so it is removed.

It's black magic and parameter tweaking hell.

Agreed, I spent several nights just tweaking parameters to get decent results. It's much harder when you are working in weird units (I simulated everything in planet radius units, e.g. elevation gets multiplied by planet radius to get meters).

January 11, 2023 06:47 PM
JoeJ

Are you talking about velocity or sediment advection?

Tried it for both. It makes a difference, but since the cubic filter causes blurring which we could get much cheaper, i can't say if it's a general advantage or disadvantage. With realtime budget i would say it's not really interesting.
But nearest neighbor sounds harsh. For this kind of code doing it on GPU wouldn't be too tedious i think. Maybe an option for the future if needed.

> Hmm currently I am actually removing most of the sediment from the simulation completely (when going from parent to child tile)

Initially i didn't transfer sediment state between LODs either, just turned it into all into ‘rock’. Now my particles remember how much of their mass comes from sediment. Sediment then causes softer surfaces than rock. *
When i had troubles with good results in 3D, i've spent a lot of effort on achieving mass conservation, so sediment did not disappear during the simulation of a single LOD.
But it was no key to success really. I found that allowing sediment to vanish gives more ravines and details, so i still use aggressive settings violating mass conservation for artistic reasons.

One thing i had tried on my road of failures was to model sediment with particles, at double the resolution of the rock. Costly, because i need one more simulator for the sediment, but interesting.
I will try this again to model landslides maybe. I feel the need to add some new things to get better close up details. Rigid body simulation with fracture might be useful too…

> It's much harder when you are working in weird units

The hardest problem is to make the same settings give the same results independent of the scale of a LOD.
I found it faster to do trial and error with experiments, than trying to figure out correct math. Parameters have to be scaled with s, s^2, or s^3, or the reciprocal of those… I really have lots of params, so that's quite a pain ; )
If i would start from scratch, would set the unit scale from a single grid cell, not the whole domain. If i had done this, i think scaling params would not be needed at all.

*) That ‘soft sediment’ feature is interesting maybe. Here an image:

You see a clear distinction between rock and soft sediment. The wavy banding is actually an artifact from SDF particles to isosurface meshing, in fact the floors are indeed very smooth.
To get this, i use the sediment percentage to make curvature bumps erode, and sinks fill up more easily. So that's a good example of using curvature and art control to get richer results.
I have also experimented with the curvature gradient, which gave me terraces, or alien structures. I also tried true primary curvature directions. That's what we really want to have, but seems to expensive even for my offline needs.

Still lots of work… getting rivers for example (much harder in 3D with particle water), or landslides, caves, artist control to get multiple biomes… It's fun, but way more work than thought.

January 11, 2023 08:12 PM
JoeJ

found quite a number of creative hacks across implementations.

… but the most adventurous hack i saw here (maybe the wrong blog post): https://nickmcd.me/2022/04/15/soilmachine/#layer-saturation-and-water-model

The guy uses the droplet approach, thus the water particles do not interact with each other, and can form no lakes.
So he did kind of breath first search to identify minima and sections where a lake should form, and then water flowing into a lake searched for a way out on it's lowest edge, to prevent the particle from getting stuck in the local minima.

Haha… the fallacy of the droplet approach, lol. But still many people claim it gives them ‘better results’. : )

But seems the linked blog illustrates the idea to use noise to reduce the axis aligned rivers. Seems to work well. : )
And the guy has lots of ideas, e.g. on some form of tectonic simulation.

January 11, 2023 09:06 AM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement
Advertisement