The BRDFs and BTDFs introduced in the previous chapter address only part of the problem of describing how a surface scatters light. Although they describe how light is scattered at a particular point on a surface, the renderer needs to determine which BRDFs and BTDFs are present at a point on a surface and what their parameters are. In this chapter, we describe a procedural shading mechanism that addresses this issue.
The basic idea behind pbrt’s approach is that a surface shader is bound to each primitive in the scene. The surface shader is represented by an instance of the Material interface class, which has a method that takes a point on a surface and creates a BSDF object (and possibly a BSSRDF) that represents scattering at the point. The BSDF class holds a set of BxDFs whose contributions are summed to give the full scattering function. Materials, in turn, use instances of the Texture class (to be defined in the next chapter) to determine the material properties at particular points on surfaces. For example, an ImageTexture might be used to modulate the color of diffuse reflection across a surface. This is a somewhat different shading paradigm from the one that many rendering systems use; it is common practice to combine the function of the surface shader and the lighting integrator (see Chapter 14) into a single module and have the shader return the color of reflected light at the point. However, by separating these two components and having the Material return a BSDF, pbrt is better able to handle a variety of light transport algorithms.