Now I’m over the excitement of my first GDC, time to mention one of the most interesting things I saw. This was a short poster session on improving impostor rendering in Fortnite by Ryan Brucks, who also covers the details on his accompanying blog post.
Although Ryan’s working in the other popular engine with a name beginning with ‘U’, the techniques are universal so I’ve started implementing them into my landscape engine.
Impostors are a level-of-detail technique that replaces distant objects with a flat camera-facing plane textured with an image of the original object. The impostor texture is actually an atlas containing several views of the object; the shader then switches between them to best match what the camera would be seeing if we were rendering the full 3D model.
They’re typically used for trees and other vegetation in landscape rendering, and in fact Unity’s own landscape system uses them for distant trees. From far enough away this can look good enough, but there’s always a trade-off between visual quality (how far away you can use the real 3D models) and performance. With several neat but not too expensive improvements, basic impostors can be made to look much better, allowing them to be used much closer to the camera. This is especially important for large landscapes where you want enough detail to fill out a decent vista without tanking frame rate.
Ceci n’est pas un Arbre
First up is an editor tool to actually generate the impostor.
The impostor image is actually a texture atlas made up of several images of the object captured at different angles, arranged in a regular grid. When rendering you choose the sub-image in the atlas that most closely matches the angle you’re looking at the billboard from. The neat thing here is the use of an Octahedral mapping to find that image. Briefly, it’s a way of transforming a 3D vector (in this case the normalized view direction to the impostor’s center) into a 2D UV coordinate in the texture atlas, without using any expensive trig functions. As I’m mostly interested in using this for trees, I’m currently implementing the hemi-octahedral version that only uses the upper half of the octahedron.
The editor tool calculates the correct capture locations and renders into the corresponding section of the atlas. Here are the capture locations for a 6×6 atlas, the frusta are coloured according to the view vector budged into RGB.
Finally here’s a quick turntable of the impostor, note the actual geometry is only two triangles. This shader is just doing the bare-minimum, picking the correct sub-image in the atlas for the view direction. Next up is adding the fancy improvements such as blending between multiple images to smooth out the transitions.