Custom Evaluator API

The following section describes new API classes and methods to define custom evaluators. Custom evaluators allow control over how the Maya scene is computed.

If you want to create a custom evaluator, you need to define a plug-in that extends the MPxCustomEvaluator class. The following lists the key class methods that you should override.

The Basics

Before new evaluators can be used, they must be registered:

MStatus registerEvaluator(
    // name of the evaluator
    const char *     evaluatorName,  

    // evaluator priority. Higher priority evaluators get 'first-dibs'
    unsigned int     uniquePriority,

    // function pointer to method returning a new evaluator instance 
    MCreatorFunction creatorFunction
)

and deregistered:

MStatus deregisterEvaluator(
    // name of the evaluator
    const char* evaluatorName 
)

using MFnPlugin methods. These functions should be used during plug-in initialization:

MStatus initializePlugin( MObject obj )
{
    MFnPlugin plugin( obj, PLUGIN_COMPANY, "3.0", "Any");
    MStatus status = plugin.registerEvaluator(
        "SimpleValuator", 
        40 /* unused priority */, 
        simpleEvaluator::creator);
    if (!status) 
        status.perror("registerEvaluator");
    return status;
}

and uninitialization:

MStatus uninitializePlugin( MObject obj)
{
    MFnPlugin plugin( obj );
    MStatus status = plugin.deregisterEvaluator( "SimpleValuator" );
    if (!status)
        status.perror("deRegisterEvaluator");
    return status;
}

as illustrated above.

Once the plug-in has been loaded, you can use Python or MEL commands to enable:

import maya.cmds as cmds
cmds.evaluator(enable=True, name='SimpleEvaluator')

# Result: False #

disable:

cmds.evaluator(enable=False, name='SimpleEvaluator')

# Result: True # 

and query information about evaluators:

print cmds.evaluator(query=True)

[u'dynamics', ... u'SimpleEvaluator']
NOTE:The evaluator command returns the previous state of the evaluator. This command fails if the evaluator cannot be enabled. See the Technical Documentation section of the Maya Help for more information on this command.

To view the priorities of all loaded evaluators, use the priority flag on the evaluator command:

for evaluatorName in cmds.evaluator():
    print "%-25s : %d" % (
        evaluatorName,
        cmds.evaluator(name=evaluatorName, query=True, priority=True))

dynamics                 : 103000
ikSystem                 : 102000
timeEditorCurveEvaluator : 101000
disabling                : 100000
GPUOverride              : 5000
transformFlattening      : 3000
reference                : 1000
SimpleValuator           : 40

API Reference

This section provides more detail on different MPxCustomEvaluator API methods.

Claiming clusters

During EG partitioning, each evaluator can claim evaluation nodes, using the:

method. It is safe to cause evaluation in this call, but it increases partitioning and evaluation time. It is up to the developer to decide whether evaluation is required (call .outputValue/.outputArrayValue) or whether the previously evaluated datablock values can be re-used (call .inputValue/.inputArrayValue). If multiple evaluators mark a specific node, priority is used to determine which evaluator is assigned a node at run-time. For example, if you have two evaluators, A and B, mark node C of interest, and if evaluator A has priority 100, and evaluator B has priority 10, then during graph evaluation, evaluator A is assigned the cluster with node C.

Scheduling

To determine if an evaluator can evaluate clusters in Parallel, use:

MCustomEvaluatorClusterNode::SchedulingType schedulingType(
    // a disjoint set of nodes on a custom evaluator layer
    const MCustomEvaluatorClusterNode * cluster 
)

where,

Scheduling Type Details
kParallel any number of nodes of the same type can run in parallel
kSerial all nodes of this type should be chained and executed sequentially
kGloballySerial only one node of this type can be run at a time
kUntrusted nothing else can execute with this node since it is not possible to predict what will happen

During EG scheduling:

bool MPxCustomEvaluator::clusterInitialize(
    const MCustomEvaluatorClusterNode* cluster // evaluation cluster node
)

can be used to do any required cluster preparation. The pointer to the cluster remains valid until graph invalidation, such as when the scene topology changes.

Before the cluster is deleted,

void MPxCustomEvaluator::clusterTerminate(
    const MCustomEvaluatorClusterNode* cluster // the cluster to terminate
)

is called to allow needed cleanup, such as releasing evaluator-specific resources. It's up to the custom evaluator to decide if it wants to clear its internal representation.

Execution

There are 3 main methods used during execution.

Prior to graph execution, the EM calls:

void MPxCustomEvaluator::preEvaluate(
    const MEvaluationGraph* graph // the graph about to be evaluated
)

during execution, the EM calls:

void MPxCustomEvaluator::clusterEvaluate(
    const MCustomEvaluatorClusterNode* cluster // the cluster to be evaluated
)

You will only receive clusters that belong to this evaluator. This call always happens after clusterInitialize and never after clusterTerminate. Finally,

void MPxCustomEvaluator::postEvaluate(
    const MEvaluationGraph* graph // the graph that was evaluated
)

is called just after a graph evaluation finishes.

Simple Evaluator API example

Refer to the simpleEvaluator plug-in in the Developer Kit for an example that limits evaluation by caching previous results.

Useful script

This simple script checks which nodes are associated with a given evaluator:

def printClusters(evaluatorName):
    """
    Print out any clusters of nodes captured by the specified evaluator.
    """
    evaluators = cmds.evaluator( query=True )
    if evaluatorName in evaluators:
        try:
            print cmds.evaluator( 
                query=True, 
                name=evaluatorName, 
                clusters=True )[1:]
        except KeyError:
            print 'No clusters in the specified evaluator'
    else:
        print 'The specified evaluator is not active. Use the "evaluator" command to activate it'