Chapter 9
Understanding C++ and the API Documentation
Author
Adam Mechtley
Project
Walk through the MVector class in the API documentation
Example Files
MVector Class Documentation
MScriptUtil Class Documentation
Synopsis
This chapter introduces the Maya API and how it fits into the overall Maya architecture. We briefly describe what the API is and how it differs from the scripts that readers have written up to this point. The chapter walks readers through the C++ API’s documentation so they are able to locate information when they need it, explains how to identify what functionality is not accessible to Python, and summarizes some of the major differences between the Python and C++ APIs including the MScriptUtil and MStatus classes.
Resources
Autodesk Developer Network
Maya Python API 2.0 Documentation
Michael Comet’s Maya API Help Page
Chad Vernon’s Maya API Programming Page
Complete Maya Programming: An Extensive Guide to MEL and the C++ API
Other Notes
None
Errata for the First Edition
None
Hi,
Im currently working through this book (loving the book.. ) and even started to experiment with Maya API. Im a little stuck and was wondering if someone could please help me out. Im writing a script to find the average edge length but I cant seem to get it in world space. “getLength(doublePtr, NOT SURE WHAT I NEEDS HERE)”
import maya.cmds as mc
import maya.mel as mm
import maya.OpenMaya as om
#
#GET POLYGON SELECTION
selection = om.MSelectionList()
om.MGlobal.getActiveSelectionList( selection );
iter = om.MItSelectionList ( selection, om.MFn.kGeometric );
while not iter.isDone():
dagPath = om.MDagPath()
iter.getDagPath( dagPath )
mObj = om.MObject()
iter.getDependNode( mObj )
dagPathHandle = dagPath.fullPathName()
iterEdge = om.MItMeshEdge( mObj )
while not iterEdge.isDone():
edgeIndexListHandle =[]
edgeIndexListHandle.append(iterEdge.index())
print edgeIndexListHandle
util = om.MScriptUtil()
doublePtr = util.asDoublePtr()
iterEdge.getLength(doublePtr)
length = om.MScriptUtil.getDouble(doublePtr)
print length
iterEdge.next()
iter.next()
francois said this on February 12, 2012 at 4:51 pm |
Hi Francois,
Looks like the second parameter for MItMeshEdge.getLength() is an MSpace (enum) value, whose default value is object space. To do world space, you should try passing om.MSpace.kWorld.
Adam said this on February 12, 2012 at 7:20 pm |
When i try to pass om.MSpace.kWorld I get the following error:
RuntimeError: (kInvalidParameter): Must have a DAG path to do world space transforms #
Im a bit stuck on how to get this
francois said this on February 13, 2012 at 1:56 pm |
When you initialize your MItMeshEdge iterator, you must pass it an MDagPath (dagPath) rather than an MObject (mObj). When you initialize with an MObject, there may be multiple paths to the object (e.g., if it is instanced) and so it needs a unique DAG path in order to know where it is in world space.
Adam said this on February 13, 2012 at 4:24 pm |
Thanks Adam that did the trick
francois said this on February 14, 2012 at 7:17 pm |
I ran into an issue using the the API and I need some help.
I used MFnSkinCluster.getPointsAffectedByInfluence to get the vertices affected by an influence. When I print out the selection list of the points it says that there is only one point even though I know that influence affects more points. here is the script I used:
import maya.OpenMaya as om
import maya.OpenMayaAnim as oma
om.MGlobal.clearSelectionList()
om.MGlobal.selectByName(‘skinCluster2’)
infs = om.MDagPathArray()
sList = om.MSelectionList()
om.MGlobal.getActiveSelectionList(sList)
node = om.MObject()
sList.getDependNode( 0, node )
skin = oma.MFnSkinCluster(node)
numInfs = skin.influenceObjects(infs)
skinPath = om.MDagPath()
index = 0
skin.getPathAtIndex(index,skinPath)
geo = om.MItGeometry(skinPath)
weights = om.MDoubleArray()
pointsInfl = om.MSelectionList()
skin.getPointsAffectedByInfluence(infs[3], pointsInfl, weights)
print ‘pointsInfl %s’% pointsInfl
print pointsInfl.length()
serena said this on June 29, 2012 at 9:15 am |
Hi,
I’m writing a simple deformer which I need it to get and set vertex positions in world space.
I’m getting the same error francois. But the MItMeshVertex has been created automatically by the deform method so how can we pass it a MDagPath?
Here is what I’ve accomplished so far:
import maya.OpenMaya as om
import maya.OpenMayaMPx as mpx
import sys
nodeName = 'ehm_flattenDeformer'
nodeId = om.MTypeId( 0x0011E182 )
class ehm_flattenDeformer( mpx.MPxDeformerNode ):
def __init__( self ):
mpx.MPxDeformerNode.__init__( self )
def deform( self, dataBlock, geoItr, matrix, index ):
# 0. get deformer input
input = mpx.cvar.MPxDeformerNode_input
# 1. Attach a handle to input Array Attribute.
inputHandle_array = dataBlock.inputArrayValue( input )
# 2. Jump to particular element
inputHandle_array.jumpToElement( index )
# 3. Attach a handle to specific data block
inputHandle_element = inputHandle_array.inputValue()
# 4. Reach to the child - inputGeom
inputGeom = mpx.cvar.MPxDeformerNode_inputGeom
inMeshHandle = inputHandle_element.child( inputGeom )
# 5. get Mesh
inMesh = inMeshHandle.asMesh()
# Envelope
envelope = mpx.cvar.MPxDeformerNode_envelope
envelopeHandle = dataBlock.inputValue( envelope )
envelopeValue = envelopeHandle.asFloat()
# deform
while not geoItr.isDone():
pointPosition = geoItr.position( om.MSpace.kWorld )
pointPosition.y *= (1-envelopeValue)
geoItr.setPosition( pointPosition, om.MSpace.kWorld )
geoItr.next()
def nodeCreator():
return mpx.asMPxPtr( ehm_flattenDeformer() )
def nodeInitializer():
pass
def initializePlugin( mObj ):
plugin = mpx.MFnPlugin( mObj, 'Ehsan HM', '1.0', 'any' )
try:
plugin.registerNode( nodeName, nodeId, nodeCreator, nodeInitializer, mpx.MPxNode.kDeformerNode )
except:
sys.stderr.write( 'Faild to load plugin: %s' % nodeName )
def uninitializePlugin( mObj ):
plugin = mpx.MFnPlugin( mObj )
try:
plugin.deregisterNode( nodeId )
except:
sys.stderr.write( 'Faild to unload plugin: %s' % nodeName )
Ehsan said this on November 14, 2013 at 9:10 am |
Hi Ehsan,
It’s the same problem, unfortunately. Imagine you have a shape node of some kind connected to your deformer. This shape might be instanced by 100 different transforms, so you’d need to somehow specify which you want to use for world space. However, you don’t really want to start looking outside your node (i.e. traversing the DAG) to get a path, as you could trigger all kinds of other computation in the graph. A safe approach could be to have your node take local and parent matrices as additional input, which you then use to calculate your positions for the iterator, and then make sure your accompanying command or other setup utility attaches a selected object’s matrix/parentMatrix when the node is created.
Adam said this on November 28, 2013 at 8:18 pm |