In Arnold 5.0, the BSDF API has been redesigned to support more advanced rendering algorithms, more advanced BSDFs, and more optimized implementations.
Here is a simple diffuse BSDF example, with a shader that uses the BSDF to integrate direct and indirect light.
A BSDF consists of a struct to store its parameters, and a number of methods. A new BSDF is created using
AiBSDF, which receives a method table and allocates a struct to store parameters. After shader evaluation is finished, the integrator will initialize, evaluate and sample the BSDF.
bsdf_init: Called before the BSDF is evaluated or sampled for the first time. BSDF initialization can include: ensuring that the provided parameters are within a valid range, storing local geometry data for later evaluation and sampling (geometric normal, outgoing view direction, ...), and precomputing any data needed for evaluation and sampling. Here the BSDF must also provide information about its lobes, and optionally provide bounds for more efficient light culling.
bsdf_eval: Evaluates the BSDF for a given incoming light direction and the current outgoing view direction. If the BSDF consists of multiple lobes, lobe_mask describes which lobes must be evaluated. The result of this evaluation for each lobe is:
BSDF * cos(N.wi) / pdf.The cosine of the angle between the surface normal and the incoming light direction must be included, and the weight is divided by the probability density. For a BSDF that provides perfect importance sampling, this weight would be
bsdf_sample: Sample an incoming light direction and evaluate the BSDF for this direction. This function returns:
- Sampled incoming light direction
- Index of the lobe that was sampled.
bsdf_evalfor the same incoming light direction.
- Sampled incoming light direction
bsdf_interior: Optionally return a list of volume closures to fill the interior of the volume. The typical example would be a glass BSDF returning a volume absorption closure.
BSDF can consist of multiple lobes, for example multiple layers in a layered BSDF, or separate reflection and refraction components in glass BSDF. Each lobe has an associated ray type and AOV name. This makes it possible to:
- Output each lobe to a separate AOV.
- Independently control the diffuse, glossy and refraction depth and number of samples.
- Let Arnold do more efficient sampling by separating lobes with distinct shapes.
In BSDF initialization the BSDF specifies the number of lobes it consists of, and provides an array with the ray type and AOV name for each.
The evaluation and sample methods then receive a lobe bitmask to indicate which lobes to evaluate or sample respectively. If the sample method receives a lobe mask with multiple lobes, it is up to the BSDF to pick one of the lobes to sample, ideally importance sampling based on how much each lobe contributes.
These methods output an array of lobe samples, and return a lobe bitmask to indicate which lobe samples were filled in. This may be a subset or superset of the lobes specified with the input lobe mask.
If all reflected incoming light on the BSDF is contained in a hemisphere, it is possible to specify the normal of that hemisphere. Providing this information is not strictly required, but can help speed up rendering by letting Arnold more quickly discard light that is outside the bounds of the BSDF.
BSDF may use normals different than the smooth surface normal
Ns, using bump or normal mapping. If this modified normal is very different than the smooth surface normal, artifacts may appear however. An
AiBSDFBumpShadow utility function is provided to hide such artifacts by adding extra shadowing as part of BSDF evaluation.
This function takes as input the forward facing smooth normal, the bump mapped normal, and the incoming light direction, and outputs a factor to multiply with the BSDF weight.
Ray directions returned by
bsdf_sample include ray differentials. For good texture filtering performance and quality it is important to provide ray differentials. The
AiRefractWithDerivs utility functions can be used to compute reflected or refracted vectors with derivatives.
Example for a simple perfectly sharp specular BSDF:
Unidirectional path tracers can't resolve caustics efficiently. Sharp specular bounces seen through a rough specular or diffuse bounce are too noisy without any compensation. Built-in BSDFs automatically increase their roughness to reduce caustic noise at the cost of bias.
options.indirect_glossy_blur controls the amount of blurring, with 0 resulting in unbiased renders.
Custom BSDFs can use the same method, by clamping their roughness with the automatically estimated minimum roughness provided by the
Glass shaders often require many bounces to escape. If the number of bounces is limited, this leads to dark patches. Each BSDF lobe has a flag that can be set to use the background color or a fixed white color when the number of bounces has been exceeded.
The API is designed to work with bidirectional rendering algorithms. However as Arnold does not provide such an integrator yet, BSDFs are not yet required to provide implementations compatible with such rendering methods. The
reverse_pdf member of lobe samples is a placeholder and ignored currently.