Generating Terrain with Noise

It occurred to me recently that it was time to improve the terrain/world generation in Eden. Up to this point, believe it or not, I was getting by with some homemade algorithms that created enough variety early on in development to be useful. Now however, as the game is maturing, I needed more realistic looking terrain and structure.

Perlin NoiseFrom past projects, experimentation and research I new the quickest and most elegant solution would involve the use of noise generation to produce height maps. The first obvious choice was to try out Perlin Noise (thank you Ken!). This is an algorithm that I won’t even try to deconstruct, but the short of it is that it generates a floating-point value between some defined range at a specific location (x, y) in space, which is typically used to represent height but can really be used for whatever the designer/programmer wants. The key to it is that all points the noise is calculated for are associated with one another, they don’t exist in a vacuum. Perlin Noise is great for producing gradients for whatever purpose desired; in this case terrain generation and specifically height or depth of the terrain.

Example of Heightmap Generated via Noise Algorithm

Simplex Noise
However the major issue with Perlin Noise is that it produces artifacts along directions of the geometry, you play with it long enough and it’s noticeable. So the improvement to that issue was dubbed Simplex Noise (thanks again Ken!). Simplex Noise enhances Perlin Noise by being faster to compute, scales up as needed (x or x,y or x,y,z, etc.) and doesn’t produce the visual artifacts, among other advantages.Here I ran into the issue of it having a patent (understandable Ken!) and I’m not mathematically strong enough to begin to write this stuff myself, so I looked around and learned about OpenSimplex Noise, which is different in it’s implementation from Ken’s Simplex Noise as to not infringe on the patent. After additional research and testing I decided upon integrating Simplex Noise in C# by Kurt Spencer (Thank you Kurt!) into Eden.

Procedural Terrain Generation via Noise
For reference, a lot of games and graphics applications make use of all kinds of noise algorithms. Notch himself explained in an old Minecraft blog article that he too originally made use of Perlin Noise in the generation of terrain and worlds within Minecraft albeit with customization and trade secrets (understandable Notch!). It’s also used in generating fractals, dynamic textures at run time, and I’m sure there are tons of other useful applications of generated noise.

Example of Terrain in Minecraft

So, what of it? We have an algorithm that generates noise given a point in space, how in the world do you turn a bunch of numbers into fancy looking terrain?! The truth is, it depends on what you are trying to accomplish. The main point is to make use of the value given the range of values that could be returned. Its up to you!

As an example, let’s imagine valid values that could come back are in the range of -1.0 ~ +1.0. A programmer could treat these values and map them to heights in their terrain generation, maybe +1.0 means the highest possible point in their world while -1.0 is the lowest. That could also be a shift, maybe anything below 0 is ignored but anything above 0 is used for height purposes, it’s really arbitrary and up to the programmer. The important thing to remember is that it’s producing smooth gradients in all locations calculated, so if a specific point is 1.0, then logically the points adjacent to that location are going to be a little less than 1.0 (most likely), and so-on, creating troughs and valleys. It’s up to the programmer to use this information as needed for their need, whether that’s creating a height map for physical terrain height, or applying textures at various world heights or depths (think of games where the higher the terrain goes, the textures change from green grass, to grey rocks, to white caps at their peaks for example).

If you’ve played Minecraft, you’re aware that while there is a world surface on which you might see hills and mountains, you can also come across caves, chasms and very deep labyrinthine underground networks of caves. In all likely hood, this is the result of a noise-like algorithm, I would suspect that to generate the worlds that Minecraft creates, it’s many different applications of noise for many different purposes, one application for the surface world, another for mountains, yet another to create empty space within the physical world (caves), generating the different biomes, veins of ore and the list likely goes on.

In my research I’ve come across more than a few folks talking about limitations of Perlin Noise and similar algorithms being that they don’t produce ‘cliffs’ and ‘overhangs’ (concave structures or non-gradient formations). While it’s true they don’t inherently create interesting concave structures, it’s a pretty misleading and uniformed statement and only serves to foolishly diminish the real power and value that these noise algorithms provide. As I stated, multiple applications of the same noise algorithm (multiple, different passes) can easily produce cliffs and caves and interesting concave geometry if it’s simply applied correctly. I can attest to this because I’m using such techniques in Eden to produce interesting cavern networks, mountain ranges, cliffs, overhangs and the like.

The last important thing to understand about noise algorithms is that since the data is all associated, you can affect the results uniformly (or not!) in ways that benefit your intended purpose. One such way is to work in a resolution factor. By modifying the information you input into the noise function, you will affect the resolution of the data that comes out. By dividing the values input into the function you are effectively giving it smaller values and thus increasing or decreasing the resolution of the information that comes out; think of this as zooming in or zooming out the resultant data that is output. I bring this up because if you are REALLY zoomed out (due to your numbers being input), you might not get the results you want or expect; you might get a lot of really small but extreme height values and think something is broken. Really all that is going on is you are probably feeding the function values that are too large or too small (depending on implementation). The solution? Just divide/multiply them by a resolution factor, play around with that number until you get something that produces what you want. You can further play with the inputs to generate all kinds of different outputs.