Around The World, Part 26: Biomes
I should be working on gameplay, but I got tired of looking at drab grey terrain, so I decided to beautify it first by adding some vegetation. In a way, this is in line with my plan to add a solid technical foundation for the game before stacking too much gameplay on top, because I’m not sure that the hardware will be able to render all those trees in a huge open world.
Let’s take a look at our starting point:
(That mountain village is placed a bit unrealistically, but I’ll tackle that later.)
You probably don’t remember from a post almost two years ago, but I already implemented generation of temperature, wind and precipitation patterns, and inferred the local climate from those. That was still in C# on a spherical world though, so I dutifully started porting it all to Rust on a flat world. In the end, I got my algorithms to produce a nice climate map using the Köppen-Geiger scheme, like before:
This map uses a common colour scheme, same as Wikipedia. Here’s the real world for reference:
Source: Wikimedia Commons, CC-BY 4.0
You can see that my attempt is far from perfect – in fact, it’s worse than what I got previously in my C# implementation. This is mostly because I simplified wind patterns, and I haven’t added noise to rain distribution yet either. But looking at the coasts (which is what the player will see), I think we’ve got good variety, which is the most important thing.
The next step was to map Köppen climate classes like “temperate oceanic climate” (Cfb) and “cold-summer Mediterranean climate” (Csc) to a set of trees and plants that could plausibly grow there. And that’s where the real trouble began.
To Köppen or not to Köppen
I had originally chosen the Köppen-Geiger scheme because, and I quote myself:
Köppen designed the system based on his experience as a botanist, so his classification is based on the vegetation we encounter in each climate class. That aligns perfectly with my goals.
So logically, these climate classes should cleanly map to particular biomes, right? I never checked this before, so I checked it now…
… and it’s false.
An awesome Wikipedia user has created the following map of the Earth’s biomes:
Source: Berkserker on Wikimedia Commons, CC-BY-SA 3.0
These are biomes I can work with; even if I don’t manage to find any data sources, names like “dry steppe and thorn forest” contain enough information to start drawing something plausible. So the question is: how does this compare to the Köppen map? Which Köppen climate zones map to which biomes?
Of course, being a programmer and map nerd, I wasn’t going to determine this by hand. So I figured out by trial and error that the above map was using the Robinson projection, used GDAL and QGIS to reproject the Köppen map into Robinson as well, aligned the two to the best of my abilities in GIMP, and then wrote some Python code to tally the corresponding pixels in each map. Note that the alignment isn’t perfect, so there will be some noise in the results, especially for Köppen zones that cover only a small part of the world. I’ll paste the full results here in case somebody has a use for it, but don’t bother reading the whole thing:
Af 89.0% tropical rainforest, 8.2% subtropical evergreen forest
Am 84.4% tropical rainforest, 6.3% grass savanna
Aw 29.0% dry forest and woodland savanna, 23.2% tropical rainforest, 23.0% tree savanna, 14.8% monsoon forests and mosaic, 5.7% grass savanna
As 100.0% monsoon forests and mosaic
BWh 44.1% xeric shrubland, 21.1% arid desert, 20.5% semiarid desert, 5.9% dry steppe and thorn forest
BWk 39.3% xeric shrubland, 25.3% dry steppe and thorn forest, 12.8% arid desert, 11.4% montane forests and grasslands, 5.5% semiarid desert
BSh 25.3% grass savanna, 22.8% tree savanna, 19.7% dry forest and woodland savanna, 17.9% dry steppe and thorn forest, 4.8% temperate steppe and savanna
BSk 57.8% temperate steppe and savanna, 10.2% dry steppe and thorn forest, 9.1% Mediterranean vegetation, 9.0% montane forests and grasslands, 6.3% xeric shrubland
Csa 63.9% Mediterranean vegetation, 14.5% temperate steppe and savanna, 11.8% temperate broadleaf forest
Csb 29.1% Mediterranean vegetation, 24.7% montane forests and grasslands, 24.1% temperate broadleaf forest, 9.2% dry steppe and thorn forest, 5.2% temperate steppe and savanna
Csc 38.5% Mediterranean vegetation, 30.8% temperate broadleaf forest, 30.8% montane forests and grasslands
Cwa 44.6% dry forest and woodland savanna, 19.4% temperate broadleaf forest, 14.1% monsoon forests and mosaic, 11.2% subtropical evergreen forest, 3.5% montane forests and grasslands
Cwb 32.3% montane forests and grasslands, 24.6% subtropical evergreen forest, 13.0% dry forest and woodland savanna, 12.2% temperate steppe and savanna, 8.8% tree savanna
Cwc no matches
Cfa 42.6% temperate broadleaf forest, 25.7% subtropical evergreen forest, 20.7% temperate steppe and savanna, 5.8% dry forest and woodland savanna
Cfb no matches
Cfc 62.5% taiga, 37.5% temperate broadleaf forest
Dsa 30.3% dry steppe and thorn forest, 29.8% montane forests and grasslands, 28.7% temperate broadleaf forest, 6.2% temperate steppe and savanna
Dsb 76.3% montane forests and grasslands, 13.5% dry steppe and thorn forest, 4.8% temperate steppe and savanna
Dsc 52.2% tundra, 36.0% taiga, 9.9% alpine tundra
Dsd 50.0% alpine tundra, 25.0% tundra, 25.0% taiga
Dwa 82.4% temperate broadleaf forest, 17.5% temperate steppe and savanna
Dwb 46.8% temperate broadleaf forest, 23.0% taiga, 16.3% temperate steppe and savanna, 13.7% montane forests and grasslands
Dwc 61.6% taiga, 17.9% alpine tundra, 15.4% montane forests and grasslands
Dwd 83.0% taiga, 16.0% alpine tundra
Dfa 55.2% temperate steppe and savanna, 44.7% temperate broadleaf forest
Dfb 46.3% temperate broadleaf forest, 44.1% taiga
Dfc 65.9% taiga, 29.3% tundra
Dfd 71.9% taiga, 26.1% tundra
ET 46.0% tundra, 44.8% montane forests and grasslands
EF 83.9% ice sheet and polar desert, 15.2% tundra
The thing that you should be looking at is the first percentage on each line. For example, Köppen class Af
is covered for 89% by tropical rainforest – fine, we can just always plant tropical rainforest there. But the majority of climate zones aren’t nearly so clear cut; for example, what to make of BSh
(hot semi-arid)? One quarter of it is covered by grass savanna, almost a quarter by tree savanna, and several other biome types as well.
At this point, I concluded that Köppen’s scheme did not fit my purposes as well as I had assumed, so I started looking at alternatives. And that’s when I was reminded of a blog post by the always extremely thorough World Building Pasta: Beyond the Köppen-Geiger Climate Classification System, Part I: Extensions and Alternatives. In it, Pasta describes several alternative climate classification systems with their pros and cons.
BIOME1
The system that caught my attention was the BIOME1 model by Prentice et al., 1992 (PDF). This model fits my purposes very well, because it directly talks about plant types and in which climates they might grow, and offers a very data-driven approach to find out. The core of the paper is this one table:
For example, this says that the plant type “cool-temperate conifer” can grow in areas where the minimum temperature is at least −19 °C, the maximum temperature does not exceed 5 °C, there are at least 900 growing degree-days in a year, and the α coefficient is at least 0.65. Let’s unpack this one by one.
Temperatures Tc and Tw are straightforward; Prentice et al. use the monthly average here, which I have readily available from my simulations.
Growing degree-days are also easy to compute, but might warrant some explanation. The idea is that plants do not grow below some particular temperature, here taken as 5 °C, and they grow faster the higher the temperature goes. So to approximate the total amount of growth in a year, for each day we take the number of degrees above the 5 °C threshold, and add those up across the days in a year. For example, a 21 °C day is good for 21 - 5 = 16 growing degree-days, and a 2 °C day doesn’t contribute any growing degree-days at all. Some plants can start growing above 0 °C already, which is what the GDD₀ column is for.
The Priestley-Taylor coefficient α is a bit more complicated to determine. Prentice et al. describe an iterative algorithm that models moisture storage in the soil, but I used a simpler approach: α = precipitation / PET
, where PET is the potential evapotransipiration computed using the outdated, but simple, Thornthwaite equation. I compute α separately for each month (assuming 10 in the case where PET is zero, because this empirically gave better results than 1), then take the average over the year.
Finally, there’s the column “D”, the dominance class. This is needed because, even if a plant type could technically grow in a particular climate, other plants are better adapted and will outcompete it. This is why, for example, we won’t see any conifers in tropical rainforest. The rule is: if any plant type with a particular dominance class can grow in a particular climate, all other types with higher-numbered dominance classes are excluded. Plants with the same dominance class can coexist though! This model is simple, straightforward, wrong, and oh so useful to me because it’s easy to implement and efficient to evaluate.
With the list of plant types in hand, the BIOME1 model also specifies how to map these to biomes:
So the biomes are computed from the plants that can grow, rather than the other way round. Since I only want to plop down some plants, you might wonder why I’d bother with biomes at all. There are two reasons: one, I’d like to plot these on a map so I can compare it to the paper; and two, I want to assign different colours and textures to the base terrain depending on the biome.
Here’s the output computed by Prentice et al. themselves:
And, using the same colour scheme, here’s mine:
Again, it’s far from perfect, but this is clearly because of my simplistic climate model and not because of my implementation of the BIOME1 model. Most importantly, all classes are represented here.
Now, not to repeat my previous mistake with the Köppen model, I checked beforehand whether I could find a list of specific plant species for each of these biomes. That more or less worked by patching together various sources, and validating using the amazing Map of Life whether their occurrence actually corresponds to that biome. In the end, I have a list of 2-3 distinct and characteristic species for each plant type, and since most biomes contain more than one plant type, this should give a decent impression of biodiversity on my world.
Colouring terrain
Actually modelling, placing and rendering those plants is for a future blog post, because this one is getting plenty long already. So I’ll tackle the terrain colours first. I manually assigned each biome a plausible colour, and then mapped it to the terrain using the above biome map:
It works exactly as designed! We’re looking at cool mixed forest (yellowish green), cool conifer forest (blueish green), tundra (yellowish) and ice/polar desert (white) here. This makes sense, because this island is situated at 56° north, and should have a climate comparable to the Hebrides off the coast of Scotland.
But maybe, just maybe, real biomes don’t have such straight and hard borders? Actual biomes blend into each other. Interpolating between biomes is tricky though, because they are discrete classes. I could instead interpolate the output colours, but I think it would look more natural to add some domain warping using simplex noise instead:
Better. Never mind that the snow line no longer corresponds properly to height; snow is something I’ll tackle later.
One cheap trick to make every terrain instantly look much more varied is to have nothing grow on steep slopes, so let’s expose grey rock underneath:
Finally, terrain near the waterline will not be overgrown, or at least not by the same type of plants, because of tides and spray from the salty sea. So let’s expose the bare rock there too:
The effect is subtle from this perspective, but it helps ground the terrain much better, and also makes the underwater bits less unnaturally green. (Underwater biomes and vegetation is something that should be handled separately, if needed.)
Notice how there’s not a single texture in sight. I’m not great at drawing textures, and I hate UV unwrapping, so I’m trying to get away with a mostly texture-free art style in this game. We’ll see more of that style when I finish modelling my arboretum.