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:
};
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;
}
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);
addAttribute( offsetMatrix);
attributeAffects( offset::offsetMatrix, offset::outputGeom );
return MStatus::kSuccess;
}
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.
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;
}