So one super convenient thing pymel gives you is a name independent way of tracking nodes in your code. So doing this:
from maya.cmds import *
o = group( em=True )
rename( o, 'something_else' )
select( o )
This will fail because the o variable is just the name of the group when it was originally created, and the name changes before the select command is run. Now obviously the above is a trivial case and can be easily solved, but sometimes its not so easy.
For example, if you have a group with a non-unique leaf name that is nested deeply in the hierarchy, just by re-parenting one of its parents, the node will change. Tracking this changed name is non-trivial, and is the sort of problem you run into every now and then when writing generalized tools for rigging, or just general scene construction.
Anyhoo, so poking around a bit I experimented with adding a few methods to MObject, kinda like this:
from maya.OpenMaya import *
def asMObject( otherMobject=None ):
'''
tries to cast the given obj to an mobject - it can be string
'''
if otherMobject is None:
return MObject()
if isinstance( otherMobject, basestring ):
sel = MSelectionList()
sel.add( otherMobject )
tmp = MObject()
sel.getDependNode( 0, tmp )
#tmp.cast()
return tmp
def partialPathName( self ):
'''
returns the partial name of the node
'''
if self.hasFn( MFn.kDagNode ):
dagPath = MDagPath()
MDagPath.getAPathTo( self, dagPath )
return dagPath.partialPathName()
return MFnDependencyNode( self ).name()
MObject.__str__ = partialPathName
MObject.__unicode__ = partialPathName
MObject.partialPathName = partialPathName
MObject.name = partialPathName
def _hash( self ):
return MObjectHandle( self ).hashCode()
MObject.__hash__ = _hash
def cmpNodes( a, b ):
'''
compares two nodes and returns whether they're equivalent or not.
the compare is done on MObjects not strings so passing the fullname
and a partial name to the same dag will still return True
'''
if not isinstance( a, MObject ):
a = asMObject( a )
if not isinstance( b, MObject ):
b = asMObject( b )
return a.name() == b.name()
Now this is hardly rocket science here, but it does go along way toward making MObjects useful in just your average script, and more to the point it solves the problem discussed above.
How? Well, first off, its easy to cast a node name to an MObject with the asMObject function. More importantly, you can still pass the variable to a normal mel command. ie this works:
from maya.cmds import *
o = asMObject( group( em=True ) )
rename( o, 'something_else' )
select( o )
Plus you can compare two nodes without having to worry about whether one is a full path to the node or a partial path.
This code can be packaged up into a simple little module that you can import at will – simply by importing the script you get the functionality added to the MObject class, so all you need to do really is add this to the top of your scripts:
from apiExtensions import asMObject
And wham – you get the rest for free.
Casting to these MObjects is still slow – there’s no way around that. Thats just maya being a slut. But you can easily target which parts of your script to add this functionality to without having to change your entire code base to use something like pymel or MRV. Plus you can also pass this MObject to the api class – again without having to wrap anything.
I’m smelling win.
Thoughts?
Posted in main | 6 Comments »