Over the past month I’ve continued looking into terrain generation for my next game. My previous attempts were using algorithms to generate a fully-formed terrain from scratch, but I wanted to see if I could come up with a way to simulate terrain generation over time. I’m envisioning that the player will be able to change the terrain dynamically, so I want to be able to evolve the terrain as the player interacts with it.
I started with a basic heightmap where every location of the terrain has been assigned an elevation. Using lava flows as real-world inspiration, I added a variable for each location’s temperature and designated some cells to be heat emitters. At every step of the simulation, these emitters will add heat to their map location, which can be transferred to neighboring cells. Over time, the temperature increase will spread across the height map. I also added some rules that govern how heat is lost – for example, due to dissipation as heat is transmitted across the map. Whenever this happens, the location’s elevation is raised similar to what happens when a lava flow cools down and comes to a rest.
My first implementation of this simulation algorithm was done in 1 dimension, where each position on the x axis represents a cell. Using each cell’s elevation information on the y axis, this can then be visualized in 2D:
The red columns are emitters, and the colors of the other columns are determined by their temperatures whenever the elevation was raised. As the difference between the elevation of any two neighboring cells increases, so does the amount of heat that can be transferred. This prototype allowed me to fine-tune parameters like how much heat is produced by each emitter or how much heat is lost each turn to generate a mountain landscape.
I decided to make the simulation a little more interesting by adding a variable to represent a cell’s level of vegetation. In the game, this will likely translate into grass / trees growing at a location. To that end, I added rules to increase the vegetation level whenever a cell is fully cooled down and to reset it once a cell heats up. The next screenshot shows vegetation in green at the crest of the mountains:
Once I was happy with the results from the simulation in one dimension, I moved on to implementing it in 2D. The main change was that instead of heat being transferred to the two neighboring cells on the left and right, I now had to consider up to eight neighbors. The full 2D version is a little more difficult to visualize in a single picture, so here is just the temperature and vegetation rendered in red and green, respectively:
In addition, the map also stores the elevation data, shown in blue in the following image:
Following this, I used the information stored in the map to render the 3-dimensional terrain. In order to do so, I had to upload the map to a texture on the GPU to be able to read it in the vertex shader. (Side note: I spent some time trying to re-implement the simulation algorithm directly in the shader to avoid this upload step, but then realized that I would need to access information from the elevation map for game logic which would require me to copy it back from the GPU anyway.)
Here is an accelerated animation showing the terrain growing over time:
I will continue work on the algorithm as I’m not 100% satisfied with the shape of the terrain yet. The islands end up a little too round and there are few valleys or flat areas, but I think that can be remedied by tweaking the algorithm further. Specifically, I’m considering adding another variable that models the amount of dirt at a given location. Using that, the simulation could include erosion processes that level differences between neighboring cells without the need heat transmission. Stay tuned for more.