Larry Gritz described at SIGGRAPH 2002 ``A Recipe for Texture Baking'' in course 16 called ``RenderMan in Production''. In the same course Hayden Landis, working for Industrial Light + Magic, described several ``occlusion'' passes in ``Production-Ready Global Illumination''. At that time PRMan didn't support global illumination (GI) and Landis basically showed how to fake certain effects of GI.
Today a lot of renderer do support GI but it might be still worth to invest some time to think about efficiency. The problem with GI is that most of the time you will end up with flickering in an animation because the solution might be slightly different from frame to frame.
The image in figure 20 shows the Chrysler Building rendered with a renderer called Lucille35. The renderer is in very early development but it allows you to render RIB files using geometry with only triangle polygons. Which means that you can't easily render RIB files from production yet but on the other side the examples coming with Lucille can be modified to render with other RenderMan compatible renderers and we can use them to test the techniques described at the SIGGRAPH course and compare rendering times, quality, etc. with the results from Lucille.
Even if the baking process takes quite a long time it might be worth to do it if you can reuse the baked information for a whole sequence. Larry Gritz' arguments why you might want to bake complex computations into texture maps were:
texture() calls. For
patterns that are truly dependent on only parametric (or
reference-space) position, and have no time-dependence at all, a
single baking can be reused over many shots. This means that it's
okay for the original computations to be absurdly expensive,
because that expense will be thinly spread across all frames, all
shots, for an entire production.
The process described in the SIGGRAPH paper was quite technical and
showed how to implement the baking by writing ``DSO
Shadeops''36. The main reason for that
is that in the shading language of RenderMan you can't open files.
In mental ray this would be easy because the shading language is
using C or C++ anyway. I use this technique quite often to dump any
information needed later in a shader to a binary file, read the
information in the init phase of the shader, attach it to the
state as user data, and reuse the information in the main
shader.
In the meantime a lot of renderers support baking natively. For example SiTex Graphics offers a special version of their renderer AIR called BakeAIR for especially the purpose of baking and mental ray 3.0 supports ``light mapping'' for similar reasons.
Before I show a few examples how to bake information with BakeAIR I want to go back to the example I mentioned earlier. In the part called ``Production-Ready Global Illumination'' of the SIGGRAPH course the author talks about both HDR37 images and ambient occlusion.
I just took the example coming with Lucille and changed the
RIB file a bit to use it with a renderer called
3Delight38. With
3Delight there comes an example how to use HDR images and I just
added the commands necessary to use a light probe as an environment
map and to add some ambient occlusion to the result. It makes a big
difference to the picture you would get with just the
defaultsurface shader. And it's rendered with just
one pass.
The steps necessary are quite simple. First I removed all
Surface lines, the AreaLightSource and all lines the
renderer was complaining about from the original RIB file. This
allows me to render without any lights using the
defaultsurface shader. Then I added the following lines for
3Delight:
Attribute "visibility" "transmission" "opaque"
LightSource "envlight" 3 "float samples" 32
"string envmap" "grace_probe.tdl"
"float Kenv" .5 "float Kocc" 0.5
Surface "matte" "float Kd" 0.5
Objects contributing to occlusion have to be tagged as visible to
transmission rays. This is done by the first line. The ambient
occlusion is calculated by the light shader envlight. Have a
look at the implementation of the shader. The same shader takes the
HDR image, which was downloaded from
http://www.debevec.org/Probes and converted to a texture, as an
environment map to light the scene purely based on that image.
AIR has a very similar shader with the same name but
different parameters. I didn't try the HDR image with AIR but I
checked the ambient occlusion with the following line39:
LightSource "envlight" 3 "float occlusionsamples" 32
Unfortunately we can't use this example easily to demonstrate baking with BakeAIR because polygons and subdivision surfaces lack a natural coordinate system for 2D textures. If the model would have been made of NURBS it would be easier to bake the ambient occlusion. Nevertheless ambient occlusion can be used with polygons without baking it and there are examples coming with BakeAIR which demonstrate how to bake with NURBS surfaces. An interesting example how to bake displacements can be found online at the following two addresses:
http://www.drone.org/tutorials/displacement_maps_air.html http://www.seanomlor.com/owenr
The idea is to use a low-res version of a subdivision surface and measure the distance to a high-res version. Once that information is baked you can render the low-res version and use the baked information to displace it back to the original high-res version. But why would you like to do that? Well, this way you can use arbitrary shapes and morph them into each other by animating the displacement over time.
Let's have a look at one of the examples where you bake the normals
and positions of a face and use them later to place hairs over the
whole face. Figure 22 shows the resulting image for
baking the normals on the left, and for baking the positions on the
right. First you have to define for a each texture you want to
create through the baking process a Display line:
Display "headP.tif" "file" "P" "quantize" [0 0 0 0] Display "headN.tif" "file" "N" "quantize" [0 0 0 0]
The next step is to either specify a camera which will produce a tessellation during the rendering process which will be used for the baking or to explicitly control the tessellation with some additional commands:
Attribute "divide" "u" 64
Now you specified the tessellation and the filenames for the baking but you didn't say which geometry should be used. This is done by adding the following lines to the geomtry definition:
NuPatch ... "P" [ ... ] "constant string bakemap_P" "headP.tif" "constant string bakemap_N" "headN.tif"
Figure 22 shows the baked textures which are used to grow hair on the NURBS surface. Look at figure 23 for the result.
But how was the hair placed onto the head? AIR allows you
to write -- beside the five standard shader types mentioned earlier
-- shaders of two additional shader types: The
transformation and procedure shaders. In the RIB file
creating the image of figure 23 you will find at
the very end the following lines:
...
Surface "VHair" "color RootColor" [.03 .02 .01]
"color TipColor" [.6 .6 .2]
Procedure "growhair"
"float ns" 400
"float nt" 400
"string Pfile" "headP.tif"
"string Nfile" "headN.tif"
"float height" .3
"float width" .02
"float vary" .2
WorldEnd
FrameEnd
This attaches a surface shader called VHair with some
parameters to the geometry which will be created by a procedure
shader with the name growhair. The surface shader is coming
with the AIR distribution and the compiled version of the shader was
created from file which can be found in the $AIRHOME/vshaders
folder. All the file in this folder were created visually by using
VShade on Windows. See section 1 for a
screenshot of this program. Nevertheless the file is stored in a human
readable way and shouldn't be too different from standard shaders. The
source code for the other shader can be found in
$AIRHOME/bakeexamples/fuzz. Basically a procedure shader
uses ribprintf commands to create the lines for the RIB file
where the shader is called.