Create a fragment renderer plug-in example

A viewRenderOverrideFromFragments example plug-in is available which demonstrates the use of a set of APIs that allow you to use scripted fragment and fragment graphs to render the scene and any desired post effects. Script fragments are the building blocks used internally by Maya for standard viewport rendering effects, and are located in a series of .xml files in the bin/ScriptFragment folder of your Maya installation directory.

These APIs allow you to reuse, modify and extend the Maya viewport and hardware renderer by combining Maya's own standard building blocks with your own.

The example plug-in does the following:

Refer to pyGroundReflectionRenderer.py for the plug-in example.

This example creates a Ground Reflections renderer in the Renderer viewport panel menu. When you switch to the Ground Reflections renderer, the viewport updates to render your object and its reflection.

NOTE:

Before you load the example, you must set the path to the plug-in in the initializePlugin function of the pyGroundReflectionRenderer.py file (line 242).

Fragment xml files are provided in the ScriptFragment directory of the viewRenderOverrideFromFragments plug-in folder. The main fragment graph for this render is GroundReflections.xml. The provided .xml files must be in your shader search path.

The initializePlugin function of the plug-in code also adds the Shaders directory of this plug-in to the shader search path.

To access the fragment manager and add a new fragment graph, call MRenderer.getFragmentManager() as follows:

omr.MRenderer.getFragmentManager().addFragmentGraphFromFile("GroundReflections.xml")

Create your scene render using an MSceneRender and provide the name of the fragment graph (in this case, “GroundReflections”):

class FragmentSceneRender(omr.MSceneRender):
    def __init__(self, name):
        super(FragmentSceneRender, self).__init__(name, "GroundReflections")

Create an MRenderOverride to create the fragment renderer, and register it by calling:

omr.MRenderer.registerOverride(fragmentRenderer)

When you create the MRenderOverride, you provide a list of MRenderOperations, one of which is the custom render operation, which is derived from MSceneRender:

class FragmentRenderOverride(omr.MRenderOverride):

    def __init__(self, name):
        self.operatioIndex = 0
        self.operations =  [FragmentSceneRender("sceneAndGroundReflections"),
                           omr.MHUDRender(),
                           omr.MPresentTarget("present")]

When overriding the preSceneRender function, call MSceneRender::getParameters() to obtain the block of render parameters. See MRenderParameters.

def preSceneRender(self, context):
    params = self.getParameters()

Create an options node, after checking that one doesn’t already exist:

optionsNodeName = 'groundReflectionOptions'
optionObj = nameToNode(optionsNodeName)
if optionObj is None:
    optionObj = nameToNode(cmds.createNode(RenderOverrideOptions.kTypeName, name=optionsNodeName, skipSelect=True))

You can then obtain the plugs from the options node, and call MRenderParameters::setParameter() to pass the values to the render fragment used by the custom MSceneRender (custom scene render operation).

if optionObj is not None:
    # set the fragment's enabled input
    optionPlug = om.MPlug(optionObj, RenderOverrideOptions.enableReflections)
    if optionPlug is not None:
        enabled = getBoolPlugValue(optionPlug)
        params.setParameter('EnableReflection', enabled)

The GroundReflections fragment graph contains fragments such as DepthTarget, as well as other fragment graphs such as ReflectionPass which contains the fragment graph Reflection_Renderer, which contains fragments such as simpleBlitScript, MayaShadedBeauty, DrawPreUIOption, and so forth. It also uses the hard-coded C++ procedural fragment VE_ReflectCamera.

NOTE: The ReflectionPass fragment graph is simply a default fragment graph that has been renamed for clarity. The sub-fragments that it consists of are used in Maya’s standard scene renderer.

To set an effect, its parameters and its associated textures

Some of the fragments in the example fragment graph are scripted fragments. These are leaf fragments in the graph that contain the commands used to execute the rendering operation. Some of these commands allow you to assign effects for the pass, and control the effects parameters.

  1. Use the SetEffect command to set the effect.

    Refer to VE_PlanarReflection_RenderFragment.xml for example usage of these commands.

    <SetEffect name="DilateH" path="DistanceDilate" technique="DilateHoriz" />
    <SetEffectParameter effect="DilateH" name="gAmount" value="_UseDistanceDilate_Amount" />
    <SetTexture effect="DilateH" name="gSourceTex" value="PointClamp" texture="@DistanceMap" />
    <SetEffectParameter effect="DilateH" name="gSourceSamp" value="PointClamp" />
    <SetTarget index="0" value="tempDilate" />
    <Render name="Quad" />

    An effect is the equivalent of an instance of a non-fragment MShaderInstance, but it cannot be used directly in a script. The name attribute is the name used to refer to this effect. The path attribute is the path and name of the effects file. It is not necessary to provide a file extension, as Maya will look up the appropriate extension based on the device being used; for example, .fx for DX11, .ogsfx for Core Profile and .cgfx for non-core profile OpenGL. The technique attribute refers to the technique in the effects file that should be used, as there could be more than one in the single file.

  2. Set your effect values using the SetEffectParameter command, and the texture used by the effect using the SetTexture command.

    If the shaders you are referring to use macros, you can also set the macrolist value to control how the shader is compiled.

    <SetEffect name="BlurH" path="Blur" technique="BlurHoriz" macrolist="BLUR_AMOUNT=12" />
  3. Call this command at the end of the script to restore the original Viewport 2.0 override effect. When the SetEffect command is used, it works by setting a local override effect in Viewport 2.0.
    <RestoreOverrideEffect />