Custom MPxDeformer node slowness when using keyframes
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Hello, I'm running some basic tests to understand the behaviour and performance of the custom attributes in a MPxDeformerNode. I have created a MFnNumericAttribute that is a float, and then inside the deform method I do nothing (this is for testing purposes only). The new attribute will affect the outputGeometry attribute only.
In my scene, I have 1 sphere with 1 million vertices. And then, I connect my custom deformer node to the sphere to trigger the deform method. So, I realised that if the attribute contains a constant value the scene is running at 600 fps it is normal because the deform is not triggered every frame. Then, if I connect the attribute to a floatConstant node with 1 or more keyframes set, then the performance falls to 60 fps. (Custom_Deformer.gif)
I mean, I understand that the attribute gets dirty and the deform method is executed every frame. But then, I took a look to the native BlendShape deformer node and performing a deformation using the same geometry is running at 200 fps with keyframes. (BlendShapeMaya.gif)
How can I avoid getting that performance reduction when using keyframes in the input attribute? I was searching in the API documentation but I didn't find anything about this behaviour. Even testing with the given MPxGPUDeformer example, as soon as I connect an attribute with keyframes, the framerate falls too much.
Thanks for your attention.
This is the code I'm using for this test:
# You have to use maya API 1.0 because MPxDeformerNode is not available in 2.0.
import maya.OpenMaya as OpenMaya
import maya.OpenMayaMPx as OpenMayaMPx
# Set globals to the proper cpp cvars. (compatible from maya 2016)
kInput = OpenMayaMPx.cvar.MPxGeometryFilter_input
kInputGeom = OpenMayaMPx.cvar.MPxGeometryFilter_inputGeom
kOutputGeom = OpenMayaMPx.cvar.MPxGeometryFilter_outputGeom
kEnvelope = OpenMayaMPx.cvar.MPxGeometryFilter_envelope
kGroupId = OpenMayaMPx.cvar.MPxGeometryFilter_groupId
class templateDeformer(OpenMayaMPx.MPxDeformerNode):
"""Template deformer node."""
# Replace this with a valid node id for use in production.
type_id = OpenMaya.MTypeId(0x00001)
type_name = "templateDeformer"
@classmethod
def initialize(cls):
"""Initialize attributes and dependencies."""
# Add any input and outputs to the deformer here, also set up
# dependencies between the in and outputs. If you want to use another
# mesh as an input you can use an MFnGenericAttribute and add
# MFnData.kMesh with the addDataAccept method.
numericAttributeFn = OpenMaya.MFnNumericAttribute()
cls.sampleInAttribute = numericAttributeFn.create( 'myInputAttribute', 'i',
OpenMaya.MFnNumericData.kFloat,
0.0 )
cls.addAttribute( cls.sampleInAttribute )
cls.attributeAffects( cls.sampleInAttribute, kOutputGeom )
pass
@classmethod
def creator(cls):
"""Create instance of this class.
Returns:
templateDeformer: New class instance.
"""
return cls()
def __init__(self):
"""Construction."""
OpenMayaMPx.MPxDeformerNode.__init__(self)
def deform(
self,
data_block,
geometry_iterator,
local_to_world_matrix,
geometry_index
):
"""Deform each vertex using the geometry iterator.
Args:
data_block (MDataBlock): the node's datablock.
geometry_iterator (MItGeometry):
iterator for the geometry being deformed.
local_to_world_matrix (MMatrix):
the geometry's world space transformation matrix.
geometry_index (int):
the index corresponding to the requested output geometry.
"""
# This is where you can add your deformation logic.
# you can access the mesh this deformer is applied to either through
# the given geometry_iterator, or by using the getDeformerInputGeometry
# method below.
# You can access all your defined attributes the way you would in any
# other plugin, you can access base deformer attributes like the
# envelope using the global variables like so:
# envelope_attribute = kEnvelope
# envelope_value = data_block.inputValue( envelope_attribute ).asFloat()
a = 0
def getDeformerInputGeometry(self, data_block, geometry_index):
"""Obtain a reference to the input mesh.
We use MDataBlock.outputArrayValue() to avoid having to recompute the
mesh and propagate this recomputation throughout the Dependency Graph.
OpenMayaMPx.cvar.MPxGeometryFilter_input and
OpenMayaMPx.cvar.MPxGeometryFilter_inputGeom (Maya 2016)
are SWIG-generated variables which respectively contain references to
the deformer's 'input' attribute and 'inputGeom' attribute.
Args:
data_block (MDataBlock): the node's datablock.
geometry_index (int):
the index corresponding to the requested output geometry.
"""
inputAttribute = OpenMayaMPx.cvar.MPxGeometryFilter_input
inputGeometryAttribute = OpenMayaMPx.cvar.MPxGeometryFilter_inputGeom
inputHandle = data_block.outputArrayValue( inputAttribute )
inputHandle.jumpToElement( geometry_index )
inputGeometryObject = inputHandle.outputValue().child(
inputGeometryAttribute
).asMesh()
return inputGeometryObject
def initializePlugin(plugin):
"""Called when plugin is loaded.
Args:
plugin (MObject): The plugin.
"""
plugin_fn = OpenMayaMPx.MFnPlugin(plugin, "Test", "0.1", "Any")
try:
plugin_fn.registerNode(
templateDeformer.type_name,
templateDeformer.type_id,
templateDeformer.creator,
templateDeformer.initialize,
OpenMayaMPx.MPxNode.kDeformerNode
)
except:
print("failed to register node {0}".format(templateDeformer.type_name))
raise
def uninitializePlugin(plugin):
"""Called when plugin is unloaded.
Args:
plugin (MObject): The plugin.
"""
plugin_fn = OpenMayaMPx.MFnPlugin(plugin)
try:
plugin_fn.deregisterNode(templateDeformer.type_id)
except:
print("failed to deregister node {0}".format(
templateDeformer.type_name
))
raise
(