Here is another one of my weekend projects I happened to work on way more than expected. The initial smaller goal was to upgrade the terrain generation for the HexTexMex project to have more variation in the map generation.

First I started with some random variation in terrain height, but I did not like this look and feel, at all.

The next best thing is Perlin noise. It is a function that takes x and y coordinates, and gives a height value back. The interesting detail is that close x and y values have similar height values, and you get a surface similar to a basketball.

To improve on this, you can layer multiple levels of perlin noise on top of each other. Every layer gets a different scale, eg 1x, 10x and 100x and the resulting height levels resemble natural terrain quite nicely.

The number of layers determines how far you can zoom out before you can spot repetition in the pattern. With my initial approach, every tile was a copy of a custom 3D hex object I modeled up in Blender. I set the origin of the model to its top surface. This means scaling the object in its vertical axis does not change the position of the top surface, but still makes the object larger. This comes in extremely handy if you like to position other 3D assets on top of your geometry since the surface position is always known.
Another neat trick to make terrain look more believable are thresholds, which e.g. result in every spot with a lower height value to become capped at that value and become water, and another threshold that defines that terrain above a certain height value will be covered with snow.

You can also use the slope of tiles e.g. to determine if they should become beach if the slope is flat and they are close to water, or rocky if the slope is high.
But overall, the underlying approach with individual tiles is bad for performance. A lot of geometry needs to be rendered that is impossible to be seen by the player and the game takes a big and unnecessary performance hit during runtime while rendering thousands of individual tile models. Since I wanted to create larger worlds nonetheless, I checked how to optimize my terrain generation and figured that the best course of action is generating a single mesh on the fly that contains all the tile geometry with the height data as well as their predefined terrain attributes to assign the correct material to the top surface.



This algorithm first renders the output of the perlin noise function in a 2d grid and then all the modifiers are applied, e.g. to cap valleys to the water level and turning nearby flat areas into beaches. The algorithm then uses this pre-generated data to calculate the position of every vertex and face that is visible to the outside and generates a watertight mesh. With this algorithm, the game was able to render terrains having 5x the amount of tiles.

If you need a custom algorithm to solve a new or improve on an existing problem, feel free to contact me using my email address.