Contents
Introduction
This documentation is intended to instruct developers in the authoring of custom bxdfs (previously referred to as surface shaders). Developers should also consult the RixBxdf.h
header file for complete details.
The RixBxdfFactory
interface defines a shading plugin responsible for creating a RixBxdf
object from a shading context (RixShadingContext)
and the set of connected patterns (RixPattern
).
The RixBxdf
interface characterizes the light-scattering behavior (sometimes referred to as material response) for a given point on the surface of an object.
RixBxdfFactory
Integrators (RixIntegrator
) uses RixBxdfFactory
objects by invoking RixBxdfFactory::BeginScatter()
to obtain a RixBxdf,
parameterized by the bxdf's potentially varying input parameters. RixBxdfFactory::BeginScatter()
is expected to invoke RixShadingContext::EvalParam()
for the relevant bxdf parameters. The bxdf acts as a closure, associated with a given shading context.
RixBxdf
Once a RixBxdf
object is obtained, the integrator may invoke the following methods:
RixBxdf::GenerateSample()
to generate samples of the bxdf function.RixBxdf::EvaluateSample()
andRixBxdf::EvaluateSamplesAtIndex()
to evaluate the bxdf function.RixBxdf::EmitLocal()
to retrieve the bxdf's local emission.
The RixBxdf
methods above are expected to return quantities for each point of the shading context originally given to RixBxdfFactor::BeginScatter()
, excepting RixBxdf::EvaluateSamplesAtIndex()
, that operates on a single point of the shading context, evaluating the bxdf function for one or many directions.
RixOpacity
In certain cases, integrators may also call RixBxdfFactory::BeginOpacity()
to retrieve a RixOpacity
object, and invoke the following methods:
RixBxdf::GetPresence()
to evaluate the geometry presence.RixBxdf::GetOpacity()
to evaluate the opacity color.
Execution Model
There is one instance of a RixBxdfFactory
per bound RiBxdf
(RIB) request. This instance may be active in multiple threads simultaneously.
The context for a per-thread execution is signaled by the various methods Begin___()
and End___()
. Has a consequence, RixBxdf
objects can be assumed as being used used in a mono-threaded context.
The RixBxdfFactory
should stash state in the RixBxdf
object and consider that the RixBxdf
lifetime is under control of the integrator. Generally integrators will attempt to minimize the number of live RixBxdf
objects but may nonetheless require a large number. For this reason, the RixBxdf
instances should attempt to minimize memory consumption and construction / deconstruction costs.
The primary RixBxdf
entry points operate on a collection of shading points (RixShadingContext
) in order to reasonably maximize shading coherency and support SIMD computation. Integrators rely on the RixBxdf
's ability to generate and evaluate samples across the entire collection of points. Sample evaluation may be performed in an all-points-one-sample variant using EvaluateSample()
, and a 1-point-n-samples variant via EvaluateSamplesAtIndex()
. Generation, however, is constrained to all-points-one-sample. Evaluation typically has different requirements (e.g. for making connections in a bidirectional integrator), whereas generation typically benefits from being performed all points at once.
RixBxdf::GenerateSample()
generates one sample for each point of the shading contextRixBxdf::EvaluateSample()
evaluates one direction for each point of the shading contextRixBxdf::EvaluateSamplesAtIndex()
evaluates one-or-many directions for a given point of the shading context
Bxdf correctness
A bxdf should always provide the three methods RixBxdf::GenerateSample()
, RixBxdf::EvaluateSample()
and RixBxdf::EvaluateSamplesAtIndex()
.
In order to maintain physical correctness, bxdfs are expected to conserve energy and obey the Helmholtz reciprocity. Care should be taken so that RixBxdf::GenerateSample()
, RixBxdf::EvaluateSample()
and RixBxdf::EvaluateSamplesAtIndex()
return consistent results. This allows bxdf plugins to be compatible with different rendering techniques such as:
- unidirectional path tracing
- bidirectional path tracing
- photon mapping
- vertex connection merging (VCM)
- unified points, beam and paths (UPBP)
Note that the RixBxdf
interfaces requires two separate scalar pdf values to be returned. The forward pdf should account for light moving from the L to V direction where as the reverse pdf account for the opposite (from V to L). Bxdfs should always provide both values for the integrators to use.
Bxdfs that do not scatter light (e.g. PxrConstant) should disable all lobes and set the forward pdf and reversed pdf to zero.
Additional Considerations
Installation
RenderMan will search for bxdf plugins on demand, under the rixplugin searchpath. The following rib stream will search for a plugin file named MyDiffuse.so
Bxdf "MyDiffuse" "diffuse1" "color tint" [0.5 0.5 0.5]
Args files
By convention, arg files (.args) are used to define shader metadata needed by host applications. This includes parameter names, default values, localization and GUI hints.
Arg files are written in a simple xml format and should be easy to parse.
Bridge specific metadata should also be written to arg files. For example, Maya requires nodeid
and classification
information:
<rfmdata nodeid="1053406" classification="shader/surface:rendernode/RenderMan/bxdf:swatch/rmanSwatch"/>
Note that RenderMan itself queries parameter information using the RixBxdfFactory::GetParamTable()
method, not by reading arg files.