## 8.1 Basic Interface

We will first define the interface for the individual BRDF and BTDF
functions. BRDFs and BTDFs share a common base class, `BxDF`. Because
both have the exact same interface, sharing the same base class reduces
repeated code and allows some parts of the system to work with `BxDF`s
generically without distinguishing between BRDFs and BTDFs.

The `BSDF` class, which will be introduced in Section 9.1,
holds a collection of `BxDF` objects that together describe the
scattering at a point on a surface. Although we are hiding the
implementation details of the `BxDF` behind a common interface for
reflective and transmissive materials, some of the light transport
algorithms in Chapters 14 through
16 will need to distinguish between these two types.
Therefore, all `BxDF`s have a `BxDF::type` member that holds flags
from `BxDFType`. For each `BxDF`, the flags should have at least
one of `BSDF_REFLECTION` or `BSDF_TRANSMISSION` set and exactly
one of the diffuse, glossy, and specular flags. Note that there is no
retro-reflective flag; retro-reflection is treated as glossy reflection in
this categorization.

The `MatchesFlags()` utility method determines if the `BxDF`
matches the user-supplied type flags:

The key method that `BxDF`s provide is `BxDF::f()`. It
returns the value of the distribution function for the given pair of
directions. This interface implicitly assumes that light in different
wavelengths is decoupled—energy at one wavelength will not be
reflected at a different wavelength. By making this assumption, the effect
of the reflection function can be represented directly with a
`Spectrum`. Supporting fluorescent materials where this
assumption is not true would require that this method return an
matrix that encoded the transfer of energy between spectral samples (where
is the number of samples in the `Spectrum` representation).

Not all `BxDF`s can be evaluated with the `f()` method. For example,
perfectly specular objects like a mirror, glass, or water only scatter
light from a single incident direction into a single outgoing direction.
Such `BxDF`s are best described with delta distributions that are zero
except for the single direction where light is scattered.
These `BxDF`s need special handling in `pbrt`, so we will also provide
the method `BxDF::Sample_f()`. This method is used both for
handling scattering that is described by delta distributions as well as for
randomly sampling directions from `BxDF`s that scatter light along
multiple directions; this second application will be explained in the
discussion of Monte Carlo BSDF sampling in
Section 14.1.

`BxDF::Sample_f()` computes the direction of
incident light given an outgoing direction and returns the
value of the `BxDF` for the pair of directions. For delta
distributions, it is necessary for the `BxDF` to choose the incident
light direction in this way, since the caller has no chance of generating
the appropriate direction.
The
`sample` and `pdf` parameters aren’t needed for delta
distribution `BxDFs`, so they will be explained later, in
Section 14.1, when we provide implementations of this
method for nonspecular reflection functions.

### 8.1.1 Reflectance

It can be useful to take the aggregate behavior of the 4D BRDF or BTDF, defined as a function over pairs of directions, and reduce it to a 2D function over a single direction, or even to a constant value that describes its overall scattering behavior.

The *hemispherical-directional reflectance* is a 2D function that
gives the total reflection in a given direction due to constant
illumination over the hemisphere, or, equivalently, total reflection over
the hemisphere due to light from a given direction.
It is defined
as

The `BxDF::rho()` method computes the reflectance function
. Some `BxDF`s can compute this value in closed form,
although most use Monte Carlo integration to compute an approximation to
it. For those `BxDF`s, the `nSamples` and `samples`
parameters are used by the implementation of the Monte Carlo algorithm; they are
explained in Section 14.1.5.

The *hemispherical-hemispherical reflectance* of a surface, denoted
by , is a spectral value that gives the fraction of
incident light reflected by a surface when the incident light is the same
from all directions. It is

The `BxDF::rho()` method computes if no direction
is provided. The remaining parameters are again used when computing
a Monte Carlo estimate of the value of , if needed.

### 8.1.2 BxDF Scaling Adapter

It is also useful to take a given `BxDF` and scale its contribution
with a `Spectrum` value. The `ScaledBxDF` wrapper holds a
`BxDF *` and a `Spectrum` and implements this functionality. This
class is used by the `MixMaterial` (defined in
Section 9.2.3), which creates `BSDF`s based on a
weighted combination of two other materials.

The implementations of the `ScaledBxDF` methods are straightforward;
we’ll only include `f()` here.