...
The input/output array contribution contains the lighting contribution distributed into some number of diffuse and specular lobes. For each lobe there are numSamples
entries. For instance, to modulate the lighting by a filter that passes only the red channel:
Code Block | ||
---|---|---|
| ||
for(int j = 0; j < contribution->GetNumSpecularLobes(); ++j) {
for(int i = 0; i < numSamples; ++i) {
contribution->GetSpecularLobe(j)[i] *= RtColorRGB(1.0,0.0f,0.0f);
}
}
for(int j = 0; j < contribution->GetNumDiffuseLobes(); ++j) {
for(int i = 0; i < numSamples; ++i) {
contribution->GetDiffuseLobe(j)[i] *= RtColorRGB(1.0,0.0f,0.0f);
}
} |
...
Instance Data
For a detailed discussion of instance data, see lightweight instancing services. When the CreateInstanceData routine is called, the plugin has access to the parameter list of the light filter and can create arbitrary data that is stored by the renderer and supplied as the instanceData pointer during filtering. This should be uniform data that can be accessed by multiple threads simultaneously. Pre-processing the parameter list is an important performance optimization. A light filter will be invoked for every surface-to-light interaction, and in a production-level shot there can be billions of these events.
As an example, below is the CreateInstanceData method for PxrLightFilterCombiner. Like bxdfs, light filters can be referenced in arguments to other light filters. To run multiple light filters, call EvalParam to get pointers to the upstream light filter and it's instance. These are stored and used later during filtering.
Code Block | ||
---|---|---|
| ||
struct myData { int arrayLen; RixLightFilter** filters; RtConstPointer* instances; }; static void releaseInstanceData(RtPointer data) { myData* md = (myData*) data; delete[] md->filters; delete[] md->instances; delete md; } int PxrLightFilterCombiner::CreateInstanceData( RixContext &ctx, |
...
char const *handle,
|
...
|
...
RixParameterList const *plist,
|
...
RixShadingPlugin::InstanceData *idata)
{
RixSCType typ;
bool isconnected;
int arraylen;
plist->GetParamInfo(k_mult, &typ, &isconnected, &arraylen);
myData* mydata = new myData;
mydata->arrayLen = arraylen;
mydata->filters = new RixLightFilter* [arraylen];
mydata->instances = new RtConstPointer [arraylen];
for (int i=0; i<arraylen; ++i)
plist->EvalParam(k_mult, i, &mydata->filters[i], &mydata->instances[i]);
idata->data = (void *) mydata;
idata->freefunc = releaseInstanceData;
return 0;
} |
...
Running multiple filters
Like bxdfs, light filters can be parameters to other light filters. The last filter given before an AreaLightSource call (the root filter in a tree of filters) is responsible for delegating to the filters in its parameter list. Furthermore, light filters can be disabled on a gprim basis. To respect this, it is the responsibility of the filter to call RixLightFilterContext::IsEnabled()
. If the upstream filter is not enabled, don't run it. IsEnabled()
also returns a pointer to the upstream filter's instanceData
, which should be passed to its Filter()
method.
...