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']
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:
bool MPxCustomEvaluator::markIfSupported(const MEvaluationNode* node)
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'