Page tree

Versions Compared

Key

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

...

A RixPattern plugin is used to connect textures and procedurally generated patterns to RiBxdf parameters, or to other patterns to create a shading graph. There are numerous pattern plugins included with RenderMan Pro Server and RenderMan for Mayathe RenderMan software, but if none of the included plugins generate the pattern you want, then this guide will help you write your own pattern plugin. Source code for many of the RenderMan pattern plugins can be found in the PixarRenderMan-Examples-VERSION/plugins/pattern/ directory which is installed as part of the separate examples package.

For pattern generation using the Open Shading Language (OSL), see the PxrOSL plugin documentation on Working with PxrOSL.

Source code for pattern plugin examples can be found in the /lib/examples/RIS/plugins/pattern/ directory of your RenderMan Pro Server installation.

Implementing the RixPattern Interface

RixPattern.h defines the interface that all pattern plugins must implement. RixPattern is a subclass of RixShadingPlugin, and therefore shares the same initializationsynchronization, and parameter table logic as other shading plugins. Because a RixPattern is expected to be a lightweight object that may be created many times over the course of the render, RixPattern is expected to take advantage of the lightweight instancing services provided by RixShadingPluginTherefore to start developing your own pattern, you can #include "RixPattern.h" and make sure your pattern class implements the required methods inherited from the RixShadingPlugin interface: Init(), Finalize()Synchronize(), GetParamTable(), and CreateInstanceData().

The RIX_PATTERNCREATE() method is called by the renderer to create an instance of the pattern plugin. Generally, the implementation of this method should simply return a new allocated copy of your pattern class. Similarly, the RIX_PATTERNDESTROY() method is called by the renderer to delete an instance of the pattern plugin; a typical implementation of this method is to delete the passed in pattern pointer:


RIX_PATTERNCREATE
{
return new MyPattern();
}
    RIX_PATTERNDESTROY
{
delete ((MyPattern*)pattern);
}


ComputeOutputParams()

ComputeOutputParams() is the heart of a pattern plugin; : it reads evaluates the input parameters, and computes the pattern output. It is called once per graph execution. All , and all outputs must be computed during this one callsingle invocation. The renderer provides a list of the outputs it expects the plugin to compute. Most often, this is exactly the same as the outputs declared number and type of outputs should match the number and type of outputs declared in the parameter table. This method operates on The domain of evaluation of this function is a shading context, which is of type RixShadingContext, which is defined in RixShading.h

To read an input value, use the RixShadingContext::EvalParam() method. Some examples for reading different types of input parameters are shown below:

int
PxrCustomNoise::ComputeOutputParams(RixShadingContext const *sctx,
                                RtInt *noutputs, OutputSpec **outputs,
                                RixSCParamInfo const *ignored)
{
    bool varying = true;
    bool uniform = false;
    RixSCType type;
    bool isconnected;

    // read a uniform integer value, and store the result in the
    // RtInt noiseType variable. m_noiseType is a PxrCustomNoise
    // member variable that contains the default noiseType value.
    RtInt *noiseTypePtr;
    sctx->EvalParam(k_noiseType, -1, &noiseTypePtr, &m_noiseType, uniform);
    RtInt const noiseType(*noiseTypePtr);

    // read a varying float value for the threshold input parameter.
    // m_threshold is a PxrCustomNoise member variable that contains
    // the default value.
    RtFloat *threshold;
    sctx->EvalParam(k_threshold, -1, &threshold, &m_threshold, varying);

    // read one value from a varying float[2] array
    RtFloat *repeatUV0, *repeatUV1;
    sctx->EvalParam(k_repeatUV, 0, &repeatUV0, &m_repreatUV, varying);
    // read the other value from a varying float[2] array. Note that
    // the arrayIndex parameter is set to 1 to read the second value.
    sctx->EvalParam(k_repeatUV, 1, &repeatUV1, &m_repreatUV, varying);

    // read in a float[3] array of values into a RtFloat3 variable.
    RtFloat3 *scale;
    sctx->EvalParam(k_scale, -1, &scale, &m_scale, varying);

    // check for manifold input
    RtPoint3 *Q = (RtPoint3*)RixAlloca(sizeof(RtPoint3)*sctx->numPts);
    RtFloat *Qradius = (RtFloat*)RixAlloca(sizeof(RtFloat)*sctx->numPts);
    sctx->GetParamInfo(k_manifoldBegin, &type, &isconnected);
    if(isconnected)
    {
        sctx->EvalParam(k_manifoldQ, -1, &Q);
        sctx->EvalParam(k_manifoldQradius, -1, &Qradius);
    }
    else
    {
        // allocate space for our remapped P
        RtFloat const *pvWidth;
        RtPoint3 const *pv;
        char const *primvarNm = "P";
        RtFloat3 fill(0.f, 0.f, 0.f);
        sctx->GetPrimVar(primvarNm, fill, &pv, &pvWidth);
        *Qradius = *pvWidth;
        memcpy(Q, pv, sizeof(RtPoint3) * sctx->numPts);
    }

    // read in the placementMatrix float values and
    // default the to the identity matrix
    RtFloat *placementMatrix = (RtFloat*)RixAlloca(sizeof(RtFloat)*16);
    const RtFloat zero = 0.0f;
    const RtFloat one = 1.0f;
    RtFloat* placementInput;
    for (int i=0; i< 16; i++)
    {
        if ( i % 5 == 0)
            sctx->EvalParam(k_placementMatrix, i,
                &placementInput, &one, uniform);
        else
            sctx->EvalParam(k_placementMatrix, i,
                &placementInput, &zero, uniform);
        placementMatrix[i] = *placementInput;
    }

    // read in a varying color value.
    RtColorRGB* defaultColor;
    sctx->EvalParam(k_defaultColor, -1, &defaultColor,
        &m_defaultColor, varying);

Now that you have read in the input parameter values, you can start to write the output values in ComputeOutputParams. First, you will need to allocate memory for the outputs using the RixShadingContext memory allocation services, and then bind the output parameters to the outputs parameter of ComputeOutputParams:

...

The desired input parameter to the pattern is selected by an integer paramId, which is the ordinal position of the parameter in the parameter table. Patterns are expected to know the paramId, the type of the associated parameter, and are expected to pass a pointer to a pointer of the appropriate type. As such, it is suggested that a private parameter enumeration is used to keep track of the order that the parameters are created in the parameter table. For more information, please consult the documentation for RixShadingContext::EvalParam() and RixShadingPlugin::GetParamTable().

After reading input values, output values need to be set up. First, memory buffers for the requested outputs should be allocated using the RixShadingContext memory allocation services. These buffers should then be bound to the requested OutputSpec outputs parameter passed to ComputeOutputParams(), and the type and detail information about those outputs filled in as well. This information should match the declarations from the parameter table. The following code is boilerplate code that can be used to set up the memory allocations for the output parameters. It reads the plugin's parameter table, loops through and allocates the appropriate buffers, and sets the detail and type assuming that the output is always a varying color or float (typical of most patterns).

    // Find the number of outputs
RixSCParamInfo const* paramTable = GetParamTable();
int numOutputs = -1;
while (paramTable[++numOutputs].access == k_RixSCOutput) {}
    // Allocate and bind our outputs
RixShadingContext::Allocator pool(sctx);
OutputSpec* out = pool.AllocForPattern<OutputSpec>(numOutputs);
*outputs = out;
*noutputs = numOutputs;
    // looping through the different output ids
for (int i = 0; i < numOutputs; ++i)
{
        out[i].paramId = i;
out[i].detail = k_RixSCInvalidDetail;
out[i].value = NULL;
        type = paramTable[i].type; // we know this

sctx->GetParamInfo(i, &type, &cinfo);
if(cinfo == k_RixSCNetworkValue)
{
            if( type == k_RixSCColor 

...

)

...

 

...

 

...

         

...

{

...

 

...

 

...

 

...

 

...

    

...

 

...

   

...

out[i].detail = k_RixSCVarying;
out[i].value = pool.AllocForPattern<RtColorRGB>(sctx->numPts);
}
else if( type == k_RixSCFloat )
{
out[i].detail = k_RixSCVarying;
out[i].value = pool.AllocForPattern<RtFloat>(sctx->numPts);
}
}
}

Finally, the pattern can now actually compute the values that go into the output buffers. This is typically done by using the inputs and

...

looping through the number of shaded points

...

RixShadingContext::numPts to compute some values that are stored in the allocated output buffers.


for (int i=0; i<sctx->numPts; i++)
{
    // Compute some output values based on your input. Here we assume
    // outColor is the memory buffer allocated for an output parameter,
    // and inputColor and inputFloat are two inputs that were returned from
    // EvalParam.
    if (style == 1)
    {
        outColor[i] = defaultColorinputColor[i] * inputFloat[i];
    }
}

In the simple example above, we assume the style variable  variable was a uniform RtInt input uniform RtInt input value, so there is only one value for all the points in the shading context. The defaultColor variable was Meanwhile, the inputColor and inputFloat  variable were varying instead of uniform, so it a pointer they are pointers to an array of RtColorRGB values (of RtColorRGB values and array of RtFloat values respectively, one for each shaded point in the shading context).

The ComputeOutputParams() method should return 0 if no error occurred while calculating the output, otherwise it should return a non-zero integer value.For more examples of how input and output parameters are handled in the ComputeOutputParams method, see the pattern plugin examples in the /lib/examples/RIS/plugins/pattern/ directory of your RenderMan Pro Server installation.

Testing Your Pattern Plugin

...