Deformer Node Example

This section describes the yTwistNode plug-in, which is an example of a deformer node. This plug-in is available through the Maya Developer Kit.

Implementing the Proxy Deformer Node

The ytwist class inherits from MPxGeometryFilter and defines a single virtual method, deform().

class yTwist : public MPxGeometryFilter
{
public:
                         yTwist();
    virtual              ~yTwist();

    static  void*        creator();
    static  MStatus      initialize();

    // deformation function
    virtual MStatus      deform(MDataBlock&  block,
                         MItGeometry&        iter,
                         const MMatrix&      mat,
                         unsigned int        multiIndex);

public:
    // yTwist attributes
    static  MObject     angle;          // angle to twist    
    static  MTypeId        id;

private:

};

Initializing the Plug-in

The new deformer node must be registered with the registerNode() method of MFnPlugin when initializing the plug-in.

MStatus initializePlugin( MObject obj )
{
	MStatus result;
	MFnPlugin plugin( obj, PLUGIN_COMPANY, "3.0", "Any");
	result = plugin.registerNode( "yTwist", yTwist::id, yTwist::creator, 
								  yTwist::initialize, MPxNode::kDeformerNode );
	return result;
}

To remove the deformer node, you must deregister the plug-in with a call to the deregisterNode() method of MFnPlugin.

MStatus uninitializePlugin( MObject obj)
{
    MStatus result;
    MFnPlugin plugin( obj );
    result = plugin.deregisterNode( offset::id );
    return result;
}

Adding Deformer Attributes

The initialize() method is used to add and configure new attributes to proxy nodes. In the example below, the angle attribute is added to the node and is made connectable. Any changes to the input attribute angle affect the output attribute outputGeom.

MStatus yTwist::initialize()
{
	// local attribute initialization
	//
	MFnNumericAttribute nAttr;
	angle=nAttr.create( "angle", "fa", MFnNumericData::kDouble );
	    nAttr.setDefault(0.0);
	    nAttr.setKeyable(true);
	addAttribute( angle); 

	// affects
	//
    attributeAffects( yTwist::angle, yTwist::outputGeom );

	return MS::kSuccess;
}

Deform Method

The deform() method implements an algorithm to compute the deformation.

In the yTwist class, the deform() method deforms a point with a yTwist algorithm. The geometry data is extracted from the datablock by MDataHandle and deforms each point of the geometry. The deform() method returns a MS::kSuccess to indicate a successful deformation. If not, the deformation encountered problems, such as invalid data input or insufficient memory.

There are four required arguments for this method. The block argument refers to the node’s datablock where information on the geometry is stored. The iter argument is the iterator for the geometry to be deformed. The m is the matrix used to transform points from local space to world space. The multiIndex is the index of the requested output geometry. In the yTwistNode example, only the block and the iter arguments are used.

MStatus
yTwist::deform( MDataBlock& block,
				MItGeometry& iter,
				const MMatrix& /*m*/,
				unsigned int /*multiIndex*/)

{
	MStatus status = MS::kSuccess;
	
	// determine the angle of the yTwist
	//
	MDataHandle angleData = block.inputValue(angle,&status);
	McheckErr(status, "Error getting angle data handle\n");
	double magnitude = angleData.asDouble();

	// determine the envelope (this is a global scale factor)
	//
	MDataHandle envData = block.inputValue(envelope,&status);
	McheckErr(status, "Error getting envelope data handle\n");	
	float env = envData.asFloat();	

	// iterate through each point in the geometry
	//
	for ( ; !iter.isDone(); iter.next()) {
		
		MPoint pt = iter.position();

		// do the twist
		//
		double ff = magnitude*pt.y*env;
		if (ff != 0.0) {
			double cct= cos(ff);
			double cst= sin(ff);
			double tt= pt.x*cct-pt.z*cst;
			pt.z= pt.x*cst + pt.z*cct;
			pt.x=tt;;
		}

		iter.setPosition(pt);
	}
	return status;
}

In this example, no per-vertex weighting is used by the deformer. For an example of per-vertex weighting, see the Developer Kit example offsetNode, which inherits from MPxDeformerNode, and uses weightValue() to obtain the weight value for each vertex, CV or lattice point. This example also illustrates how to implement accessory nodes.

Other methods

There are several other methods in MPxGeometryFilter that allow the plug-in to: