Table of Contents | ||
---|---|---|
|
Introduction
This
<h3> <ac:structured-macro ac:macro-id="800ed41e-1dc2-48bf-8f89-99488606d54f" ac:name="toc" ac:schema-version="1"> <ac:parameter ac:name="minLevel">3</ac:parameter> </ac:structured-macro></h3><h3>Introduction</h3><p>This documentation is intended to instruct developers in the authoring of custom <em> <a href="https://en.wikipedia.org/wiki/Bidirectional_scattering_distribution_function">bxdfs</a> </em> bxdfs (previously referred to as <em>surface shaders</em> surface shaders). Developers should also consult the <code>RixBxdf.h</code> header the RixBxdf.h
header file for complete details.</p><p>The <code>RixBxdfFactory</code> interface
The RixBxdfFactory
interface defines a shading plugin responsible for creating a <code>RixBxdf</code> object a RixBxdf
object from a shading context (<code>RixShadingContext)</code> and RixShadingContext)
and the set of connected patterns (<code>RixPattern</code>).</p><p>The <code>RixBxdf</code> interface characterizes the <em>light-scattering behavior</RixPattern
).
The RixBxdf
interface characterizes the light-scattering behavior em> (sometimes referred to as <em>material response</em>) for material response) for a given point on the surface of an object.
RixBxdfFactory
Integrators (RixIntegrator
) uses RixBxdfFactory
objects by invoking RixBxdfFactory
</p><h4> <code>RixBxdfFactory</code></h4><p>Integrators (<code>RixIntegrator</code>) uses <code>RixBxdfFactory</code> objects by invoking <code style="line-height: 1.42857;">RixBxdfFactory::BeginScatter()
</code> to obtain a <code style="line-height: 1.42857;">RixBxdf,</code> parameterized to obtain a RixBxdf,
parameterized by the bxdf's potentially varying input parameters. <code style="line-height: 1.42857;">RixBxdfFactory::RixBxdfFactory::BeginScatter()
</code> is is expected to invoke <code style="line-height: 1.42857;">RixShadingContextRixShadingContext::EvalParam()
</code> for for the relevant bxdf parameters. The bxdf acts bxdf acts as a closurea closure, associated with a given shading context.</p><h4> <code>RixBxdf</code></
RixBxdf
Once a RixBxdf
h4><p>Once a <code>RixBxdf</code> object is obtained, the integrator may invoke the following methods:</p><ul style="list-style-type: square;"> <li> <code>RixBxdf::
RixBxdf::GenerateSample()
...
- to generate samples of the bxdf function.
...
RixBxdf::EvaluateSample()
...
- and
RixBxdf::EvaluateSamplesAtIndex()
...
- to evaluate the bxdf function.
...
RixBxdf::EmitLocal()
...
- to retrieve the bxdf's local emission.
The RixBxdf
</li></ul><p>The <code>RixBxdf</code> methods above are expected to return quantities for each point of the shading context originally given to <code>RixBxdfFactorcontext originally given to RixBxdfFactor::BeginScatter()
</code>, excepting <code style="line-height: 1.42857;">RixBxdf, excepting RixBxdf::EvaluateSamplesAtIndex()
</code> , that operates on a single point of the shading context, evaluating the bxdf function for one or many directions.
RixOpacity
In </p><h4> <code>RixOpacity</code></h4><p>In certain cases, integrators may also call <code>RixBxdfFactorycall RixBxdfFactory::BeginOpacity()
</code> to retrieve a <code>RixOpacity</code> a RixOpacity
object, and invoke the following methods:</p><ul style="list-style-type: square;"> <li> <code>RixBxdf
RixBxdf::GetPresence()
...
- to evaluate the
...
- geometry presence.
RixBxdf::GetOpacity()
...
- to evaluate the opacity color.
Execution Model
There <em>opacity color</em>.</li></ul><h3>Execution Model</h3><p>There is one instance of a <code>RixBxdfFactory</code> a RixBxdfFactory
per bound <code>RiBxdf</code> RiBxdf
(RIB) request. This instance may be active in multiple threads simultaneously.</p><p>The
The context for a per-thread execution is signaled by the various methods <code>Beginmethods Begin___()
</code> and <code>End and End___()
</code>. Has a consequence, <code>RixBxdf</code> objects RixBxdf
objects can be assumed as being used used in a mono-threaded context.</p><p>The <code>RixBxdfFactory</code>
The RixBxdfFactory
should stash state in the <code>RixBxdf</code> the RixBxdf
object and consider that the <code>RixBxdf</code> lifetime RixBxdf
lifetime is under control of the integrator. Generally Generally integrators will attempt to minimize the number of live <code>RixBxdf</code> objects RixBxdf
objects but may nonetheless require a large number. For For this reason, the <code>RixBxdf</code> instances RixBxdf
instances should attempt to minimize memory consumption and construction / deconstruction costs.</p><p>The primary <code>RixBxdf</code> entry
The primary RixBxdf
entry points operate on a collection of shading points (<code>RixShadingContext</code>RixShadingContext
) in in order to reasonably maximize shading coherency and support SIMD computation. Integrators rely on the <code>RixBxdf</code> RixBxdf
's ability to generate and evaluate samples across the entire collection of points. Sample evaluation may be performed in an <em>allall-points-one-sample</em> variant using <code style="line-height: 1.42857;">EvaluateSample()</code> sample variant using EvaluateSample()
, and a <em>11-point-n-samples</em> variant via <code style="line-height: 1.42857;">EvaluateSamplesAtIndex()</code> samples variant via EvaluateSamplesAtIndex()
. Generation, however, is constrained to <em>allall-points-one-sample</em>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.</p><ul> <li> <code>RixBxdf
RixBxdf::GenerateSample()
...
- generates one sample for each point of the shading context
RixBxdf::EvaluateSample()
...
- evaluates one direction for each point of the shading context
RixBxdf::EvaluateSamplesAtIndex()
...
- evaluates one-or-many
...
- directions for a
...
- given point of the shading context
Bxdf correctness
A context</li></ul><h3>Bxdf correctness</h3><p>A bxdf should always provide the three methods <code>RixBxdfmethods RixBxdf::GenerateSample()
</code>, <code>RixBxdf RixBxdf::EvaluateSample()
</code> and <code>RixBxdf and RixBxdf::EvaluateSamplesAtIndex()
</code>.</p><p>In .
In order to maintain physical correctness, bxdfs are expected to conserve energy and obey the <a href="https://en.wikipedia.org/wiki/Helmholtz_reciprocity">Helmholtz reciprocity</a>the Helmholtz reciprocity. Care should be taken so that <code>RixBxdfthat RixBxdf::GenerateSample()
</code>, <code>RixBxdf RixBxdf::EvaluateSample()
</code> and <code>RixBxdf and RixBxdf::EvaluateSamplesAtIndex()
</code> return return consistent results. This allows bxdf plugins to be compatible with different rendering techniques such as:</p><ul> <li> <a href="https://en.wikipedia.org/wiki/Path_tracing">unidirectional path tracing</a> </li> <li> <a href="https://en.wikipedia.org/wiki/Path_tracing#Bidirectional_path_tracing">bidirectional path tracing</a> </li> <li> <a href="https://en.wikipedia.org/wiki/Photon_mapping">photon mapping</a> </li> <li> <a href="http://iliyan.com/publications/VertexMerging">vertex connection merging (VCM)</a> </li> <li> <a href="http://cgg.mff.cuni.cz/~jaroslav/papers/2014-upbp/index.htm">unified
- unidirectional path tracing
- bidirectional path tracing
- photon mapping
- vertex connection merging (VCM)
- unified points, beam and paths (UPBP)
Note that the RixBxdf
interfaces </a> </li></ul><p>Note that the <code>RixBxdf</code> interfaces requires two separate scalar pdf values to be returned. The <em>forward pdf</em> should The forward pdf should account for light moving from the L to V direction where as the <em>reverse pdf</em> account the reverse pdf account for the opposite (from V to L). Bxdfs should always provide both values for the integrators to use.
Bxdfs </p><p>Bxdfs that do not scatter light (e.g. PxrConstant) should disable all lobes and set the <em>forward pdf</em> and <em>reversed pdf</the forward pdf and reversed pdf to zero.
Additional Considerations
Installation
RenderMan em> to zero.</p><h3>Additional Considerations</h3><p> <ac:link> <ri:page ri:content-title="Bxdf Evaluation Domain"/> </ac:link></p><p> <ac:link> <ri:page ri:content-title="Bxdf Lobes"/> </ac:link></p><p> <ac:link> <ri:page ri:content-title="Non-Opaque Surfaces"/> </ac:link></p><p> <ac:link> <ri:page ri:content-title="Alpha For Compositing"/> </ac:link></p><p> <ac:link> <ri:page ri:content-title="Query Ray Properties"/> </ac:link></p><p> <ac:link> <ri:page ri:content-title="Bxdf Sample Validity"/> </ac:link></p><h3>Installation</h3><p>RenderMan will search for bxdf plugins on demand, under the <em>rixplugin</em> rixplugin searchpath. The following rib stream will search for a plugin file named <code>MyDiffuse.so</code></p><ac:structured-macro ac:macro-id="5966a98e-1073-4d4f-922a-e0e0916dd514" ac:name="code" ac:schema-version="1"> <ac:plain-text-body><![CDATA[Bxdf "MyDiffuse" "diffuse1" "color tint" named MyDiffuse.so
Code Block |
---|
Bxdf "MyDiffuse" "diffuse1" "color tint" [0.5 0.5 0.5] |
Args files
By convention, arg ]]></ac:plain-text-body></ac:structured-macro><h3>Args files</h3><p>By convention, <em>arg</em> files (.args) are used to define shader metadata needed by host applications. This includes parameter names, default values, localization and GUI hints.</
Arg p><p>Arg files are written in a simple xml format and should be easy to parse.
Bridge </p><p>Bridge specific metadata should also be written to arg files. For example, Maya requires <code>nodeid</code> and <code>classification</code> information:</p><p> </p><ac:structured-macro ac:macro-id="5836fb1a-7e85-4530-b332-37e69de0548d" ac:name="code" ac:schema-version="1"> <ac:plain-text-body><![CDATA[<rfmdata nodeid
and classification
information:
Code Block |
---|
<rfmdata nodeid="1053406" classification="shader/surface:rendernode/RenderMan/bxdf:swatch/rmanSwatch"/> |
Note ]]></ac:plain-text-body></ac:structured-macro><p>Note that RenderMan itself queries parameter information using the <code>RixBxdfFactorythe RixBxdfFactory::GetParamTable()
</code> method, not by reading arg files.</p>