Daily #10: Billboarding

I decided to take a break from Maya today to focus on a technique I’ve wanted to try my hand at for a while now. Billboarding involves rendering a 2D sprite in a 3D environment such that it always points at the camera. The benefit of this technique is that many low-poly pieces of geometry (usually a quad) can be used to simulate highly detailed 3D geometry. Of course the effect is best used for object far from the camera (ex. trees and foliage in the distance), or when performance is critical, unless the stylized look is part of the game. You can spot it in early console titles like Mario Kart 64 where the players’ sprites jump between different versions depending on the orientation of the camera.

In the real-time graphics world, the vertex shader transforms the billboard’s (quad’s) origin into in camera space and then positions the vertices relative to it in the camera’s X-Y plane. This ensures the billboard always faces the camera. In ray-tracing, the same thing can be done at render time through a displacement shader, or each billboard can be transformed or rotated to face the camera prior to rendering.

I wanted to generate a grassy hill using this technique by billboarding my grass texture, with it’s corresponding alpha map, across quads instanced at points scattered over my terrain geometry.

Grass texture

I ended up going with the precomputed orientation route by transforming each billboard in Vex ahead of time before rendering. I tried the displacement shader approach as well, but it prevented me from being able to preview it in real-time in the viewport. Using Vex’s ptransform function I was able to easily compute the billboard’s origin in camera space, position each vertex relative to that, and then transform the whole thing back to object space. Of course, you could use lookat instead to rotate each primitive (quad) accordingly, with the added benefit that parented transforms would be inherited correctly. Either way, copying this to a few thousand points scattered over the geometry looked something like this:

Houdini viewport

In the end the render worked out OK, although my rough grass texture came out a bit too sharp and chunky for my liking:

Result

I’d like to retry it with a wispier texture to give that soft field look. I’m also interested in exploring optimizations for this approach such as only drawing billboards that can be seen. I’m sure I’ll revisit this soon as I want to play with a real-time implementation of the same technique.

Updated: