A look back at brick maps and radiance caches.
In this second retro RenderMan piece, befores & afters explores the kitchens of Pixar’s Ratatouille, released in 2007, via previously published RenderMan materials. Back then, having so many reflective surfaces was, Pixar describes, “a rendering nightmare waiting to happen.” The solution at the time, especially to get to a desired soft reflection look in an achievable time-frame was to employ brick maps, as you’ll read about below.
Why reflections were (are) hard
Like any well-stocked kitchen, the Gusteau’s Restaurant kitchen had knives, pots, pans, liquids, shiny counters – collectively hundreds of glossy, reflective surfaces that needed to inter-reflect.
Anyone who has ray traced reflections before knows that glossy, blurred reflections are expensive due to the number of sampling rays required to smoothly blur the ‘high-frequency’ details in reflections. Essentially, you are taking the full, high-resolution geometry then sampling it many times to make it appear LESS high-resolution (i.e. filtered or blurred).
Enter, brick maps.
How do brick maps fit into the equation? First, remember what a brick map is: a cache of data written into a multi-resolution 3d voxel structure (like a MIP mapped texture, but in 3d). If the arbitrary data you write into this 3d structure is surface illumination color (radiance), then you have a multi-resolution version of your shaded, lit object. For more information on brick maps, see brick map fundamentals
As the brick map generation requires a pre-pass, we first need to set up a reference camera. Remember that RenderMan culls everything off-screen, so if you have objects reflecting from outside your final camera, the reference camera needs to be pulled back to see them. Also remember that backface, and hidden, culling must be turned off in the radiance pre-pass. This is an obvious necessity, as first bounce reflections could easily find faces that are backfacing or hidden to the final render camera. This pre-pass creates a point cloud with radiance data, which is then processed into a brick map using the brickmake utility.
Tracing into the brick map
Once we have our brick map, we need to develop a shader that ray traces reflections. But, instead of evaluating the shader at the hit surface, it looks up our illumination data from the brick map. The construction of this shader is beyond the scope of this production example. But for someone conversant in RenderMan shader authoring, the details below should be enough to implement the technique.
So for our blurred reflection shader, we find the reflection direction and cast reflection rays along it using standard ray tracing techniques (SL’s gather construct). However, instead of evaluating the reflected object’s shader, we query the impact position and normal, as well as the length and direction of the ray. We use the point and normal to index into the brick map, using the ray info to calculate the filter width. For this a small bit of mathematics must be done [Shaw2007]. The equation looks like this:
Filter radius = sqrt(h*tan(theta)/s)
Where theta is the cone angle of the reflection, h is the hit distance projected onto the reflection vector and s is the number of tracing samples.
Together, this provides enough information for a blurred lookup into the brick map. The only thing to note about this technique is the need to multi-sample your ‘brick map’ rays (s in the equation above, your sample value in the gather call), if you have a large cone angle. This is because geometry edges need enough samples to blur them; the brick map blur only accounts for internal object and texture blurring. However, in practice, the number of samples required is significantly fewer than required for a full ray tracing solution.
When you render the radiance cache (a.k.a. the illumination brick map) it will include view dependent shading. So, depending on the location of your reference camera, the highlights in your reflection may, or may not, be an accurate approximation.
When setting up the reference camera you can align it to the predominant reflection direction to capture the majority of the view dependent shading. This ameliorates a bit of the highlight discrepancies; but, in general, most people fail to notice these minor discrepancies. For a complete discussion of the results including performance gains, see the original paper in Pixar’s library.