Pregenerating Rivers


A perlin texture with lots of dimples will create lots of lakes. By the time the lakes have filled with enough silt to join them, the landscape has pretty much been obliterated by erosion. In the real world, there are things like hydrostatic pressure to erode dams. Instead I do a riverfying pass.

A random landscape tends to form lots of dams and lakes. Some riverfication helps naturalise the terrain.

After trying a variety of techniques I've settled on the following:

1. Create rain map from lush map for the most wet areas, then pointise it.

Since the pathfinding algorithm is one texel wide, you need to scale the river map accordingly. This doesn't mean you are commiting to a river width, the eroding brush can be bigger than one texel. Further erosion will alter the widths of the pathway, but you need it to be approximately sensible.

2. Flood fill for each river start to the edge/sea level.

Terrain with the flood map superimposed. The blue is flooded area while trying to find a way out. Yellow texels are the start of the rivers. Insets are lushmap and floodmap. Basically the floodmap is a lushmap that guarantees rivers make it to the ocean or edge.

I use a flood fill rather than the original lush map because the original tends to be splotchy and theres no guarantee rivers make it to the ocean. The basic procedure is migrate down until you can't go down anymore. Then flood fill raising the water level by the next neighbouring height until a texels height is less than the flood increase. This means you've just spilled over a dam. Start again from this new point. Although getting this up and running isn't too hard, you'll need to spend a bit of time getting it fast enough for large textures without letting it run all day.

3. Stringize the flood map, giving preference to downhill texels.

Terrain with the flood map superimposed. The flood map is stringized for ease of the pathfinding algorithm.

Some of the paths are a little convoluted, but so long as the waterways are narrowish, a simple pathfinding by steps is adequate.

4. Create a path map for each river end and try to path all river starts to it.

Rivers cut into the terrain by using a simple path algorithm. The blue is the final flood map.

Count up based on the slope of the next texel to encourage following the lowest path. Imagine a giant marble carving out valleys as it rolls down hill; I carve a shape of a logarithmic curve based on the amount of water I've accumulated. It doesn't have to be perfect, after erosion, it will look natural enough.

Rock is not eroded by the river pass, which can lead to dams and lakes forming. I've thought about filling flooded areas with silt to avoid carving too deeply into the terrain, but it's basically workable as is, so it's not a high priority. You can avoid deep ravines by having a clamp that ensures a minimum height for the centre, or using the islandising system in the previous pages. My generator lets me just add extra height maps, so it's no big deal for me. Following passes of erosion will wash silt into the newly carved canyons anyway, its a matter of what method is fastest.

Cycle through rain erosion, ocean erosion and river erosion. Each time the lush map, river map etc is recalculated. This gives a much better result as the river will shift as the terrain is altered. The flood algorithm takes a while the first time but gets faster for additional passes because theres a semi pathway. The path algorithm will speed up too as the stringizing will be better. Make sure to guess the node order for the pathing.

This system isn't too good at picking up little streamlets. Most rivers start at lakes. In phase 2 I will put a lot more work into rivers, as they are a pretty important part of a good terrain.


I know you're thinking, why didn't I stick with one formula like a flood algorithm that plots a path. Or why not use the iterative rainfall to plot the rivers path. All the ins and outs are too many to discuss here, but some algorithms I liked were too slow and others used too many resources. By breaking the process into stages which all work on a map in order, I can modularize each step. Thats a big plus because some of the algorithms are pretty messy.

Don't worry too much if you're pathing and flooding isn't quite right. At the end of the day it doesn't matter too much because the landscape is self perpetuating. What I mean is if you bulldoze a river where one didn't need to be, another cycle of erosion will utilize it anyway. If you don't require the final terrain to look anything like the original then it doesn't really matter.

Next: Phase 2

Email for questions. Please don't ask me for source code, but I may do pseudo code for sections if there's interest.