Page tree

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

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
languagecpp
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
languagecpp
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.

...