...
Note |
---|
In order to facilitate the reuse of the same parameter enumeration for pattern output computation, it is highly recommended that all outputs be placed at the beginning of the parameter table. |
Initialization and Synchronization
Anchor |
---|
...
|
...
|
...
Dynamic Parameters
A plugin can create its parameter table dynamically based on the parameters provided to each instance of the plugin. This dynamically created table is created using the CreateInstanceData()
method, and should be saved in the paramtable
member of the InstanceData.
If the associated memory need to be freed, if should be taken care of in the freefunc()
routine. Generally, static interfaces should be preferred over dynamic interfaces due to their extra memory expense. If the paramtable
member remains null, all instances will share the parameter table returned by GetParamTable()
. In order to prevent the renderer from filtering out dynamic parameters as bad inputs, a plugin that is using a dynamically created table should have a k_RixSCAnyType
entry in its plugin parameter table.
Initialization and Synchronization
Anchor | ||||
---|---|---|---|---|
|
In order to initialize the plugin, the renderer will call Init()
once. Even if the plugin is evoked multiple times during the render with different arguments, Init()
will still be called only once during the lifetime of the render. The RixContext
parameter can be used by the plugin to request any RixInterfaces
services provided by the renderer. Any expensive memory allocations or operations that can be reused during the lifetime of the plugin can be performed in this routine. Upon successful initialization, this routine should return a zero status.
Finalize()
is the companion to Init()
, called at the end of rendering with the expectation that any data allocated within the Init()
implementation will be released.
Plugin instance initialization
Depending on the paradigm used by the plugin type, CreateInstanceData()
or CreateXXX()
will be called once per plugin instance:
- CreateInstanceData() allows the plugin instance to create private data (stored in
InstanceData::data
), that will then be provided back to the various plugin methods the renderer will call during rendering. - CreateXXX() returns a C++ object that should store its own representation of the plugin instance. The renderer will call methods on this object during rendering (instead of calling plugin methods).
The renderer provides the unique evocation parameters that triggered the creation of the plugin instance through the the RixParameterList
class.
RixParameterList
allows for the evaluation of the plugin instance parameters via the EvalParam()
method. To aid in this, it allows for the querying via RixParameterList::GetParamInfo()
of whether the parameters have been unset (and are therefore at their default value), set as a uniform value, or are part of a network connection, i.e. the parameter is computed by an upstream node in the shading graph. A network connection is understood to be a varying quantity, and its value cannot be evaluated at the time that CreateInstanceData
is evoked; this is why EvalParam()
will return k_RixSCInvalidDetail
if the parameter is a network connection. Otherwise, EvalParam()
can be used to get an understanding of the uniform, non-varying parameters that are passed to the shading instance, and these can be used to perform any precomputations as needed.
Anchor | ||||
---|---|---|---|---|
|
The Synchronize()
routine allows the plugin to respond to synchronization signals delivered by the renderer. This call may happen multiple times during a render session and/or during a given render.
The renderer may provide additional information to the plugin via the input parameter RixParameterList
. These signals include:
k_RixSCRenderBegin
: The renderer is being initialized.k_RixSCRenderEnd
: The renderer is about to end.k_RixSCInstanceEdit
: Currently unused.k_RixSCCancel
: Currently unused.k_RixSCCheckpointRecover
: A signal that the renderer is about to restart rendering from a checkpoint. The
In order to initialize the plugin, the renderer will call Init()
once. Even if the plugin is evoked multiple times during the render with different arguments, Init()
will still be called only once during the lifetime of the render. The RixContext
parameter can be used by the plugin to request any RixInterfaces
services provided by the renderer. Any expensive memory allocations or operations that can be reused during the lifetime of the plugin can be performed in this routine. Upon successful initialization, this routine should return a zero status.
Finalize()
is the companion to Init()
, called at the end of rendering with the expectation that any data allocated within the Init()
implementation will be released.
Plugin instance initialization
Depending on the paradigm used by the plugin type, CreateInstanceData()
or CreateXXX()
will be called once per plugin instance:
- CreateInstanceData() allows the plugin instance to create private data (stored in
InstanceData::data
), that will then be provided back to the various plugin methods the renderer will call during rendering. - CreateXXX() returns a C++ object that should store its own representation of the plugin instance. The renderer will call methods on this object during rendering (instead of calling plugin methods).
The renderer provides the unique evocation parameters that triggered the creation of the plugin instance through the the RixParameterList
class.
RixParameterList
allows for the evaluation of the plugin instance parameters via the EvalParam()
method. To aid in this, it allows for the querying via RixParameterList::GetParamInfo()
of whether the parameters have been unset (and are therefore at their default value), set as a uniform value, or are part of a network connection, i.e. the parameter is computed by an upstream node in the shading graph. A network connection is understood to be a varying quantity, and its value cannot be evaluated at the time that CreateInstanceData
is evoked; this is why EvalParam()
will return k_RixSCInvalidDetail
if the parameter is a network connection. Otherwise, EvalParam()
can be used to get an understanding of the uniform, non-varying parameters that are passed to the shading instance, and these can be used to perform any precomputations as needed.
...
The Synchronize()
routine allows the plugin to respond to synchronization signals delivered by the renderer. This call may happen multiple times during a render session and/or during a given render.
The renderer may provide additional information to the plugin via the input parameter RixParameterList
. These signals include:
k_RixSCRenderBegin
: The renderer is being initialized.k_RixSCRenderEnd
: The renderer is about to end.k_RixSCInstanceEdit
: Currently unused.k_RixSCCancel
: Currently unused.k_RixSCCheckpointRecover
: A signal that the renderer is about to restart rendering from a checkpoint. The parameter list will contain a single constant integer "increment" which contains the increment value from which the renderer will restart.k_RixSCCheckpointWrite
: A signal that the renderer is about to write a checkpoint. The parameter list will contain two values: a constant integer "increment" indicating the increment value the renderer will write, and a constant string "reason" which contains one of three values: "checkpoint", "exiting", or "finished", indicating why the renderer is writing the checkpoint.k_RixSCIncrementBarrier
: A signal that the rendering of an new increment is about to begin. This signal will only be received if the integrator has setwantsIncrementBarrier
to true in theRixIntegratorEnvironment
. The parameter list will contain a single constant integer "increment" which contains the increment value from which the renderer will restart.k_RixSCCheckpointWrite
: A signal that the renderer is about to render.
Plugin instance synchronization
Similarly to Synchronize()
, the SynchronizeInstanceData()
method allows the plugin instance to update its state when a render starts.
There are some subtle differences with Synchronize()
though:
- there is no synchronization message, it is always assumed to be k_RixSCRenderBegin
- the plugin instance must subscribe to this mechanism, by appropriately setting InstanceData::synchronizeHints duringCreateInstanceData()
If the plugin type doesn't use CreateInstanceData()
but CreateXXX()
, the created objects will sometimes expose an Edit()
or Synchronize()
method.
Closures synchronization
Closures are transient objects with a very short lifetime, and are re-created with such a frequency that there is no need for synchronization mechanism.
Interactive rendering sessions
Because Init()
and CreateInstanceData()
are only called once during a rendering session, they are unable to capture edits that may have happened after the previous render.
- write a checkpoint. The parameter list will contain two values: a constant integer "increment" indicating the increment value the renderer will write, and a constant string "reason" which contains one of three values: "checkpoint", "exiting", or "finished", indicating why the renderer is writing the checkpoint.
k_RixSCIncrementBarrier
: A signal that the rendering of an new increment is about to begin. This signal will only be received if the integrator has setwantsIncrementBarrier
to true in theRixIntegratorEnvironment
. The parameter list will contain a single constant integer "increment" which contains the increment value the renderer is about to render.
Plugin instance synchronization
Similarly to Synchronize()
, the SynchronizeInstanceData()
method allows the plugin instance to update its state when a render starts.
There are some subtle differences with Synchronize()
though:
- there is no synchronization message, it is always assumed to be k_RixSCRenderBegin
- the plugin instance must subscribe to this mechanism, by appropriately setting InstanceData::synchronizeHints duringCreateInstanceData()
If the plugin type doesn't use CreateInstanceData()
but CreateXXX()
, the created objects will sometimes expose an Edit()
or Synchronize()
method.
Closures synchronization
Closures are transient objects with a very short lifetime, and are re-created with such a frequency that there is no need for synchronization mechanism.
Interactive rendering sessions
Because Init()
and CreateInstanceData()
are only called once during a rendering session, they are unable to capture edits that may have happened after the previous render.
It is therefore strongly recommended for these two methods to only rely on data that was explicitly provided (e.g. the plugin instance parameter list). In particular, special care should be taken not to query options or anything related to the render state (displays, integrator environment, lpe-related quantities, etc...) for the following reasons:
...
RixBxdf::GetInstanceHints()
is called afterCreateInstanceData()
but beforeSynchronizeInstanceData()
. As a consequence, if a bxdf instance's hint depends on a global option or on the render state, edits will have no effect. This will lead to counter-intuitive behaviors, and it is strongly recommended for bxdf instance hints to only depend on the shader parameters provided toCreateInstanceData()
RixPattern::Bake2dOutput()
andRixPattern::Bake3dOutput()
are called afterCreateInstanceData()
but beforeSynchronizeInstanceData()
. The same limitations as the one described in the item above apply.RixLight::Edit()
andRixLight::SynchronizeInstanceData()
are currently not called.
Misc
...
Overview
The following table summarizes the structure of the various RixShadingPlugin, in relation to initialization and synchronization. All plugins use the RixShadingPlugin::Init()
and RixShadingPlugin::Finalize()
calls.
Plugin | RixShadingPlugin subclass | Instance representation | Generates a closure (per RixShadingContext) |
---|---|---|---|
bxdf | RixBxdfFactory | InstanceData::data | Yes, RixBxdf |
displacement | RixDisplacementFactory | InstanceData::data | Yes, RixDisplacement |
display filter | RixDisplayFilter | InstanceData::data | No |
integrator | RixIntegratorFactory | RixIntegrator | No |
light | RixLightFactory | RixLight | No |
light filter | RixLightFilter | InstanceData::data | No |
pattern | RixPattern | InstanceData::data | No |
projection | RixProjectionFactory | RixProjection | No |
sample filter | RixSampleFilter | InstanceData::data | No |
Examples
PxrDiffuse
First, note that while the bxdf plugin is published and exposed as 'PxrDiffuse', it is comprised of two classes:
...
Code Block | ||
---|---|---|
| ||
plist->GetParamInfo(k_presence, &typ, &cnx1); if(cnx1 == k_RixSCNetworkValue) { if (cachePresence == 0) { req |= k_ComputesPresence; } else { req |= k_ComputesPresence | k_PresenceCanBeCached; } } |
PxrDirt
For a more complicated example of instance data usage, consider the PxrDirt
pattern. Its instance data routine caches the values of many uniform parameters and reuses them in PxrDirt::ComputeOutputParams()
, knowing that its .args file prohibits those parameters from being set to network connections.
Code Block | ||
---|---|---|
| ||
Data *data = static_cast<Data*>(instanceData->data); data->numSamples = 4; data->distribution = k_distributionCosine; data->cosineSpread = 1.0f; data->falloff = 0.0f; data->maxDistance = 0.0f; data->direction = k_directionOutside; data->raySpread = 1.0f; params->EvalParam(k_numSamples, 0, &data->numSamples); data->numSamples = RixMax(1, data->numSamples); params->EvalParam(k_distribution, 0, &data->distribution); params->EvalParam(k_cosineSpread, 0, &data->cosineSpread); params->EvalParam(k_falloff, 0, &data->falloff); params->EvalParam(k_maxDistance, 0, &data->maxDistance); params->EvalParam(k_direction, 0, &data->direction); |
...
...
Anchor | ||||
---|---|---|---|---|
|
...