So now we have a handle of getting a selection, or building an MSelectionList() to get MObjects to manipulate in scene.
Now another big part of our day is creating nodes / adding or removing attributes / querying attributes values / connecting or disconnecting attributes.
Below might look familiar those of you using cmds a lot;
from maya import cmds
curSel = cmds.ls(sl=True)
srcNode = curSel[0]
destNode = curSel[1]
# connect
cmds.connect("{}.translate".format(srcNode),
"{}.translate".format(destNode),
force=True)
# getAttr
transX = cmds.getAttr("{}.translate".format(srcNode))
# setAttr
cmds.setAttr("{}.translateX".format(srcNode), 10)
# createNode
newNode = cmds.createNode("transform", name="Fart")
Yes it is true that we’re about to convert this into more lines using om2. And yes I still do a lot of prototyping in cmds when mashing stuff together in the script editor, but for reuse tools, I will most likely convert those scripts to om2, even the ones that might not see a lot of benefit speed wise, as it’s just good practise and I find it fun to do shrug.
from maya.api import OpenMaya as om2
from maya import cmds
# mDagMod for creating / handling DGNodes
mdgmod = om2.MDGModifier()
# mDagMod for creating / handling DagNodes
mDagMod = om2.MDagModifier()
curSel = om2.MGlobal.getActiveSelectionList()
srcNode = curSel.getDependNode(0)
destNode = curSel.getDependNode(1)
# connect
# Find first source plug, find dest plug, use the modifier to connect them
mFn = om2.MFnDependencyNode(srcNode)
srcPlug = mFn.findPlug("translate", False)
mFn.setObject(destNode)
destPlug = mFn.findPlug("translate", False)
if destPlug.isConnected:
# Find what it is connected to and disconnect it first!
# Since this is a destination only one thing can be connected to it.
# Else if we're looking for all connected to a source we can use connectedTo()
src = destPlug.source()
mDagMod.disconnect(srcPlug, destPlug)
mDagMod.connect(srcPlug, destPlug)
mDagMod.doIt()
# getAttr
# some plugs are compounds, some are arrays, some are floats / bool / shorts / double etc
srcTrans = [srcPlug.child(x).asFloat() for x in range(srcPlug.numChildren())]
print(srcTrans)
# setAttr
srcPlug.child(0).setFloat(10)
# createNode
# Depending on if you are making a DAGNode or DGNode you'll need to use either a
# MDagModifier or a MDGModifier() eg: you can't make a joint with a MDGModifier()
nodeName = "Fart"
# We can use cmds here to check for the node as the queries in cmds are pretty
# fast.
if not cmds.objExists(nodeName):
newNode = mDagMod.createNode("transform")
mDagMod.renameNode(newNode, nodeName)
mDagMod.doIt()
# Note you might want to use the MFnDependencyNode.create() method, but this will
# create the node in scene as soon as you call this. Using the MDG or MDag modifiers
# lets you queue up xNum of operations and using the doIt() to perform them in one
# go. Which can be a HUGE time saver when building complex scenes.
So what about this:
”# some plugs are compounds, some are arrays, some are floats / bool / shorts / double etc”
If you’re confused what kind you’re dealing with you can use Maya’s nodeEditor to try to figure it out.
An MPlug has a couple methods to help out.
MPlug.isArray()
MPlug.isCompound()
MPlug.isElement()
MPlug.isChild()
The main difference between an Array and a Compound being;
Lets look at this in code:
from maya.api import OpenMaya as om2
# mDagMod for creating / handling DAGNodes
mDagMod = om2.MDagModifier()
mDGMod = om2.MDGModifier()
curSel = om2.MGlobal.getActiveSelectionList()
srcNode = curSel.getDependNode(0)
destNode = curSel.getDependNode(1)
# Connect the CHILDREN of attributes "translate", "rotate", "scale" to
# another transform's "translate", "rotate", "scale"
mFn = om2.MFnDependencyNode()
for x in range(3):
mFn.setObject(srcNode)
for plugName in ("translate", "rotate", "scale"):
mFn.setObject(srcNode)
srcPlug = mFn.findPlug(plugName, False)
srcMPlug = srcPlug.child(x)
mFn.setObject(destNode)
destPlug = mFn.findPlug(plugName, False)
destMPlug = destPlug.child(x)
mDagMod.connect(srcMPlug, destMPlug)
# Note how we've stacked all these connections BEFORE calling the doIt()
mDagMod.doIt()
# Now the worldMatrix (which is an Array)
mFn.setObject(srcNode)
srcPlug = mFn.findPlug("worldMatrix", False)
srcWorldMatrix0 = srcPlug.elementByLogicalIndex(0)
mFn.setObject(destNode)
decomposeMatrix = mDGMod.createNode("decomposeMatrix")
# This node NEEDS TO EXIST to connect to! So we have to create it now!
mDGMod.doIt()
mFn.setObject(decomposeMatrix)
destPlug = mFn.findPlug("inputMatrix", False)
mDagMod.connect(srcWorldMatrix0, destPlug)
mDagMod.doIt()
Finally it’s probably important to know the difference between a logical index and a physical one… from the docs… yes the info is all there :P
Logical Index:
“This method will find and return a plug with the given logical index.
The logical index is the sparse array index used in MEL scripts.
If a plug does not exist at the given Index, Maya will create a plug at that index.
This is not the case with elementByPhysicalIndex(). If needed, elementByLogicalIndex
can be used to expand an array plug on a node.
It is important to note that Maya assumes that all such plugs serve a purpose and it will not free non-networked
plugs that result from such an array expansion.”
Physical Index:
“This method will find and return a plug with the given physical index.
The index can range from 0 to numElements() - 1. This function is particularly useful for iteration through the element plugs of an array plug. It is equivalent to operator [] (int) This method is only valid for array plugs.
If the returned plug is networked, the networked plug will be returned. Otherwise, a non-networked plug will be returned.”