Short Contents

7.6 Baking

"Baking" is the pre-computation of a costly shading operator into a texture map or a point cloud so that it can be reused in more than one render using efficient texture lookups. Baking is generally desirable for costly ray tracing effects such as ambient occlusion and indirect illumination (see section Global Illumination). Before considering the baking approach one should be aware that:

That being said, baking is widely used in production and could result in important rendering speedups.
Before baking, one must make sure to disable 3Delight's hidden surface removal in order to include, in the bake file, informations that are invisible in a normal render. Visibility culling, as well as backface culling (when RiSides is set to `1'), can be disabled using the following RIB snippet:

Attribute "cull" "hidden" [0]
Attribute "cull" "backfacing" [0]

These two attributes should be set for all primitives for which baking is desired (see Primitives Visibility and Ray Tracing Attributes). Additionally, it is good to disable the view dependant dicing so that micro-polygons on object's silouettes are properly formed:

Attribute "dice" "rasterorient" [0]
NOTE

Culling and dicing attributes could have a severe impact on performance, they should not be used in beauty (main) renders.

7.6.1 2D Baking

2D baking is the operation of storing some function into a standard texture map. This is possible when the underlying model has a suitable parametrisation, which is often the case since one needs a proper parametrisation to use texture mapping. The following example code saves the ambient occlusion into a 2D texture map using the bake() shadeop (see bake shadeop):

float occ = occlusion( P, N );

if( is_baking == 1.0 )
{
    /* Bake occlusion into a file */
    bake( "occ.bake", s, t, occ );
}
Listing 7.9: Occlusion baking using the bake() shadeop.

The created `.bake' is a collection of 2D points and their associated data and is not suitable for later texture lookups. To convert it into a mip-mapped texture that can be read back using the texture() shadeop one could use tdlmake (see section Using the Texture Optimizer - tdlmake):

tdlmake -bakeres 2048  occ.bake occ.tdl

Another way to achieve the same effect is to call RiMakeTexture from inside the RIB file (or programmatically from inside a C program):

MakeTexture "occ.bake" "occ.tdl" "clamp" "clamp"
    "sinc" 8 8 "int bakeres" 2048

An example of the entire process is illustrated in the setup found in the `$DELIGHT/examples/baking' directory.

7.6.2 3D Baking

When no suitable and continuous two dimensional parametrisation exists for some piece of geometry, 2D baking becomes tedious or non-feasible. One parametrisation that is always available is the 3D space in which primitives are defined: this gives us the option to save the data in a 3D point cloud file using the bake3d() shadeop (see bake3d shadeop):

    ...
    bake3d( "occ.ptc", "", P, N, "surface_color", Ci );
    ...

The saved values can be read back using the texture3d() call (see texture3d shadeop):

    ...
    color res =0;
    texture3d( "occ.ptc", P, N, "surface_color", res );
    ...

The interface to the bake3d() shadeop is richer than the one for bake() shadeop as it is possible to specify more than one data channel per 3D point, among other things.

NOTE

Point cloud files created with the bake3d() shadeop can be viewed using the ptcview utility.

Implementation Details

In contrast with other implementations, 3Delight's point cloud files can be loaded partially in memory and efficiently accessed using a caching mechanism, similar to renderer's 2D texture caching system. This is important since point clouds can become quite large. Additionally, point clouds can be read anytime during their creation: a shader that issues a bake3d() call can also call texture3d() on the same file. In other words, a point cloud file is always in a readable state.

7.6.3 Brick Maps

Point cloud files are stored in a sparse data structure that is not suited for filtered lookups. This means that accessing point cloud files could result in aliasing. The solution is to convert the point cloud file into a mip-mapped 3D texture, similarly to the 2D textures produced by tdlmake. Such 3D textures are commonly called "brick maps" and have nice properties such as filtering and automatic level of detail. There is two ways to convert a point cloud file into such a texture:

  1. By using the ptc2brick utility (see section Using ptc2brick) as in:
    ptc2brick scene.ptc scene.bkm
    
  2. By calling RiMakeBrickMap from inside a RIB file (or programmatically from inside a C source file):
    ...
    MakeBrickMap [ "scene.ptc" ] "scene.bkm"
    ...
    
NOTE

The first parameter to RiMakeBrickMap in the example above is an array of strings and not a single string. This means that the command can receive more than one point cloud file at a time. The same applies to ptc2brick: more than one point cloud file can be specified as input.

A brickmap file can then be accessed using the texture3d() shadeop (see texture3d shadeop), exactly as for point cloud files.

7.6.4 Baking Using Lights

One potential downside to baking is the necessary modifications to all contributing shaders. The basic structure of a shader that has been modifying for baking is similar to this:

surface foo(
    ... common parameters ...
    ... baking related parameters )
{
    ... main shader's code ...

    ... baking code ... 
}

The most annoying part of this approach is the addition of the baking related parameters. Not only one has to add them to all shaders but also one needs to specify them for each shader instance. One solution to this problem is to specify the baking parameters as user attributes:

Attribute "user" "string bakefile" "color.ptc"

The shader can then access these parameters using the attribute() shadeop (see attribute shadeop). Another solution is to use a light source to perform the baking. The main advantage of using light sources instead of user attributes is that most 3D packages have an easy way to perform and visualize light linking; so one can easily attach a light source to parts of a scene that needs to be baked.

light bakelight(
    bool do_bake = 0.0;
    string bake_file = "";
    float bake_color = 0.0;
    string spacename = "world";
    string __category = "bakelight";)
{
    if( do_bake==1.0 && bake_file != "" )
    {
        if( bake_color == 1 )
        {
            color C = 0;
            surface( "Ci", C ); 
            bake3d(
                bake_file, "", Ps, Ns,
                "interpolate", 1, "coordsystem", spacename,
                "Ci", C );
        }
        else
        {
            bake3d(
                bake_file, "", Ps, Ns, 
                "interpolate", 1, "coordsystem", spacename );
        }
    }
}
Listing 7.10: Baking using a light source.

The light source in Listing 7.10 above can bake both the color (for color bleeding) or the area (for occlusion). It uses the surface() shadeop to get Ci from the surface shader that is executing the light source. This means that the light source has to be executed after Ci has been computed. The execution of a light source can be triggered explicitly using the illuminance() construct but one should avoid executing light sources that are not meant for baking(53) and that is why a __category string is specified. Here is an example shader that will trigger the execution of the baking light:

surface plastic( ... )
{
    Ci = ... ;

    /* execute light sources in the "bakelight" category */
    illuminance( "bakelight", P );
    { /* nothing to do here */
    }
}

In this case, the light source should be attached to the scene during the backing pass and detached in the beauty pass. This process can be made somewhat easier by using a user option to enable the light during the backing pass and disabling it in the beauty pass so to avoid light linking operations between passes. The illuminance call then becomes:

...
float enable = 0;
option( "user:bakepass", enable );
illuminance( "bakelight", P, "send:light:do_bake", enable );
{
}

In this case the user has to properly set the bakepass boolean to `1' during the bake pass and to `0' during the beauty pass. The send: command will set the do_bake parameter of the light source using forward message passing.

3Delight 10.0. Copyright 2000-2011 The 3Delight Team. All Rights Reserved.