timetocode

A blog about game development and procedural content generation.

First time here? Try the graphical archive of all posts.

Feel free to email me or Tumblr ask | FAQ | Also on Twitter @bennettor

...querying twitch.tv... http://www.twitch.tv/timetocode

More erosion+river algo experiments

A larger erosion test. 1 pixel = 1 tile = ~ 2 sq ft. Looks like there could almost be some large rivers that reach from inland all the way to the ocean if I tune the maths.
You may recognize a tiny area in the top left corner from previous images.
The colors are still topography only — no actual representation of materials or vegetation yet.

A larger erosion test. 1 pixel = 1 tile = ~ 2 sq ft. Looks like there could almost be some large rivers that reach from inland all the way to the ocean if I tune the maths.

You may recognize a tiny area in the top left corner from previous images.

The colors are still topography only — no actual representation of materials or vegetation yet.

The erosion + rivers may be good enough for now.
I ended up going with one algo that simulates a unit of water landing on a tile and flowing downhill picking up dirt along the way. The dirt simply gets deleted after the water flows about 100 tiles. I would like to try a version of this algo that deposits the dirt, carving some areas but smoothing others.
This particular image was made in two passes from the same algo. The first pass involved 1000 units of water falling randomly, and set to very weak carving. I called this the “erosion pass,” and it changes the land quite a bit. I then recalculate all the slopes, so that future flows can take advantage of the new land features, such as the two large river deltas that formed. After that, I ran the same algo one more time, with 70 units of water set to a much stronger carving, which I call the “river pass.” The river pass is marked in a darker blue.

The erosion + rivers may be good enough for now.

I ended up going with one algo that simulates a unit of water landing on a tile and flowing downhill picking up dirt along the way. The dirt simply gets deleted after the water flows about 100 tiles. I would like to try a version of this algo that deposits the dirt, carving some areas but smoothing others.

This particular image was made in two passes from the same algo. The first pass involved 1000 units of water falling randomly, and set to very weak carving. I called this the “erosion pass,” and it changes the land quite a bit. I then recalculate all the slopes, so that future flows can take advantage of the new land features, such as the two large river deltas that formed. After that, I ran the same algo one more time, with 70 units of water set to a much stronger carving, which I call the “river pass.” The river pass is marked in a darker blue.

Grayscale river-like carving by simulated water

Grayscale river-like carving by simulated water

More erosion / water flow algo progress

More erosion / water flow algo progress

First Image: 100 units of water were dropped randomly onto the landscape and allowed to ‘carve’ until they hit a low a point. It’s neither stream nor erosion, just a mathematical step in the right direction.

Second Image: 1000 units of water, restricted to to the top 3/4 of the scene.

For it to be [crude] erosion, I’d say it the water would need to deposit some of the soil it removes, perhaps dropping soil as the slope decreases, and/or filling in the destination where the water comes to rest before pretending to evaporate.

For it to be a river, I think I’d just want some random curving along the course (and I’ve had some excellent suggestions on how to implement these curves).

Even in the current stage I am enjoying the deformation of the heightmap, as well as the root-like branching.

In case anyone is interested in the process that generates the above, it’s a WIP but goes approximately like this:

generate a height map

generate a slope map;

slopeMap[x, y] = {
     x: heightMap[x+1, y] - heightMap[x-1,y],
     y: heightMap[x, y+1] - heightMap[x,y-1]
}
     

waterFlow(x, y):

  1. get the height at x,y aka heightMap[x,y]
  2. get the slope at x,y aka slopeMap[x,y]
  3. decide the magnitude of the erosion, so far I just use getVectorLength(slope), which basically means steeper areas get eroded more than flatter areas
  4. get the neighboring tiles to the n,s,e,w
  5. find the lowest elevation neighbor
  6. if that neighbor is lower than our current position, carve some soil out of our current position, and then waterFlow(neighbor.x, neighbor.y) aka continue recursively — if the lowest neighbor is no lower than our current position, just stop

Also, there needs to be a special check to make sure that water does not flow right back to where it just came from (which it WILL try to do, after all it just carved a hole where it was, and therefore this area is lower).

 

Playing with slope. Each blue mark represents the slope of a tile. The smaller the mark, the flatter the area. The marks are also aligned to point downhill.
I took these colors from a topographical map, though its still too crazy-looking to tell whats going on. You’ll have to take my word the top right of the image is a big mountain, and the lower left corner is the edge of the ocean, barely within the image. The weird patterns in blue appear because the slope vectors (blue marks) in the steep areas are long enough to overlap onto each other, making for a bit of an optical illusion.
I’m contemplating working these slopes into a river algo, or maybe even into erosion.
The game this generator would go into is only 2d, so I may abandon this approach unless it yields some nice land or rivers. I imagine this would be a nice approach in 3d though.

Playing with slope. Each blue mark represents the slope of a tile. The smaller the mark, the flatter the area. The marks are also aligned to point downhill.

I took these colors from a topographical map, though its still too crazy-looking to tell whats going on. You’ll have to take my word the top right of the image is a big mountain, and the lower left corner is the edge of the ocean, barely within the image. The weird patterns in blue appear because the slope vectors (blue marks) in the steep areas are long enough to overlap onto each other, making for a bit of an optical illusion.

I’m contemplating working these slopes into a river algo, or maybe even into erosion.

The game this generator would go into is only 2d, so I may abandon this approach unless it yields some nice land or rivers. I imagine this would be a nice approach in 3d though.

River flow v1
The lines (and eventual rivers) start at mountain tops and head downhill to the nearest dip. Each line then goes to the next nearest dip, and so on, until reaching sea level. The thickness of the lines represent the number of tributaries that merge together.
Ideally the next step is to introduce a bit of a random walk to the river paths and also carve down the topography where the river flows. If anyone has any suggestions on how to approach randomizing a path from A to B while still consistently arriving at B, I’m all ears. The course of the river will be expressed in tiles, probably without diagonals, so any sort of fancy lines (quadratic, bezier, etc) would need rasterized.
In the above image, each peak above a certain elevation generates exactly one river, and the flow direction is always towards the nearest valley — varying all of these factors could be interesting. It would also be nice to carve out river beds and then leave them dry in some scenarios.

River flow v1

The lines (and eventual rivers) start at mountain tops and head downhill to the nearest dip. Each line then goes to the next nearest dip, and so on, until reaching sea level. The thickness of the lines represent the number of tributaries that merge together.

Ideally the next step is to introduce a bit of a random walk to the river paths and also carve down the topography where the river flows. If anyone has any suggestions on how to approach randomizing a path from A to B while still consistently arriving at B, I’m all ears. The course of the river will be expressed in tiles, probably without diagonals, so any sort of fancy lines (quadratic, bezier, etc) would need rasterized.

In the above image, each peak above a certain elevation generates exactly one river, and the flow direction is always towards the nearest valley — varying all of these factors could be interesting. It would also be nice to carve out river beds and then leave them dry in some scenarios.

Testing out a peak + valley detection algo. Red dots represent ground which is higher than the other ground around it, with the size of the dot being keyed to the total elevation. In this case the large red dots tag mountain peaks, while the smaller red dots mark hills or smaller bumps in the land. There are even a few tiny red dots for relative high spots on the ocean floor. Conversely, the blue dots mark relative low spots in the land, be it the low points along an ocean floor or just dips in the land.
My goal is to see if drawing squiggly lines from high points to low points will produce decent rivers or not.

Testing out a peak + valley detection algo. Red dots represent ground which is higher than the other ground around it, with the size of the dot being keyed to the total elevation. In this case the large red dots tag mountain peaks, while the smaller red dots mark hills or smaller bumps in the land. There are even a few tiny red dots for relative high spots on the ocean floor. Conversely, the blue dots mark relative low spots in the land, be it the low points along an ocean floor or just dips in the land.

My goal is to see if drawing squiggly lines from high points to low points will produce decent rivers or not.