Page tree

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 2 Next »

Contents

Introduction

This documentation is intended to instruct developers in the authoring of custom patterns. Developers should also consult the RixPattern.h header file for complete details.

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 Maya, but if none of the included plugins generate the pattern you want, then this guide will help you write your own pattern plugin.

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 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 input parameters, and computes the pattern output. It is called once per graph execution. All outputs must be computed during this one call. 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 in the parameter table.

This method operates on 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:

int
PxrCustomNoise::ComputeOutputParams(RixShadingContext const *sctx,
                                RtInt *noutputs, OutputSpec **outputs,
                                RixSCParamInfo const *ignored)
{
    // read in the inputs
    // ...

    // Allocate and bind the output parameters.
    // In this example, there are two output parameters: outColor and outAlpha
    RixShadingContext::Allocator pool(sctx);
    OutputSpec *o = pool.AllocForPattern<OutputSpec>(2);
    *outputs = o;
    *noutputs = 2;
    RtColorRGB* outColor = NULL;
    RtFloat* outAlpha = NULL;

    outColor = pool.AllocForPattern<RtColorRGB>(sctx->numPts);
    outAlpha = pool.AllocForPattern<RtFloat>(sctx->numPts);

    // define the param ID, detail, and value for each
    // output parameter.
    o[0].paramId = k_outColor;
    o[0].detail = k_RixSCVarying;
    o[0].value = (RtPointer) outColor;

    o[1].paramId = k_outAlpha;
    o[1].detail = k_RixSCVarying;
    o[1].value = (RtPointer) outAlpha;

The next step is to start calculating your output. This is done by looping through the number of shaded points given by the RixShadingContext parameter of ComputeOutputParams so that you are assigning an output value for each shaded point.

for (int i=0; i<sctx->numPts; i++)
{
    // Compute some output values based on your input.
    if (style == 1)
    {
        outColor[i] = defaultColor[i];
    }
}

In the simple example above, the style variable was a uniform RtInt input value, so there is only one value for all the points in the shading context. The defaultColor variable was varying instead of uniform, so it a pointer to an array of RtColorRGB values (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

After you have implemented the code for your pattern plugin, you can build it using the commands listed in the Compiling Plugins page. The next step is to test your plugin. To test it, you'll need to make sure prman can find your plugin in the standardrixpluginpath list of directories, which is defined in $RMANTREE/etc/rendermn.ini as:

/standardrixpluginpath          ${RMANTREE}/lib/RIS/pattern:${RMANTREE}/lib/RIS/bxdf:${RMANTREE}/lib/RIS/integrator:${RMANTREE}/lib/RIS/projection

You can add a rendermn.ini file to your HOME directory and modify the standardrixpluginpath value to contain the directory where your pattern plugin is located.

Then you can try to render this RIB file after you have replaced "PxrCustomPattern" with the name of your pattern plugin and connect your pattern's output parameter to one of the input parameters of the PxrDiffuse Bxdf:

Display "patternTest" "framebuffer" "rgba"
Quantize "rgba" 255 0 255 0
Format 128 128 1
Projection "perspective" "fov" [45]
Hider "raytrace" "string integrationmode" ["path"]
Integrator "PxrPathTracer" "integrator"

WorldBegin

    AttributeBegin
        Attribute "identifier" "name" ["sphere1"]
        Translate 0 0 2.75

        Pattern "PxrCustomPattern" "customPattern"

        Bxdf "PxrDiffuse" "smooth"
            "reference color diffuseColor" "customPattern:outColor"
        Sphere 1.0 -1.0 1.0 360.0
    AttributeEnd

WorldEnd

Creating a Pattern args File

If you would like RenderMan for Maya or Katana to recognize your pattern plugin and provide a user interface for changing input parameters and connecting output parameters to other nodes, then you will need to create an args file for your pattern. The args file defines the input and output parameters in XML so that tools like RMS or Katana can easily read them, discover their type, default values, and other information used while creating the user interface for the pattern node.

The args file format is described in the Katana Technical Guide and there are also example args files for the RPS pattern plugins in the/lib/RIS/pattern/Args/ directory of your RenderMan Pro Server installation.