Procedural 2D Island Generation — Noise Functions

Travall
5 min readOct 26, 2018
Generated Island, featuring moisture based biomes.

As shown above, the last few days I’ve been playing with procedural generation, specifically using Simplex Noise to generate heightmaps for 2D islands.

Heightmaps are described, formally, as:

“ a raster image used mainly as Discrete Global Grid in secondary elevation modeling. Each pixel store values, such as surface elevation data, for display in 3D computer graphics.”

In summary, a heightmap is a map of values(often ranging from 0–1) which detail information such as elevation. Lower values relate to lower elevation, higher values relate to a higher elevation. Most heightmaps, whilst still in the format of lower and higher values, are represented in the form of greyscale imagery with lower values being represented as darker colours and higher values being represented as lighter colours.

Example of a heightmap visualizing Simplex Noise

Heightmaps, in one form or another, are a very popular way of generating terrain, be it 2D or 3D. As you can see from the example above, the lighter parts of the image could easily be mapped as steeper land, with the darker parts descending into water.

In combination with the heightmaps, which are ultimately just a means of holding and displaying information, we need a means to generate values for our heightmaps to hold. To generate these values, we utilise noise functions, specifically Simplex Noise in this example.

Simplex Noise, designed by Ken Perlin in 2001 to address the limitations of his classic noise function Perlin Noise, is a recent and widely accepted function used in all kinds of generation. The basic premise of both Simplex Noise and Perlin Noise is to combine multiple octaves of noise with differing frequencies and amplitudes to form a more natural and varied noise. The higher the octave count, the bigger each island will ultimately be.

Simplex Noise, composed of 6 octaves of Brownian noise.
Simplex Noise, composed of 7 octaves of Brownian noise.

Effectively, we are able to take coordinates(be them in 2D, 3D, 4D and so on..), supply them to the Simplex Noise function with a seed and get a 0–1 value we can use to create heightmaps.

We don’t need to know all the technicalities of how the Simplex Noise function generates the value when given coordinates and whilst the technicalities are beyond the scope of this article, you may find it interesting to look further into it.

We don’t need to know all the inner workings of Simplex Noise in order to use it(thankfully!), all we need to know is that it can take a coordinate and return a normalised value for use in whatever way we see fit.

For those of you interested in learning more about how Simplex Noise works, there’s an excellent paper on the topic of demystifying Simplex Noise by Stefan Gustavson of Linköping University — http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf

With those prerequisites out the way, we can get into the generation of the islands!

Firstly, we need to generate a heightmap with Simplex Noise. Our map is going to have a size of 2048 x 2048 pixels. In order to determine the number of octaves to sum, a decent approach often used is to find what power of 2 our resolution is. This number provides a scalable map with decently sized islands. 2048 as a power of 2 is 2¹¹ and thus we will sum 11 octaves.

Secondly, in order to vary our colouring later on we need to generate an additional heightmap of the exact same size — and thus the number of octaves, but with a different seed. This heightmap will be labelled as moisture and can be later used to determine biome placement.

The Island Heightmap.
The moisture Heightmap.

Now we have these two heightmaps, we can apply colouring based on the combined elevation and moisture levels. For example, any value on the island map above a certain elevation — a certain brightness — will be rendered as grassland, the shade of which we can determine by cross-referencing the moisture levels in the same area. This method of colouring by elevation and moisture is applied to each element, sand, stone, snow and so on.

Coloured map.
Side-by-side coloured island map and heightmap.

These look pretty good, but they spill out into the borders of the image which leaves the map feeling incomplete. For us to generate more whole, self contained islands, we need to degrade the borders of the image.

In order to factor out the outermost edges of these maps, we generate a square gradient with darker values at the center, lightening as it reaches the edges.

Square gradient.

We can now take this square gradient and subtract it from our island heightmap, islands closer to the center will have less(or nothing) removed in comparison to the bordering islands, leaving us with the primary center islands and no split islands spilling off the image.

Altered heightmap.
Side-by-side altered island map with it’s removed borders.

We can now take this altered heightmap and colour it just as we did before. Here’s the final product.

Coloured altered island map.
Side-by-side altered, coloured island map and altered heightmap.

Just for fun we can also render the subtracted borders of our islands too, coloured and in heightmap form.

Subtracted borders of island map.
Side-by-side subtracted coloured island map and subtracted heightmap.

Thank you for reading :)

--

--