Shapes which require visual feedback and manipulation of attributes, such as control point based shapes, must have components associated with those attributes. Shapes such as polygonal meshes or spline surfaces have control vertices which can be selected and manipulated. These control vertices exist as attributes on the shape which are exposed interactively in Maya by representing them as components.
Components are objects (MObjects) which contain two pieces of information, the type of component and the index values or range. An example is a vertex component for a mesh shape where vtx[0] represents vertex 0 of the mesh and vtx[0:7] represents the first 8 vertices of the mesh.
The classes used for creating, editing, and querying components are:
Components fall into three categories based upon the dimensions of the index. The types are single, double, and triple indexed. Examples of these types are mesh vertices (single indexed), NURBS surface CVs (double indexed), and lattice points (triple indexed).
Components can be marked as complete, meaning the component represents a complete set of indices from 0 to numElements-1.
If you want to create a surface shape that supports components, the MPxComponentShape class is a better starting point than the MPxSurfaceShape class. MPxComponentShape is derived from MPxSurfaceShape and provides the basic functionality for users to work with shapes that support components.
If you need to edit the user interface aspects of the shape, derive from the MPxSurfaceShapeUI class. This class allows drawing and interactive selection of any components in a shape.
In Maya, components are specified as strings. Each type of component has a different string name. In the API, components are MObjects distinguished by their API type (see MFn.h). For example, a mesh vertex component can be specified in Maya as vtx[0], and in a plug-in it is represented as an MObject with apiType MFn::kMeshVertComponent. The index information can be extracted using an MFnComponent derived class.
To associate (or map) a component with one of your shapes attributes, you must choose one of Maya’s existing component types and override MPxSurfaceShape::componentToPlugs to convert component types to plugs.
The following is an example of associating a mesh vertex component with the mControlPoints attribute of a shape:
void yourShape::componentToPlugs( MObject& component, MSelectionList& list )const { if ( component.hasFn(MFn::kMeshVertComponent) ) { MFnSingleIndexedComponent fnVtxComp( component ); MObject thisNode = thisMObject(); MPlug plug( thisNode, mControlPoints ); int len = fnVtxComp.elementCount(); for ( int i = 0; i < len; i++ ) { MPlug vtxPlug = plug.elementByLogicalIndex( fnVtxComp.element(i) ); list.add( vtxPlug ); } } }
Attributes can be specified as strings in MEL. Your shape must be able to validate these strings to ensure that proper names, indices etc. have been given. The method MPxSurfaceShape::matchComponent is used for this purpose.
virtual MatchResult matchComponent( const MSelectionList& item, const MAttributeSpecArray& spec, MSelectionList& list );
This method validates component names and indices which are specified as a string and adds the corresponding component to the passed in selection list. Select commands such as select shape1.vtx[0:7] are validated with this method and the corresponding component is added to the selection list.
The attribute specification (MAttributeSpec) is a class that provides convenient access to all of the information about how attributes are specified. This includes attribute names, indices, and ranges.
For Maya to get and set the position of components you must define an iterator for your geometry by deriving from the class MPxGeometryIterator.
A geometry iterator is used by the translate/rotate/scale manipulators to determine where to place the manipulator when components are selected.
Deformers also require a geometry iterator with overridden setPoint and point methods in order to deform the points your shape.
In general, you will want to override the following methods from MPxGeometryIterator:
MPxGeometryIterator( void * userGeometry, MObjectArray & components ); MPxGeometryIterator( void * userGeometry, MObject & components ); virtual void reset(); virtual MPoint point() const; virtual void setPoint( const MPoint & ) const;
You must override the following functions of MPxSurfaceShape to associated an iterator with your shape:
virtual MPxGeometryIterator* geometryIteratorSetup( MObjectArray&, MObject&, bool ); virtual bool acceptsGeometryIterator( bool writeable ); virtual bool acceptsGeometryIterator( MObject&, bool, bool );
To support the translate, rotate and scale tools, you must override the method MPxSurfaceShape::transformUsing. The function takes a matrix and array of components as arguments. The matrix specifies the transformation that is being applied and the components specify the attribute indices that are being transformed.
For shapes with large numbers of control vertices, it can be prohibitively slow relying on Maya’s compute mechanism for setting attribute values. The method MPxNode::forceCache can be used in these situations to gain direct access to a node’s datablock and to get/set attribute values directly without going through compute. Special care must be taken to ensure that all attributes that depend on the ones you are changing also get updated. For instance, if the vertices of a mesh are changed, then the normals should also be updated as well as the bounding box. The method, vertexOffsetDirection, must be overridden if the Move tool is to work in move normal mode.