Procedural River Generation

 from Red Blob Games
DRAFT
22 May 2025

There are many guides on procedural terrain generation, including my own, but not as many about procedural river generation. On this page I’ll describe the techniques I’ve used, and link to other approaches.

 1  River properties#

These are properties I might want to model in my procedural river generators:

However, I usually implement only gravity and tributaries.

Water entering a region (via precipitation, springs, or rivers) must exit through rivers, evaporation, groundwater, or vegetation. [this is only mapgen4]

 2  Structure#

Let’s start with the main data structures. I’ll first show a square grid and then later others.

Each node is one grid tile. I place the dot in the center of the tiles:

Grid of points

Each edge links two nodes together. On a square grid, I have a choice of allowing movement only in the 4 cardinal directions:

Grid of points connected by 4-way edges

or allowing movement in 8 directions, including 4 diagonals:

Grid of points connected by 8-way edges

 3  Water flow#

Water flows downhill. To calculate water flow we need to figure out what’s “downhill”. Let’s start with some elevation. In this map, the west side is mountains and the east side is ocean:

Elevation map

At any place that’s not underwater, we can ask: what direction would a raindrop flow in?

We can check the neighbors of the tile to see which one has the lowest elevation, if any. That’s the direction the raindrop will flow.

Many inputs, but only one output

Calculating this for all nodes gives us a flow map:

Flow map

A river will follow that flow map. Here’s an example of a river that flows into the ocean:

Single river flowing east

Since every node has at most one outflow direction, rivers can join (tributaries) but they can never split (distributaries). Here’s an example of two rivers joining together:

Two springs create rivers that join

 4  Rivers#

In this model, water flows from every location downhill to the ocean:

All rivers

But that’s too many rivers. Instead, we could start rivers at only some of the points, and let them flow as far as possible:

Some rivers:

That’s what I did in mapgen2[1]. I picked random source points (preferring higher elevations) and let rivers flow from those points only.

In mapgen4[2] I picked the rivers differently. I calculated rainfall at every point, and then drew only the larger rivers.

[TODO: need better elevation map to get fewer grid artifacts]

 5  Grids#

Grid artifacts
Non-grid structure

 6  Local minima#

 6.1 Ignore

 6.2 Lake

 6.3 Fill

 6.4 Carve

 7  Examples#

 7.1 Square

show how it looks on a dense map

 7.2 Hexagons

 7.3 Irregular grid

One problem with regular grids is the rivers may look too regular. This is partly a problem with the input elevation map. But we can reduce the regularity by using a different graph for the rivers than we do for the map itself. For example, the map might be a square grid, but the rivers might be computed on a subset of grid points, connected together into a Delaunay triangulation.

To ensure that the river flow makes sense, we will also need to assign elevations on the triangle mesh, and then interpolate those back to the square grid.

{ need to show what this looks like }

{I guess I’ll have to calculate triangle centers if I want to draw the tiles…}

 8  More features#

 8.1 Infinite map

I think of rivers as a global feature. The amount of water flowing through the Nile in Egypt depends on the rainfall far away in Ethiopia. That means to generate Egypt correctly we need to generate faraway lands, not only Ethiopia to find the water that does come from there, but also potentially farther away, to make sure there’s something blocking water so that it does not come from there.

I think we have to loosen our requirements to get rivers on an infinite map. Every project will have its own tradeoffs.

 9  Other approaches#

Are we trying to create a set of good rivers, or a good set of rivers? These two are a little different. Creating a good set, we might want things like:

 10  References#