API Guide > Writing a Deformer Node >

# Deformer Node Example

This section describes the offsetNode plug-in, which is an example of a deformer node. This plug-in is available through the Maya API Devkit.

Implementing the Proxy Deformer Node

The offset class inherits from MPxDeformerNode and defines a number of virtual methods such as deform().

    class offset : public MPxDeformerNode
    {
    public:
        offset();
        virtual				~offset();
        static void*		creator();
        static MStatus	 	initialize();
        // deformation function
        //
        virtual MStatus 		deform(MDataBlock& 		block,
            MItGeometry& 	iter,
            const MMatrix& 	mat,
            unsigned int		multiIndex);
        virtual MObject&			accessoryAttribute() const;
        virtual MStatus			accessoryNodeSetup(MDagModifier& cmd);
        public:
        static MObject offsetMatrix; 	// offset center and axis

        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, "Autodesk", "3.0", "Any");
        result = plugin.registerNode( "offset", offset::id, offset::creator,
                                      offset::initialize, MPxNode::kDeformerNode );
        return result;
    }

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

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

Implementing the offsetNode

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

    MStatus offset::initialize()
    {
        MFnMatrixAttribute mAttr;
        offsetMatrix=mAttr.create( "locateMatrix", "lm");
        mAttr.setStorable(false);
        mAttr.setConnectable(true);
        ddAttribute( offsetMatrix);
        attributeAffects( offset::offsetMatrix, offset::outputGeom );
        return MStatus::kSuccess;
    }

Deform Method

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

In the offset class, the deform() method deforms a point with a squash 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.

    MStatus
    offset::deform( MDataBlock& block,
    		MItGeometry& iter,
    		const MMatrix& /*m*/,
    		unsigned int multiIndex)
    {
        MStatus returnStatus;
        MDataHandle envData = block.inputValue(envelope, &returnStatus);
        if (MS::kSuccess != returnStatus) return returnStatus;
        float env = envData.asFloat();
        MDataHandle matData = block.inputValue(offsetMatrix, &returnStatus );
        if (MS::kSuccess != returnStatus) return returnStatus;
        MMatrix omat = matData.asMatrix();
        MMatrix omatinv = omat.inverse();
        for ( ; !iter.isDone(); iter.next()) {
            MPoint pt = iter.position();
            pt *= omatinv;
            float weight = weightValue(block,multiIndex,iter.index());
            //offset algorithm
            pt.y = pt.y + env*weight;
            pt *= omat;
            iter.setPosition(pt);
        }
        return returnStatus;
    }

The weightValue() method above returns the weight value in the geometry.

The weight value for each vertex, CV or lattice point is obtained through the weightValue() method with the multi-index passed to the method. This value is then incorporated into the offset algorithm to perform the desired deformation.

Implementing Accessory Nodes

The accessoryNodesetup() method creates and attaches an additional node to the deformer node. In this example, a locator is created and its matrix attributes are connected to the matrix input of the offset node.

    MStatus
    offset::accessoryNodeSetup(MDagModifier& cmd)
    {
        MStatus result;
        MObject objLoc = cmd.createNode(MString("locator"),
    				                	MObject::kNullObj,
                    					&result);
        if (MS::kSuccess == result) {
            MFnDependencyNode fnLoc(objLoc);
            MString attrName;
            attrName.set("matrix");
            MObject attrMat = fnLoc.attribute(attrName);
            result = cmd.connect(objLoc,attrMat,this->thisMObject(),
                 			 offset::offsetMatrix);
        }
        return result;
    }

The accessoryAttribute() method returns the attribute that is connected to the accessory shape, which in this case is offset::offsetMatrix. If the accessory shape is deleted, the deformer node is automatically deleted as well.

    MObject&
    offset::accessoryAttribute() const
    {
        return offset::offsetMatrix;
    }

Other methods

There are several other methods in this class will allow:

- listen to important modification events
- handle special case during set editing of points (reconnect using old input/output indices if all points are deleted from the set and then added back in)