Saturday, November 7, 2015

Maya Python: Get the Hierarchy Root Joint

  I am taking a break from the Rigging System Case Study series; Part 3 may take some time to write out everything.  I've recently began exploring a personal project that required me to to take a look at rewriting some really simple rigging utility functions.  I decided to post a few and here is the first...


import maya.cmds as cmds


def _getHierarchyRootJoint( joint="" ):
    """
    Function to find the top parent joint node from the given 
    'joint' maya node

    Args:
        joint (string) : name of the maya joint to traverse from

    Returns:
        A string name of the top parent joint traversed from 'joint'

    Example:
        topParentJoint = _getHierarchyRootJoint( joint="LShoulder" )

    """
    
    # Search through the rootJoint's top most joint parent node
    rootJoint = joint

    while (True):
        parent = cmds.listRelatives( rootJoint,
                                     parent=True,
                                     type='joint' )
        if not parent:
            break;

        rootJoint = parent[0]

    return rootJoint 
  

  I've used this particular function for part of the traversal from mesh->skinCluster->influence->top parent joint.  I've used it for mostly exporter, animation tools and for rigging purposes - building an export skeleton layer on a game rig.

  For the purposes of my personal project - the code needs to be as fast as possible for the utility functions.  I like to stay away from plugin dependencies for Maya tools where possible,  so I am working with Maya commands engine for my Maya utility code - it's not as Pythonic as PyMel, but is faster and worth spending the extra time to consider if you are worried about speed of the tool.  It's a trade off to consider when thinking of the needs of the tool.  For instance the Rigging System that I've been blogging about was written with PyMel, where as most of the animation tools I've worked with I have used the Maya commands engine.  With my timing decorator on I am averaging about 0.0075-0.008s for this function traversing about 250 joints up the chain.

  Speaking of the time decorator, here is mine that I created to track/debug my utility stuff.  I would suggest using logging instead of print, print is bloated and would provide less accurate data for you to analyze. 


from functools import wraps
import time
import logging
import maya.utils 
 
# Create debug logger within in - a few Maya version block the basic logger
logger = logging.getLogger( "MyDebugLogger" )
logger.propagate = False
handler = maya.utils.MayaGuiLogHandler()
handler.setLevel( logging.INFO )
formatter = logging.Formatter( "%(message)s" )
handler.setFormatter( formatter )
logger.addHandler( handler )
 
def timeDecorator( f ):
    """
    Decorator function to apply a timing process to a function given

    Args:
        f (object) : Python function passed through the decorator tag

    Returns:
        return the value from the function wrapped with the decorator
        function process

    Examples:
        @timeDecorator
        def myFunc( arg1, arg2 ):

    """

    @wraps(f)
    def wrapped( *args, **kwargs ):
        """ 
        Wrapping the timing calculation around the function call 
        
        Returns:
            Result of the called wrapped function
            
        """
        

        
        # log the process time 
        t0 = time.clock()
        r = f( *args, **kwargs )
        logger.warning( "{funcName} processing took : {processTime}".format( funcName=f.__name__, processTime= + time.clock() - t0 ) )
        
        return r

    return wrapped

No comments:

Post a Comment