Due to a miscommunication between Elsevier Press and the Python Software Foundation, the first printing of this title used an unauthorized modification of the trademarked Python logo. We apologize to the PSF for this, and they have been understanding of our in-press status; in the 2nd and subsequent printing of this title, we shall use a cover design that has been approved as non-dilutive by the Python Software Foundation.

Help make the world a better place and make a secure donation to the Python Software Foundation today!

 

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


8 Responses to “Chapter 9”

  1. 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()

    • 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.

  2. 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

    • 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.

  3. Thanks Adam that did the trick

  4. 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()

  5. 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 )

    • 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.

Leave a Reply

Your email address will not be published. Required fields are marked *