Maya C++ API Programming Tips
source : http://wanochoi.com/?page_id=1588
How to handle the multiple outputs of a DG node
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
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
1
2
3
4
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
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
1
2
3
4
5
6
7
8
9
|
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
1
2
3
4
5
6
7
|
#if MAYA_API_VERSION &gt;= 201300
...
#elif MAYA_API_VERSION &gt;= 201400
...
#elif MAYA_API_VERSION &gt;= 201500
...
#endif
|
How to get the current Maya version
1
2
|
MString mayaVer = MGlobal::mayaVersion();
int
apiVer = MGlobal::apiVersion();
|
How to avoid the conflict with Cuda
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
...
#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 &lt;cuda.h&gt;
...
|
How to set the MFloatPoint from a MPoint
1
2
3
|
MPoint dp;
// double type
MFloatPoint fp;
// float type
fp.setCast( dp );
|
How to get the pixel values of an image
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
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&lt;h; ++j )
for
(
int
i=0; i&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&lt;d; ++k )
{
pixelVal[k] = c[idx++];
}
...
}}
|
How to get the DAG path from a node name
1
2
3
4
5
6
7
|
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
1
2
3
4
5
6
7
|
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
1
2
3
4
|
MObject dagNodeObj = ...;
MDagPath dagPath;
MFnDagNode dagFn( dagNodeObj );
dagFn.getPath( dagPath );
|
How to get the node name from a node object
1
2
3
4
5
6
7
8
9
10
|
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
1
2
3
4
5
6
7
|
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
1
2
3
|
MDagPath xformDagPath = ...
MDagPath shapeDagPath = xformDagPath;
shapeDagPath.extendToShape();
|
How to get the DAG paths of selected mesh shape nodes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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
1
2
3
4
5
6
|
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
1
2
3
4
5
6
7
8
9
10
11
12
|
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
1
2
3
4
5
6
|
MItDag itr( MItDag::kDepthFirst, MFn::kField );
for
( ; !itr.isDone(); itr.next() )
{
MFnField fieldFn( itr.item() );
...
}
|
How to get the world matrix of the current DAG node
1
2
3
4
5
6
7
8
|
MObject thisNodeObj = thisMObject();
MFnDependencyNode thisNodeFn( thisNodeObj );
MObject worldMatrixObj = thisNodeFn.attribute(
"worldMatrix"
);
MPlug worldMatrixPlg( thisNodeObj, worldMatrixObj );
worldMatrixPlg = worldMatrixPlg.elementByLogicalIndex( 0 );
worldMatrixPlg.getValue( worldMatrixObj );
MFnMatrixData worldMatrixData( worldMatrixObj );
Matrix worldMatrix = worldMatrixData.matrix();
|
How to connect the output plug to the parent automatically when a custom locator node is created
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
class
MyLocator
{
...
bool
connected;
...
};
MyLocator::MyLocator()
{
connected =
false
;
}
void
MyLocator::draw( M3dView&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
1
2
3
4
5
|
void
MyLocator::draw( M3dView&amp; view, ...)
{
if
( view.selectMode() ) {
return
; }
...
}
|
How to detect which input attribute is changed
1
2
3
4
5
6
7
8
9
|
MStatus MyCustomNode::compute(
const
MPlug&amp; plug, MDataBlock&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
1
2
3
4
|
if
( MGlobal::mayaState() == MGlobal::kBatch )
{
...
}
|
How to detect whether the current viewport is Viewport 2.0
1
2
3
4
5
|
M3dView view = M3dView::active3dView();
if
( view.getRendererName() == M3dView::kViewport2Renderer )
{
...
}
|
How not to draw a custom locator node while mouse interactions (>=2015)
1
2
3
4
5
6
7
8
|
void
MyLocator::draw( M3dView&amp; view, ...)
{
if
( MHWRender::MFrameContext::inUserInteraction()
|| MHWRender::MFrameContext::userChangingViewContext() )
{
...
}
}
|
How to draw a text in draw() of a custom locator node
1
2
3
4
5
6
7
8
|
void
MyLocator::draw( M3dView&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
1
2
3
4
5
6
7
8
9
10
|
MStatus MyNode::compute(
const
MPlug&amp; plug, MDataBlock&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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
MStatus MyNode::compute(
const
MPlug&amp; plug, MDataBlock&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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
class
MyCustomNode
{
...
MObject valuesObj;
...
MDoubleArray values;
};
MObject MyCustomNode::valuesObj;
MStatus MyCustomNode::initialize()
{
...
valuesObj = tAttr.create(
"values"
,
"values"
, MFnData::kDoubleArray );
...
}
MStatus MyCustomNode::compute(
const
MPlug&amp; plug, MDataBlock&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 MyCustomNode values;
setAttr MyCustomNode1.values -type doubleArray 3 1.0 2.0 3.0;
|
How to get the value of an attribute anywhere in a custom node
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
void
MyLocator::draw( M3dView&amp; view, ...)
{
float
lastPointSize=0; glGetFloatv( GL_POINT_SIZE, &amp;lastPointSize );
float
lastLineWidth=0; glGetFloatv( GL_LINE_WIDTH, &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
1
2
3
4
5
6
7
|
void
MyLocator::draw( M3dView&amp; view, ...)
{
MObject thisNodeObj = thisMObject();
MObject obj = MPlug( thisNodeObj, outputObj ).asMObject();
...
}
|
How to get the normal vector of a current camera
1
2
3
4
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
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 );
...
}
|