With the basic terrain representation finished, the next step is to render it of course, and it was decided something a little fancier than the red wireframe quads were required. The most important requirement of the terrain was that we didn’t want it to look like boxes. We had two solutions around this, either to scale our tree down to match our resolution – not a great idea – or to decide on a rendering method that would at least give the appearance of smooth terrain.
Whilst prototyping some early solutions I remembered a paper I had recently seen published by Valve, “Alpha-Tested Magnification For Vector Textures”, and decided this was definitely the path to follow. Essentially this boils down to having an edge represented as a gradient rather than a definite set of pixels, which allows a strict threshold value to be applied giving a sharp edge. Because the process takes advantage of hardware texture filtering, its a very cheap way to get a resolution-independant shape. This is a great benefit to the project as the camera will be allowed to pan and zoom all over the terrain.
Following the method detailed in the article, our terrain rendering can be broken down into a few simple steps:
- Render boolean terrain mask
- Produce distance field from mask texture
- Threshold mask texture to produce sharp edged terrain
This was a fairly inefficient process to do in real-time, as generating a distance field (particularly over several large empty areas) can be quite time consuming. Even though updates to this terrain data only occur periodically, it was still decided that a close approximation would have to do. A simple averaging blur seemed to do the trick quite nicely as the following series of images show:
By keeping the filter size down, the error in approximate to actual terrain distances is also kept small. Small enough for our purposes at least. With an actual distance field all pixels should be assigned a distance, even those not near an edge. This data turns out to be redundant for us however, as we always discard the data over a certain distance anyway. The only noticeable artifacts from this technique are produced during the interpolation. If the blur and quad sizes are not tweaked to work well together, then sometimes the smallest pieces of terrain can be lost. This can be eliminated however through proper setup and using an adaptive blur that shrinks around smaller objects.
In the above shot we can also see that the terrain is not a uniform colour, there are three distinct layers, and an additional pattern overlayed (Click on the image twice for a full-size version). The layers are created very simply by taking multiple threshold values and using the results to lookup the correct colour for that layer. This simple approach allows us to radically alter the style without having to change the code itself. The overlay pattern is simply factored into the threshold calculations and pushes the colouring back into another layer to add some variety to the overall scene.
On top of the basic mask, there is some noise integration to give a more earthy feel to the scene, as perfectly smooth edges look a bit strange and boring. This noise comes from a screen-space value created purely through experimentation and combining waves to find a nice “shape”. The below image shows a portion of the noise and how it then integrates into the layers (shown with each layer as a separate colour):
The general idea was to get a constant turbulence seen as the small diamonds, and then larger “veins” of earth that seem to clump together as they are exposed. It works quite nicely in practice as the next shot shows:
Again we can see the individual layers of terrain as separate colours, including the overlay texture. On the left shot, there is no noise, and the edges are very uniform, bland and generally look a bit odd. The center picture shows what happens when we introduce our noise. Ah, much better! The edges not only ripple and wave now, but we have varying thicknesses even between the layers. The right-hand image shows how this looks with a little colour added. Finally, this video shows the rendering adapt to real-time deformation, including some closeups of the noise generation near the end: