Getting the Input Geometry MObject

Often when we are writing a deformer, we want access to the input geometry MObject in order to get information such as vertex normals, uvs, etc. In the MPxDeformerNode::deform function, all we have available is the MItGeometry iterator which only gives us positional information. We can get the MObject from the datablock but we have to be careful not to trigger any unnecessary dependency graph calculations.
MStatus SomeDeformer::deform( MDataBlock& data, MItGeometry& itGeo, const MMatrix &localToWorldMatrix, unsigned int geomIndex )
{
    MStatus status;
    MArrayDataHandle hInput = data.outputArrayValue( input, &status );
    CHECK_MSTATUS_AND_RETURN_IT( status )
    status = hInput.jumpToElement( geomIndex );
    CHECK_MSTATUS_AND_RETURN_IT( status )
    MObject oInputGeom = hInput.outputValue().child( inputGeom ).asMesh();
    MFnMesh fnInputMesh( oInputGeom );
}
def deform(self, data, itGeo, localToWorldMatrix, geomIndex ):
    inputAttribute = OpenMayaMPx.cvar.MPxDeformerNode_input
    inputGeom = OpenMayaMPx.cvar.MPxDeformerNode_inputGeom
    hInput = data.outputArrayValue( inputAttribute )
    hInput.jumpToElement( geomIndex )
    oInputGeom = hInput.outputValue().child( inputGeom ).asMesh()
    fnInputMesh = OpenMaya.MFnMesh( oInputGeom )
In MPxDeformerNode, the compute method is already implemented for us. The compute method gets the input geometry for us, creates the geometry interator, and calls the deform method, which is what we implement. Notice when I get the data handles, I use outputArrayValue and outputValue. This prevents Maya from triggering a dirty propagation. If I were to use inputArrayValue and inputValue, Maya would recalculate the input geometry, causing an unnecessary graph evaluation since this was already done in the compute method.

4 thoughts on “Getting the Input Geometry MObject”

severum June 1, 2012 at 2:55 am

Hi.
You know Maya API and I think can help.
When OpenMP are using appear necessity to get all the point positions and weights before calculations.
(Sorry for my bad English)

First is simple
iter.allPositions(verts)
iter.setAllPositions(verts);

getAllWeight method does not exists.
In addition, “Deformer Set” can contain not all vertices.
I had looked inside MpxDeformerNode::weightValue (OpenMayaAnim.dll), that a used MFnGeometryFilter and MFnWeightGeometryFilter.
(http://www.youtube.com/watch?v=BPM6dhswIVE)

When I am try to call MfnSet.getMembers DAG calculation is happens (message like «Warning: line 0: Cycle on..» and crush)

Sample Code:

MStatus wtest::compute(const MPlug& plug, MDataBlock& block)
{
MStatus stat;

float env = block.inputValue(envelope, &stat).asFloat();
if(env==0.0) return MStatus::kSuccess;

if (plug.attribute() != outputGeom) return MStatus::kUnknownParameter;

MObject thisNode = this->thisMObject();
MFnDependencyNode thisDepNode(thisNode);
//cout << "compute: " << thisDepNode.name().asChar() << endl;

unsigned int plugIndex = plug.logicalIndex();
//cout << "plugIndex: " << plugIndex << endl;

MPlug inPlug(thisNode, input);

inPlug.selectAncestorLogicalIndex(plugIndex, input);

MDataHandle hInput = block.inputValue(inPlug);

MDataHandle hInputGeom = hInput.child(inputGeom);

MDataHandle hGroupId = hInput.child(groupId);
unsigned int valueGroupId = hGroupId.asLong();
//cout << "valueGroupId: " << valueGroupId << endl;

MFnWeightGeometryFilter weightGeometryFilter(thisNode, &stat);
//cout<<"Deformer: "<< weightGeometryFilter.name().asChar() <<endl;

MObject deformSet = weightGeometryFilter.deformerSet(&stat);

MFnSet deformFnSet(deformSet, &stat);
//cout << "deformFn: " << deformFnSet.name().asChar() << endl;

// Warning: line 0: Cycle on 'wtest1.outputGeometry[1]' may not evaluate as expected. (Use 'cycleCheck -e off' to disable this warning.)
MSelectionList deformerSetList;
stat = deformFnSet.getMembers(deformerSetList, true);
//cout << "deformerSetList: " << deformerSetList.length() << endl;

//…
//MFloatArray weightsArray();
//stat = weightGeometryFilter.getWeights(plugIndex, weightsArray);

//output geometry
MDataHandle hOutputGeom = block.outputValue(plug);
hOutputGeom.copy(hInputGeom);

//…

return stat;
}

Poor but the working (without crush) version of the code:
// store weights
MFloatArray vertWeights;
while( !iter.isDone() )
{
vertWeights.append( weightValue( block, nGeomIndex, iter.index() ) );
iter.next();
}
iter.reset();
Using of an iterator to get weights kills all the benefits of OpenMP

How it works ??
My email severum@bk.ru

ppjordan January 3, 2014 at 8:27 pm

chad–
(from above)
MArrayDataHandle hInput = data.outputArrayValue( input, &status );

it seems counter intuitive to be using “outputArrayValue” rather than “inputArrayValue”

thanks!

John Hamilton December 26, 2015 at 1:15 am

Hello Chad,
I have been taking your course online (awesome), and although you cover the C++ approach, I was wondering if you could answer a python approach question?

I want to know if it’s possible to trigger an event when an attribute becomes dirty. In my case, I want a sphere’s translate values to move the same as a (let’s just say) cube’s translations as it’s being moved. Basically a connection node without the node.

Thank you for your time and your course!!! Great value.

-J

Chad January 5, 2016 at 7:45 pm

@ppjordan It’s getting an output datahandle to the input attribute. The outputArrayValue prevents the geometry from being evaluated in the DG.

@John You can use a scriptJob or callback that gets called whenever an attribute changes.

Leave A Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

<code> For inline code.
[sourcecode] For multiline code.