The problem of triangle density with tiled landscape rendering is solved by using progressively coarse meshes for more distant tiles, like this;
Progressively less triangles are used for distant landscape meshes. Using Imposters we can also regulate the rendering impact of distant 3D objects like trees and other features. Ultimately though we are still going to run out of triangles – we either make the decision to fade out distant objects (either by alpha fading or pixel clipping based on distance from camera) or come up with a better idea.
Distant objects in the landscape are essentially 2D – unless they are unusually tall they can safely be rendered as side-on billboards, or at their most distant, hinted at by rendering them as horizontal splats onto a landscape. A forest of tress looks largely flat when there is only 2 pixels per tree.
Again though we reach a problem of simple volumes – imposters are cheap and horizontal billboards even cheaper – but they don’t cost nothing. If you have 5 million trees, how to get even a reasonable approximation of their impact on the landscape without rendering each one individually ?
Additionally there is the problem of fine detail visible at a distance, especially linear features like roads and rivers which you just can’t fade away and you can’t render effectively on top of a landscape without excessive costs.
My solution is to provide distant tiles with three textures;
- A heightmap for rendering their meshes
- A normal map so I can portray light variations irrespective of the number of triangles rendered.
- A drape.
The Normal Map is common practise and gives much better results on low poly tiles than passing in the normal as part of the mesh.
The Drape is the interesting bit.
When composing a multi-textured tile at close range I use texture weightings passed as part of a Planting Map texture, sample the Planting Map and apply a weighting to the 8 ground coverage textures applied to that tile.
But this is expensive – I need to sample 9 textures for every pixel (one planting map, then all 8 coverage textures at various weightings). The trick is that within my landscape construction pipeline I render every tile at close range (to get the full detail) and simply capture the graphics device output and save as a Texture.
For distant tiles now I need to pass in only the three textures, Heightmap, Normal Map and Drape. The Drape is the image of the fully rendered tile taken during the pipeline phase. I now only have to sample my Drape per pixel to get a fairly well scaled image of what I will see when I get close-up to the tile and I render it using the Planting Map. I can tune the size of this drape texture to give more or less detail.
This also neatly solves the problem of roads and rivers. I can throw quite a lot of technical rendering goodies at them when they are close-up, and simply allow the pipeline Drape generation to take a ‘photograph’ of what it looks like.
In the screen shot above the road doesn’t lose detail as it goes off in the distance, but its only really being rendered in the bottom half of the image – in the top half its just part of the Drape image for that tile.
The effect isn’t quite as good with trees where the screen shot naturally takes them from above, but we have the advantage there of using billboards out to a reasonable distance, and letting the Drape give a visual suggestion of the tree cover at long distance. This method neatly allows fields and other horizontal landmarks to be rendered out to long distances without any further processing – in fact; the more detail you have in an individual tile the better the results.
In the sample above we have distant forests (work-in-progress) and a road leading off into the distance. All these tiles are rendered using Drapes – they have only a few triangles each.