Previously in this series:
This time we'll look at how the terrain height data is stored and processed!
Trigger Rally’s primary source of terrain height data, forming the overall shape of the mountains, is real satellite data from the Engelberg region of the Swiss Alps. A big thank you to Jonathan de Ferranti of viewfinderpanoramas.org for permission to use his Digital Elevation Map collection!
I wrote a tool to convert the data into a tileable 1024x1024 16 bit image. The low 8 bits are stored in the red channel and the high 8 bits in the green. Here it is, with the green channel amplified for illustration:
At load time, the game transforms this into a single channel 32 bit float texture. It then draws the racing track spline (which is different for each track) onto this image.
The height data is sampled in arc seconds, which corresponds to about 21m by 30m at Alpine latitudes. I’ve scaled down the mountains in the game by a factor of about 3, so each pixel of the primary height map is 7.5m by 10.8m.
This resolution is fine for the mountains and just about enough for the track, but it’s not enough to be smooth to drive on, nor is it visually interesting in the foreground.
Keeping it smooth
The first thing to do is smoothly interpolate the height map. Linear filtering is usually smooth enough for images, but for geometry we really need higher order continuity. There are various options here, but I went with Catmull-Rom interpolation.
So far we have something like this:
Adding more detail
Now we need to add some higher-resolution detail to make the terrain more interesting and plausible. For this I use a 512x512 8 bit map with height in the blue channel, and height derivatives in red and green:
Sampling this detail map at 1 pixel per vertex at the highest terrain resolution and adding it to the primary height makes things look a whole lot better:
The detail map is modulated by the terrain gradient and by proximity to the track spline. This makes steep areas bumpier, and valleys smoother. It also keeps the track (where you have to drive!) nice and smooth, although this is configurable per track spline segment in the editor.
The shaders need some extra information about the terrain, which I store in a "surface" map:
- R: d(height)/dx
- G: d(height)/dy
- B: surface type (dirt or grass/rock)
- A: detail multiplier (determined by gradient and track proximity)
Tune in next time
In the next post I’ll show you how the surface shading works. If you can't wait, you can peek at the GLSL shaders in all their messy glory here on GitHub!