...
Note that at the time of CreateInstanceData
, like other shading plugins, Bxdfs are unable to inspect the values of pattern network inputs; therefore, in cases these inputs are provided (i.e: RixParameterList::GetParamInfo()
returns k_RixSCNetworkValue
) the Bxdf may have no choice but to defer inspection of the inputs until BeginOpacity()
or BeginInterior()
. At that time, those methods may then choose to return NULL instead.
...
RixBxdf
Once a RixBxdf
object is obtained, the integrator may invoke the following methods:
...
The RixBxdf
methods above are expected to return quantities for each point of the shading context originally given to RixBxdfFactory::BeginScatter()
, excepting RixBxdf::EvaluateSamplesAtIndex()
, that operates on a single point of the shading context, evaluating the bxdf function for one or many directions.The
In order to maintain physical correctness, bxdfs are expected to conserve energy and obey the Helmholtz reciprocity principle. Care should be taken so that RixBxdf::GenerateSample()
function has the following input parameters: transportTrait
, lobesWanted
, and random number generator rng
., 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 and vertex connection merging (VCM).
Sample Generation
The GenerateSample()
function has the following input parameters: transportTrait
, lobesWanted
, and random number generator rng
.
- The
transportTrait
tells the Bxdf the subset of light transport to consider: direct illumination, indirect illumination, or both. lobesWanted
specifies what lobes are requested,- The
transportTrait
tells the Bxdf the subset of light transport to consider: direct illumination, indirect illumination, or both. lobesWanted
specifies what lobes are requested, for example specular reflection, diffuse transmission, etc.rng
should be called to generate well-stratified samples; such samples typically reduce noise and improve convergence compared to using uniform random samples.
...
lobeSampled
is similar to the inputlobesWanted
, and specifies which lobe was actually sampled. Bxdfs must respect thetransportTrait
andlobesWanted
request and indicate which class of lobe is associated with each sample by settinglobesSampled
for each generated sample. If and only if the bxdf is unable to generate a requested sample, thenlobesSampled
should be set tok_RixBXNullTrait
; for example, if thelobesWanted
argument requests a specific lobe (e.g., diffuse reflection) that the Bxdf does not support because the Bxdf only supports glossy reflections, thenlobesSampled
should be set tok_RixBXNullTrait
. However, if it is possible to generate the requested samples, thenlobesSampled
should not be set tok_RixBXNullTrait
and should instead be set to the sampled lobe for each point in the shading contextdirections
is the generated ray direction vectors; these directions must be unit length.weights
is a color per sample indicating that sample's weight.forwardPdfs
should account for light moving from the L to V direction, whereasreversePdfs
account for the opposite (from V to L). Bxdfs should always provide both pdf values for integrators to use.compTrans
is an optional result which can be used to indicate transmission color; this will be used as alpha in compositing. A bxdf should check thatcompTrans
is not NULL before assigning to it.
As an example, a purely Lambertian diffuse bxdf should loop over the sample points and for each sample point set the result values as follows: set lobeSampled
to diffuse reflection, set the reflection direction to a randomly generated direction chosen with a cosine distribution on the hemisphere defined by the surface normal (using a well-stratified 2D "random" sample value generated by calling the provided random number generator), set the weight to the diffuse surface albedo color times dot(Nn, Ln) divided by pi, set the forward pdf to dot(Nn, Ln) divided by pi, and set the reverse pdf to dot(Nn, Vn). More details can be found in the source code for the PxrDiffuse bxdf.
The parameters to the EvaluateSample()
function are very similar: transportTrait
, lobesWanted
, random number generator, lobesEvaluated
, directions
, weights
, forwardPdfs
and reversePdfs
. The main difference is that direction (Ln) is an array of inputs that the function should compute weights and pdfs for.
The EvaluateSamplesAtIndex()
function is very similar to EvaluateSample()
, but is used to evaluate multiple samples at the same surface position and normal, but with different illumination directions (Ln). The inputs are the same as for EvaluateSample()
, except that it has two additional inputs: index
and number of samples numSamples
. index
is used to index into built-in variables such as the normal Nn and viewing direction Vn, and numSamples
is the number of directions (Ln) to evaluate the bxdf for. The functionality of EvaluateSamplesAtIndex()
otherwise is similar to EvaluateSample()
, and exists in order to make sample evaluation more efficient in certain light transport settings.
Bxdfs that do not scatter light (e.g. PxrConstant) should disable all lobes and set the forward pdf and reverse pdf to zero.
In order to maintain physical correctness, bxdfs are expected to conserve energy and obey the Helmholtz reciprocity principle. 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:
...
- .
When generating a Bxdf sample, you can run into corner cases (often legitimate cases) where a valid sample cannot be generated. For instance, if the camera ray hits the backside of a single-sided object, a valid sample cannot be generated. Therefore, the
lobeSampled
for this camera ray should be marked as invalid by callingSetValid(false)
. If an invalid sample is returned to the integrator, the integrator will terminate the ray and avoid any further computation. Bxdfs that do not scatter light (e.g.PxrConstant
) should also mark all samples as invalid.Note There is a subtle difference between an invalid sample and a black sample. If a camera ray hits a diffuse black surface, the sample will have zero contribution to the final image despite being valid. It would make sense for the integrator to terminate the ray because further bounces will not contribute to the final image either, but it is important to splat the black contribution to both the beauty and alpha channel. Failing to do so might result in missing geometry in the rendered image. An invalid sample on the other hand, should not only be terminated but also ignored for splatting purposes.
directions
is the generated ray direction vectors; these directions must be unit length.weights
is a color per sample indicating that sample's weight.forwardPdfs
should account for light moving from the L to V direction, whereasreversePdfs
account for the opposite (from V to L). Bxdfs should always provide both pdf values for integrators to use. Bxdfs that do not scatter light (e.g. PxrConstant) should set both pdfs to zero.compTrans
is an optional result which can be used to indicate transmission color; this will be used as alpha in compositing. A bxdf should check thatcompTrans
is not NULL before assigning to it.
As an example, a purely Lambertian diffuse bxdf should loop over the sample points and for each sample point set the result values as follows: set lobeSampled
to diffuse reflection, set the reflection direction to a randomly generated direction chosen with a cosine distribution on the hemisphere defined by the surface normal (using a well-stratified 2D "random" sample value generated by calling the provided random number generator), set the weight to the diffuse surface albedo color times dot(Nn, Ln) divided by pi, set the forward pdf to dot(Nn, Ln) divided by pi, and set the reverse pdf to dot(Nn, Vn). More details can be found in the source code for the PxrDiffuse bxdf.
Sample Evaluation
The parameters to the EvaluateSample()
function are very similar to GenerateSample()
: transportTrait
, lobesWanted
, random number generator, lobesEvaluated
, directions
, weights
, forwardPdfs
and reversePdfs
. The main difference is that directions
is an array of inputs that the function should compute weights and pdfs for.
The EvaluateSamplesAtIndex()
function is very similar to EvaluateSample()
, but is used to evaluate multiple samples at the same surface position and normal, but with different illumination directions (Ln). The inputs are the same as for EvaluateSample()
, except that it has two additional inputs: index
and number of samples numSamples
. index
is used to index into built-in variables such as the normal Nn and viewing direction Vn, and numSamples
is the number of directions (Ln) to evaluate the bxdf for. The functionality of EvaluateSamplesAtIndex()
otherwise is similar to EvaluateSample()
, and exists in order to make sample evaluation more efficient in certain light transport settings.
...
RixOpacity
The renderer will invoke the following methods on RixOpacity
:
...