Sunday, February 1, 2015

Terrain Generation Components

For my terrain generation code, there are many areas of interest -- here were the eight major questions I looked at:
  1. How do you define the size and shape of biomes?
  2. How do you define small, circular points of interest within a biome?
  3. How do you implement long, potentially twisting, linear features?
  4. How do you define (and save) geometry and scale?
  5. How do you define the surface?
  6. What about flora, both large (eg trees) and small (eg grass)?
  7. How do you define what's below the surface?
  8. What about water (and other fluids)?
My first goal was to find a good way to produce biome regions that were fairly large, while allowing some smaller-scale variation within a biome. For example, within a mountainous region, where are the peaks, ridges, and valleys? Will a forest have a pocket of unwooded grass (aka a meadow) within it? Can you place an oasis within the desert? For that, I settled on using a hex grid and subdividing it into a finer hex grid a couple times. Throw in a little noise and it makes for borders not too cubic, not too noisy (eg what you'd get from straight Perlin noise), and easy to subdivide.

So I'm using jittered, adjacent hexes to define the shape of biomes, and the hierarchy to define their size (question #1). The hierarchy also allows me to insert special features here and there (question #2). Right now I'm really only using this to add islands, but the tech is in place and I have an implementation for varying plains although not enough more engine tech to justify this.

But that just gives me the hexes I displayed in the previous post. Converting hexes to voxels requires defining the world surface (question #5), including its geometry (#4) and "scale". Scale is really a gameplay question, not a tech question; on the tech side, normally one cube will be one unit, so there you go.

One question I'm now facing is how to do linear features, such as mountain ridges, canyons, and rivers. I've also got to add grass, flowers, and trees (#6), usually done with billboarded quads for the small stuff and voxels for the larger stuff. Then there's the below-surface stuff (#7), if you plan on letting players dig into the ground -- this includes layers of rock; pools of lava; 'bedrock' or some other way of limiting how deep players dig; dungeons & caves; ore; and who knows what else. Finally, how do you 'do' water (question #8)?

The question I've dodged so far is linear features. This is really bugging me, because the approach I used to voxelize the hexes isn't amenable to adding linear features. Using noise functions for everything can produce interesting-looking terrain, but I want to take a more hands-on approach for some terrain elements, eg to use code to define where those ridges are and then proceed from there, rather than trying to cobble together some function that does it for me. I'm also trying to avoid using an iterative weathering or erosion process to do that. So, who knows.

For now, I'm proceeding to working on adding flora and finding better textures to use, as the debug texture I'm currently using has served its purpose and I'm now trying to make the engine look great. I've got a solid way to define & save geometry, so I'm comfortable punting the generation question for now and coming back to it later.

Thursday, November 13, 2014

Hex-Based Terrain Generation

I'm using hexes to do my terrain generation. I don't really need to use hexes, but I was thinking that it would provide more interesting borders than a strict square-grid algorithm would. The game world itself is voxels, hexes are just part of the generation algorithm.

Perhaps the simplest option would be just working in voxel space, such as what Minecraft does. MC uses quantized, interpolated, multi-dimensional fractal noise maps to define elevation and biome, for example. I see noise maps used in many different experimental terrain engines; it's a strong technique.

Another option is using Voronoi cells to define biome areas. Multiple adjacent cells could be joined together to provide large biome cells with interesting borders.

For the gameplay I want, however, a one-size-fits all approach would be hard to work. I'd like to play with borders between biomes, put unique cells in the middle of (eg) a forest biome, and some other stuff. Mostly, I came across a hierarchical algorithm and figured it could provide a lot of interesting options.

So let's take a look at that image. The first step of the algorithm is to define a 7-hex island surrounded by ocean. The blue hex is 'water', and the other three types are plains, forest, and mountain. The idea is that I can decide the layout of these biome types before I go in and pick a particular subtype of forest, such as pine / oak / blooming / autumn / ghostly / etc. That's what step 2 does: in this case, the water node is just converted to ocean (had it been in the center, it would have become a lake). The plains, mountains, and forest are actually converted to subtypes here, but you can't tell because the colors are the same -- I'll explore this more in later posts, but for now the think to note is the subsequent steps.

Step 3 takes the 5x5 grid of hexes and magnifies it to a 20x20 grid. The magnification isn't strictly 1:16, however; some sub-hexes are halfway within one parent and halfway within another, and I use a random-number generator to decide which one they take after. In this image, steps 1, 2, and 3 are all from the same seed, so you can see how the magnification process starts to break up the regular look of the first level.

The four images on the bottom-right are created from different island seeds, showing how a huge variety of island types and shapes are possible.

Not pictured: the algorithm proceeds further: step 4 is another cleanup step, step 5 is a second magnification step, then step 6 is cleanup again. Step 7 figures out elevations for everything, step 8 adds rainfall, lakes, & rivers, then step 9 converts the whole thing into voxels.