Maya C++ API Programming Tips

How to get the value of the attribute at the specified time

int frame = 101;
MPlug plg( thisMObject(), "abc" );
MDGContext ctx( MTime( frame, MTime.uiUnit() ) );
double value = 0.0;
plg.getValue( value, ctx );

How to get the data block outside compute() member function

MDataBlock block = forceCache();

How to get playback time interval

const double dt = AnimControl::playbackBy();

How to update DG node every frame without the input connection from time1

class MyNode{
private:
  MCallbackId timeChangeCallbackId;
public:
  void addedToModelCB();
  void removedFromModelCB();
  void update();
  ...
};
 
MyNode::MyNode{
  ...
  timeChangeCallbackId = 0;
  ...
}
 
static void TimeChangeCallback( MTime& time, void* clientData ){
  reinterpret_cast<ZShape*>(clientData)->update();
}
 
static void NodeAddedToModel( MObject& nodeObj, void* clientData ){
  MFnDependencyNode nodeFn( nodeObj );
 
  MyNode* nodePtr = (MyNode*)nodeFn.userNode();
  if( !nodePtr ) { return; }
 
  nodePtr->addedToModelCB();
}
 
static void NodeRemovedFromModel( MObject& nodeObj, void* clientData ){
  MFnDependencyNode nodeFn( nodeObj );
 
  MyNode* nodePtr = (MyNode*)nodeFn.userNode();
  if( !nodePtr ) { return; }
 
  nodePtr->removedFromModelCB();
}
 
void MyNode::postConstructor(){
  MModelMessage::addNodeAddedToModelCallback( thisMObject(), NodeAddedToModel );
  MModelMessage::addNodeRemovedFromModelCallback( thisMObject(), NodeRemovedFromModel );
}
 
void MyNode::addedToModelCB(){
  timeChangeCallbackId = MDGMessage::addTimeChangeCallback( TimeChangeCallback, this );
}
 
void MyNode::removedFromModelCB(){
  if( timeChangeCallbackId ){
    MDGMessage::removeCallback( timeChangeCallbackId );
    timeChangeCallbackId = 0;
  }
}

How to handle the multiple outputs of a DG node

MStatus MyNode::initialize(){
  MFnNumericAttribute nAttr;
 
  outputsObj = nAttr.create( "outputs", "outputs", MFnNumericData.kFloat, 0.f );
  nAttr.setArray( true );
  addAttribute( outputsObj );
  ...
}
 
MStatus MyNode::compute( const MPlug& plug, MDataBlock& data ){
  if( plug != outputsObj ) { return MS::kUnknownParameter; }
 
  MArrayDataHandle outputsHnd = data.outputArrayValue( outputsObj );
 
  const int nOutputs = (int)outputsHnd.elementCount();
 
  for( int i=0; i<100; ++i ){
    outputsHnd.jumpToElement( i );
    outputsHnd.outputValue().set( i );
  }
 
  outputsHnd.setAllClean();
  return MS::kSuccess;
}

How to capture the current viewport as an image file

MImage image;
M3dView view = M3dView::active3dView();
view.readColorBuffer( image, true );
image.writeToFile( "snapshot.jpg", "jpg" );

How to save the current frame buffer to a JPG file

GLint viewport[4];
glGetIntegerv( GL_VIEWPORT, viewport );
 
int width = viewport[2];
int height = viewport[3];
int depth = 4;
 
unsigned char* pixels = new unsigned int[width*height*depth];
 
glReadBuffer( GL_FRONT );
glReadPixels( 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels );
 
MImage image;
image.setPixels( pixels, width, height );
image.writeToFile( "snapshot.jopg", "jpg" );
 
delete[] pixels;

How to set the names of a custom DG node and its parent node

void MyNode::postConstructor()
{
  MPxNode::postConstructor();
 
  MObject thisMObj = thisMObject();
  MFnDependencyNode nodeFn;
  nodeFn.setObject( thisMObj );
  nodeFn.setName( "MyNodeShape#" );
}

How to compile my source code conditionally according to the Maya API version

#if MAYA_API_VERSION == 201300
...
#elif MAYA_API_VERSION == 201400
...
#elif MAYA_API_VERSION == 201500
...
#endif

How to get the current Maya version

MString mayaVer = MGlobal::mayaVersion();
int apiVer = MGlobal::apiVersion();

How to avoid the conflict with Cuda

...
#define short2 MAYA_short2
#define short3 MAYA_short3
#define long2 MAYA_long2
#define long3 MAYA_long3
#define int2 MAYA_int2
#define int3 MAYA_int3
#define float2 MAYA_float2
#define float3 MAYA_float3
#define double2 MAYA_double2
#define double3 MAYA_double3
#define double4 MAYA_double4
 
#include &amp;lt;cuda.h&amp;gt;
...

How to set the MFloatPoint from a MPoint

MPoint dp; // double type
MFloatPoint fp; // float type
fp.setCast( dp );

How to get the pixel values of an image

MImage img;
img.readFromFile( "filePathName" ); // load from a file
 
int w=0, h=0; // image width, height
img.getSize( w, h );
int d = img.depth(); // image depth
unsigned char* c = (unsigned char*)NULL;
 
if( img.pixelType() == MImage::kByte ){
  c = img.pixels();
}
 
for( int j=0; j&amp;lt;h; ++j ){
  for( int i=0; i&amp;lt;w; ++i ){
    int idx = d*(i+j*w);
    unsigned char pixelVal[4]; // RGB(d=3) or RGBA(d=4)
 
    for( int k=0; k&amp;lt;d; ++k ){
      pixelVal[k] = c[idx++];
    }
 
    ...
  }
}

How to get the DAG path from a node name

MString nodeName( "nodeName" );
MDagPath dagPath;
MSelectionList sList;
if( MGlobal::getSelectionListByName( nodeName, sList ) ){
  sList.getDagPath( 0, dagPath );
}

How to get the DG node object from a node name

MString nodeName( "nodeName" );
MObject nodeObj;
MSelectionList sList;
if( MGLobal::getSelectionListByName( nodeName, sList ) ){
  sList.getDependNode( 0, nodeObj );
}

How to get the DAG path from a DAG node object

MObject dagNodeObj = ...;
MDagPath dagPath;
MFnDagNode dagFn( dagNodeObj );
dagFn.getPath( dagPath );

How to get the node name from a node object

MObject nodeObj = ...;
MString nodeName;
 
if( nodeObj.hasFn( MFn::kDagNode ) ) {
  MFnDagNode dagNodeFn( nodeObj );
  nodeName = dagNode.fullPathName();
} else if( nodeObj.hasFn( MFn::kDependencyNode ) ) {
  MFnDependencyNode dgNodeFn( nodeObj );
  nodeName = dgNodeFn.name();
}

How to get the parent DAG node object

MObject parentDagNodeObj;
MFnDagNode dagFn( thisMObject() );
MObject obj = dagFn.parent( 0 );
if( !obj.isNull() ){
  parentDagNodeObj = obj;
}

How to get the shape node DAG path from a transform DAG path

MDagPath xformDagPath = ...
MDagPath shapeDagPath = xformDagPath;
shapeDagPath.extendToShape();

How to get the DAG paths of selected mesh shape nodes

MDagPathArray dagPaths;
 
MSelectionList sList;
MGlobal::getActiveSelectionList( sList );
 
MItSelectionList itr( sList, MFn::kMesh );
for( ; !itr.isDone(); itr.next() ){
  MDagPath dagPath;
  itr.getDagPath( dagPath );
  MFnDagNode dagFn( dagPath );
  
  if( dagFn.isIntermediateObject() ) { continue; }
  
  dagPaths.append( dagPath );
}

How to get the all of NURBS curve node objects in the current scene

MObjectArray curveObjs;
MItDag itr( MItDag::kDepthFirst, MFn::kNurbsCurve );
for( ; !itr.isDone(); itr.next() ){
  curveObjs.append( itr.item() );
}

How to get the list of a selected mesh polygons

MIntArray selectedPolygonList;
 
MSelectionList sList;
MGlobal::getActiveSelectionList( sList );
MItSelectionList sItr( sList, MFn::kMeshPolygonComponent );
 
MDagPath dagPath;
MObject componentObj;
sItr.getDagPath( dagPath, componentObj );
 
MFnSingleIndexedComponent sCompFn( componentObj );
sCompFn.getElements( selectedPolygonList );

How to get the all of fields in the current scene

MItDag itr( MItDag::kDepthFirst, MFn::kField );
for( ; !itr.isDone(); itr.next() ){
  MFnField fieldFn( itr.item() );
  ...
}

How to get the local transformation matrix of the current shape node

MObject thisShapeNodeObj = thisMObject();
MFnDagNode thisShapeNodeFn( thisShapeNodeObj );
MObject parentXFormNodeObj = thisShapeNodeFn.parent( 0 );
MFnDagNode parentXFormNodeFn( parentXFormNodeObj );
MMatrix xformMatrix = parentXFormNodeFn.transformationMatrix();

How to get the world matrix of the current shape node

MObject thisShapeNodeObj = thisMObject();
MFnDagNode thisShapeNodeFn( thisShapeNodeObj );
MObject parentXFormNodeObj = thisShapeNodeFn.parent( 0 );
MFnDependencyNode parentXFormNodeFn( parentXFormNodeObj );
MObject worldMatrixObj = parentXFormNodeFn.attribute( "worldMatrix" );
MPlug worldMatrixPlg( parentXFormNodeObj, worldMatrixObj );
worldMatrixPlg = worldMatrixPlg.elementByLogicalIndex( 0 );
worldMatrixPlg.getValue( worldMatrixObj );
MFnMatrixData worldMatrixData( worldMatrixObj );
MMatrix worldMatrix = worldMatrixData.matrix();

How to connect the output plug to the parent automatically when a custom locator node is created

class MyLocator{
  ...
  bool connected;
  ...
};
 
MyLocator::MyLocator(){
  connected = false;
}
 
void MyLocator::draw( M3dView&amp;amp; view, ...){
  if( !connected ){
    MObject thisNodeObj = thisMObject();
    MFnDagNode dagFn( thisNodeObj );
    MObject parentNodeObj = dagFn.parent( 0 );
    dagFn.setObject( parentNodeObj );
    MPlug parentPlg = dagFn.findPlug( "plugName" );
    MPlug outputPlg = MPlug( thisNodeObj, outputObj );
    if( !outputPlg.isConnected() ){
      MDGModifier dgMod;
      dgMod.connect( outputPlg, parentPlg );
      dgMod.doIt();
      connected = true;
    }
  }
  ...
}

How to make a custom locator node un-selectable

void MyLocator::draw( M3dView&amp;amp; view, ...){
  if( view.selectMode() ) { return; }
  ...
}

How to detect which input attribute is changed

MStatus MyCustomNode::compute( const MPlug&amp;amp; plug, MDataBlock&amp;amp; data ){
  if( plug != outputObj ) { return MS::kUnknownParameter; }
 
  bool inputIsChanged = !data.isClean( inputObj );
  float input = data.inputValue( inputObj ).asFloat();
 
  ...
}

Note) It doesn’t work when inputObj is array type.

How to detect whether the current state is batch mode

if( MGlobal::mayaState() == MGlobal::kBatch ){
  ...
}

How to detect whether the current viewport is Viewport 2.0

M3dView view = M3dView::active3dView();
if( view.getRendererName() == M3dView::kViewport2Renderer ){
  ...
}

How not to draw a custom locator node while mouse interactions (>=2015)

void MyLocator::draw( M3dView&amp;amp; view, ...){
  if( MHWRender::MFrameContext::inUserInteraction() 
    || MHWRender::MFrameContext::userChangingViewContext() )
  {
    ...
  }
}

How to draw a text in draw() of a custom locator node

void MyLocator::draw( M3dView&amp;amp; view, ...){
  ...
  view.beginGL();
  view.drawText( MString("text"), MPoint(0,0,0), M3dView::kLeft );
  view.endGL();
  ...
}

How to copy the input mesh to the output mesh in compute() of a custom node

MStatus MyNode::compute( const MPlug&amp;amp; plug, MDataBlock&amp;amp; data )
{
  ...
  MFnMesh newMeshFn;
  MFnMeshData dataCreator;
  MObject newMeshData = dataCreator.create();
  newMeshFn.copy( data.inputValue( inMeshObj ).asMeshTransformed(), newMeshData );
  data.outputValue( outMeshObj ).set( newMeshData );
  ...
}

How to deform the input mesh in compute() of a custom node like such a deformer

MStatus MyNode::compute( const MPlug&amp;amp; plug, MDataBlock&amp;amp; data )
{
  ...
   
  MPointArray deformedPoints = ...
 
  MFnMesh newMeshFn;
  MFnMeshData dataCreator;
  MObject newMeshData = dataCreator.create();
  newMeshFn.copy( data.inputValue( inMeshObj ).asMeshTransformed(), newMeshData );
  newMeshFn.setPoints( deformedPoints );
  data.outputValue( outMeshObj ).set( newMeshData );
 
  ...
}

How to handle array attribute

class MyNode
{
  ...
  MObject valuesObj;
  ...
  MDoubleArray values;
};
 
MObject MyNode::valuesObj;
 
MStatus MyNode::initialize(){
  ...
  valuesObj = tAttr.create( "values", "values", MFnData::kDoubleArray );
  ...
}
 
MStatus MyNode::compute( const MPlug&amp;amp; plug, MDataBlock&amp;amp; data )
{
  ...
 
  // get
  MFnDoubleArrayData arrayData;
  MObject dataObj = data.inputValue( valuesObj ).data();
  arrayData.setObject( dataObj );
 
  int numValues = 100;
 
  // set
  if( arrayData.length() != numValues ){
    MDoubleArray array( numValues, 0.0 );
    dataObj = arrayData.create( array );
    data.outputValue( valuesObj ).set( dataObj );
  }
 
  ...
}
 
// MEL
makePaintable -at doubleArray MyNode values;
setAttr MyNode1.values -type doubleArray 3 1.0 2.0 3.0;

How to get the value of an attribute anywhere in a custom node

MObject thisNodeObj = thisMObject();
 
double v0 = MPlug( thisNodeObj, attr0Obj ).asDouble();
float v1 = MPlug( thisNodeObj, attr1Obj ).asFloat();
int v2 = MPlug( thisNodeObj, attr2Obj ).asInt();
short v3 = MPlug( thisNodeObj, attr3Obj ).asShort();
bool v4 = MPlug( thisNodeObj, attr4Obj ).asBool();
MTime v5 = MPlug( thisNodeObj, attr5Obj ).asMTime();
char v6 = MPlug( thisNodeObj, attr6Obj ).asChar();
MString v7 = MPlug( thisNodeObj, attr7Obj ).asString();
 
MColor c;
MPlug plg( thisNodeObj, attrObj );
plg.child(0).getValue( c.r );
plg.child(1).getValue( c.g );
plg.child(2).getValue( c.b );

How to get the pointer of the other connected node

OtherNodeClassName* otherNodePtr = (OtherNodeClassName*)NULL;
 
MObject thisNodeObj = thisMObject();
MFnDependencyNode thisNodeFn( thisNodeObj );
MPlug plg = thisNodeFn.findPlug( inputAttrObj );
 
MPlugArray connectedPlgs;
if( plg.isConnected() ){
  if( plg.isSource() ) {
    plg.connectedTo( connectedPlgs, false, true );
  } else if( plg.isDestination() ) {
    plg.connectedTo( connectedPlgs, true, false );
  }
 
  MFnDependencyNode otherNodeFn( connectedPlgs[0].node() );
 
  if( otherNodeFn.typeId() == OtherNodeClassName::id )  {
    otherNodePtr = (OtherNodeClassName*)otherNodeFn.userNode();
  }
}

How to restore GL states in draw() of a custom locator node

void MyLocator::draw( M3dView&amp;amp; view, ...)
{
  float lastPointSize=0; glGetFloatv( GL_POINT_SIZE, &amp;amp;lastPointSize );
  float lastLineWidth=0; glGetFloatv( GL_LINE_WIDTH, &amp;amp;lastLineWidth );
  bool lightingWasOn = glIsEnabled( GL_LIGHTING ) ? true : false;
 
  if( lightingWasOn ) { glDisable( GL_LIGHTING ); }
 
  view.beginGL();
  ...
  view.endGL();
 
  glPointSize( lastPointSize );
  glLineWidth( lastLineWidth );
  if( lightingWasOn ) { glEnable( GL_LIGHTING ); }
}

How to call compute() of a custom locator without output connection

void MyLocator::draw( M3dView&amp;amp; view, ...)
{
  MObject thisNodeObj = thisMObject();
  MObject obj = MPlug( thisNodeObj, outputObj ).asMObject();
 
  ...
}

How to get the normal vector of a current camera

M3dView view = M3dView::active3dView();
MDagPath camDagPath;
view.getCamera( camDagPath );
MVector cameraZ = MVector(0,0,1) * camDagPath.inclusiveMatrix();

How to create attributes in initialize() of a custom node

MStatus MyLocator::initialize()
{
  MRampAttribute rAttr;
  MFnEnumAttribute eAttr;
  MFnUnitAttribute uAttr;
  MFnTypedAttribute tAttr;
  MFnNumericAttribute nAttr;
  MFnMessageAttribute gAttr;
 
  timeObj = uAttr.create( "time", "time", MFnUnitAttribute::kTime, 0.0 );
  addAttribute( timeObj );
 
  angleObj = uAttr.create( "angle", "angle", MFnUnitAttribute::kAngle, 0.0 );
  addAttribute( angleObj );
 
  boolObj = nAttr.create( "bool", "bool", MFnNumericData::kBoolean, false );
  addAttribute( boolObj );
 
  intObj = nAttr.create( "int", "int", MFnNumericData::kInt, 0 );
  addAttribute( intObj );
 
  floatObj = nAttr.create( "float", "float", MFnNumericData::kFloat, 0.f );
  addAttribute( floatObj );
 
  doubleObj = nAttr.create( "double", "double", MFnNumericData::kDouble, 0.0 );
  addAttribute( doubleObj );
 
  int2Obj = nAttr.create( "int2", "int2", MFnNumericData::k2Int, 0 );
  addAttribute( int2Obj );
 
  int3Obj = nAttr.create( "int3", "int3", MFnNumericData::k3Int, 0 );
  addAttribute( int3Obj );
 
  float2Obj = nAttr.create( "float2", "float2", MFnNumericData::k2Float, 0.f );
  addAttribute( float2Obj );
 
  float3Obj = nAttr.create( "float3", "float3", MFnNumericData::k3Float, 0.f );
  addAttribute( float3Obj );
 
  double2Obj = nAttr.create( "double2", "double2", MFnNumericData::k2Double, 0.0 );
  addAttribute( double2Obj );
 
  double3Obj = nAttr.create( "double3", "double3", MFnNumericData::k3Double, 0.0 );
  addAttribute( double3Obj );
 
  stringObj = tAttr.create( "string", "string", MFnData::kString, "abc" );
  addAttribute( stringObj );
 
  matrixObj = tAttr.create( "matrix", "matrix", MFnMatrixAttribute::kDouble );
  addAttribute( matrixObj );
 
  curveObj = tAttr.create( "curve", "curve", MFnData::kNurbsCurve );
  addAttribute( curveObj );
 
  meshObj = tAttr.create( "mesh", "mesh", MFnData::kMesh );
  addAttribute( meshObj );
 
  iaObj = tAttr.create( "iArray", "iArray", MFnData::kIntArray );
  addAttribute( iaObj );
 
  faObj = tAttr.create( "fArray", "fArray", MFnData::kFloatArray );
  addAttribute( faObj );
 
  daObj = tAttr.create( "dArray", "dArray", MFnData::kDoubleArray );
  addAttribute( daObj );
 
  paObj = tAttr.create( "pArray", "pArray", MFnData::kPointArray );
  addAttribute( paObj );
 
  vaObj = tAttr.create( "vArray", "vArray", MFnData::kVectorArray );
  addAttribute( vaObj );
 
  saObj = tAttr.create( "sArray", "sArray", MFnData::kStringArray );
  addAttribute( saObj );
 
  msgObj = gAttr.create( "message", "message" );
  addAttribute( msgObj );
 
  clrObj = nAttr.createColor( "color", "color" );
  addAttribute( clrObj );
 
  pntObj = nAttr.createPoint( "point", "point" );  
  addAttribute( pntObj );
 
  enumObj = eAttr.create( "enum", "enum" 0 );
  eAttr.addField( "A", 0 );
  eAttr.addField( "B", 0 );
  addAttribute( enumObj );
 
  crvRmpObj = rAttr.createCurveRampAttr( "crvRamp", "crvRamp" );
  addAttribute( crvRmpObj );
 
  clrRmpObj = rAttr.createColorRampAttr( "clrRamp", "clrRamp" );
  addAttribute( clrRmpObj );
 
  fileNameObj = tAttr.create( "fileName", "fileName", MFnData::kString );
  tAttr.setUsedAsFilename( true );
  addAttribute( fileNameObj );
 
  ...
}

Last updated