Where should I start? There are many, many approaches to procedurally generating terrain. Terrain generation is the classic introductory exercise into procedural generation, or as it is sometimes called, “Hello, Perlin.” It is straightforward (the simpler algorithms, at least), and the visual results are easy to assess. Thus it’s been used in everything from fantasy map generators to AAA first-person games (most games with large worlds use some procedural generation to make the terrain varied and realistic-looking). To discern which previous terrain generators are useful to this project, I need to state goals.
Goals and Constraints
First, I’m creating a world. I’m not texturing a mountain, or generating a mountain range. I’m creating an entire world. I want continents, oceans, and noticeably varied biomes in different regions.
Second, I’m going to apply a rule of “try to find the simplest yet lowest level system to model to get the most emergent-behavior bang for your development-time buck.” Hm. I’m going to have to shorten that rule. Let’s just call it Rule #2 for now.
Third, the world is cylindrical.
Why not spherical? It’s too hard. See Rule #2.
Why not rectangular? It’s not very difficult to wrap around on one axis, and almost all the math is the same for rectangular and cylindrical. I enjoy the wraparound in Civ maps and hopefully a cylindrical map will engender a little more believability into the world, as well as some interesting tactics when we get Civ-style play involved. I think this tradeoff allows cylindricality to pass Rule #2.
Fourth, I want usable customizability. It’s not enough to guarantee a different world for every seed: I want to be able to control different aspects of the world generation so I can create Earth-like worlds, water worlds, desert worlds, tropical worlds, mountainous worlds, and so on. Ideally, this rule coincides with (some) scientific rigor. I’ll explain this more below.
One common approach is to use Perlin or simplex noise to generate heightmaps. Here is an example from Amit Patel’s blog.
I find these heightmaps too uniformly noisy; they are a little too random to seem believable. Only a few mountain ranges and archipelagoes look like pure noise. Most of the world is less noisy than the example above.
One way to combat this noise uniformity is to use other noise functions to assign biomes which dictate how rugged the terrain is in a given region. In other words, a secondary regional noise function determines how strongly the main terrain noise function is applied in different areas.
This approach can be further extended by layering multiple noise functions with slightly different shapes and purposes. Tutorial 5 for the libnoise library is an example of this approach.
While this approach is guaranteed to eventually evolve into the exact terrain generator you want, at that point, with a dozen or so noise functions each with 6 or 7 parameters, you’re looking at over a hundred arbitrary input settings you’re using to create terrain. This clashes with our goal of usable customizability. If possible, I’d rather have a couple of noise functions combined with a lot of pseudo-scientific parameters, like maximum mountain height and the prevalence of water on the planet. That means, instead of using the noise functions to directly generate the terrain elevations, I need to go one level deeper and create some sort of system that takes in my customization parameters along with a few noise functions and generates the elevation maps.
With Rule #2 in mind, tectonic plates seem like the clear starting place. Let’s check them out.