Procedural Terrain Generation
Aug 13, 2023
3 minute read

Creating 2D terrain using simplex noise

Noise

Let’s start out with noise. You’ve probably seen noise on your tv, when you’ve tuned to a channel that doesn’t have a signal.

This sort of noise isn’t great for creating organic visuals. We need something that’s random in its vectors over time, but not random from data point to data point. Sort of like the gentle rise and fall of a stock price over many years.

To generate natural looking rises and dips, we need to use a specialized random noise generator. The cannonical implementation is Perlin noise, but a more recent version is called simplex noise. Simplex noise has a copyright, so we’ll use opensimplex noise to generate our numbers.

Generating Islands

Heightmaps

A heightmap is a black and white 2d version of your terrain, where each pixel is a gray scale value. 0 is black, white is 1, and all shades of grey in between. The value at each pixel represents your terrains height.

heightmap A picture of a black and white heightmap, used as the source of random noise for the terrain.

Island Mask

If we want islands, we need to remove the edges of our terrain. We’ll generate a radial gradient which starts at 0 in the center and scales to 1 on the perimeter.

island border mask A picture of a gradient fading from white to black from the outside towards the center.

To remove the border, simply subtract each island mask pixel value from the elevation in your heightmap. Prevent negative heights by limiting the min value to 0.

heightmap final A picture of the original heightmap, but with edges scaled to 0 by subtracting the island mask gradient from the original heightmap.

Colorize elevations

Now we can apply colors for each elevation value. As an example, we could say any elevation < .2 we’ll turn a shade of blue for water. Elevations from .2 to .4 will be forests, and thus we’ll make it green.

terrain A picture of the heightmap, colorized accoriding to elevations, showing blue oceans, green forests and brown mountains.

This is looking pretty good, but the elevations are a bit predictable, and there’s not really any interesting details once you get above the water elevation. Let’s fix that by adding in the concept of a biome.

Add biomes/moisture

First, let’s generate another heightmap, but with a little bit more detail. We can tweak the simplex noise inputs, and octaves to get more or less details and diffusion.

moisture Another heightmap with more details to be user as the biome.

Now we can apply this moisture/biome heightmap to the elevation heightmap. How you apply it is up to you, but I’ve found it gives the best results when you figure out a way to blend the elevation and moisture maps together, so you get a little bit of color variation without completely destroying the effect of rising elevation.

terrain-moisture Terrain now with moisture added.

Here’s a side-by-side view with and without moisture.

terrain-comparison showing the colorized terrain with and without moisture applied side by side.

Resources

These are some links that I found useful in coming up with these procedural generated islands.