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.
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: };
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.
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; }
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.
There are several other methods in MPxGeometryFilter that allow the plug-in to: