Advertisement
DrGravitas

Renderable Skeleton - Maya 2015 PyMel

Sep 8th, 2015
124
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.17 KB | None | 0 0
  1. '''
  2.     Script by Dr. Gravitas
  3.    
  4.     This script takes one or more joint selections and creates a series of spheres and cones
  5.     along the joint heirarchies to represent the skeletons with renderable components.
  6. '''
  7. import pymel.core as pm
  8. from maya import OpenMaya as om
  9.  
  10. '''
  11.     For a given joint, create a sphere and cone(s) representing the joint and bone lengths to any child joints
  12. '''
  13. def placeBone( aJoint, shaderGroup ):
  14.     # We can't use | in names, as would happen if two joints share the same name,
  15.     #   but just using the .nodeName() name will not be unique. So replace | with empty String
  16.     jointName = aJoint.name().replace('|', '')
  17.     #create a PolySphere with a name derived from the joint...
  18.     sphereName = 'VisSkel_' + jointName + '_sphere'
  19.    
  20.     # (Joint Radius is a bit big; scale down by 0.09. It'd be nice if we could use user joint size display prefs to calc this.)
  21.     sphere = pm.nodetypes.PolySphere( n=sphereName, sx=6, sy=6, r=aJoint.getRadius()*0.09 )        
  22.     # ...get the sphere's transform node through selection...
  23.     #       (The name given above is applied to the transform node, rather than it's PolySphere node because Maya!)
  24.     sphTrans = getTransformNodeFromPolyPrimative( sphereName )
  25.     # ...and parent it the joint, inheriting the rotation/Position, then set the rest of joint's transformation attributes.
  26.     pm.parent( sphTrans, aJoint, relative=True )
  27.     sphTrans.setScale( aJoint.getScale() )
  28.    
  29.     # Add sphere to the given shader group; eg. applying the shader to the sphere.
  30.     #shaderGroup.addMember( sphTrans )
  31.     pm.sets( shaderGroup, edit = True, forceElement=sphTrans )
  32.     #The hard part: creating cones pointing to any child joints of the current joint.
  33.     placeCones( aJoint, jointName, shaderGroup )
  34.    
  35. '''
  36.     Get a transformNode of a PolyPrimative that was created with a name (ex. PolyCone, PolySphere, etc.)
  37.     This method will clear your selections.
  38.     TODO: Figure out a better, to do this. Using select is a clunky work around
  39. '''
  40. def getTransformNodeFromPolyPrimative( polyPrimName ):
  41.     pm.select( polyPrimName )
  42.     transformNode = (pm.selected())[0]
  43.     pm.select(cl=True)
  44.     return transformNode
  45.  
  46. '''
  47.     Places Cones representing the bone length between a given joint and its children.
  48. '''
  49. def placeCones( joint, jointName, shaderGroup ):
  50.     for child in joint.getChildren(type="joint"):
  51.         # create the cone;
  52.         coneName = 'VisSkel_' + child.name().replace('|', '') + '_cone_' + jointName
  53.         # cone length is the distance between joint and it's child
  54.         height = om.MVector(*child.attr('t').get()).length()
  55.         cone = pm.polyCone(n=coneName, sh=1, sa=3, sc=0, r=joint.getRadius()*0.09,height=height )
  56.        
  57.         # position and orient the cone
  58.         pm.delete(pm.pointConstraint(joint, cone))
  59.         pm.delete(pm.aimConstraint(child, cone, aim=[0,1,0]))
  60.         pm.move(0, height/2, 0, cone, objectSpace=True, r=True)
  61.        
  62.         coneTrans = getTransformNodeFromPolyPrimative( coneName )
  63.         pm.parent( coneTrans, joint )
  64.        
  65.         #shaderGroup.addMember( coneTrans )
  66.         pm.sets( shaderGroup, edit = True, forceElement=coneTrans )
  67.  
  68. '''
  69.     Create A Lambert Shader of the given color, with the name VisSkel_Lambert# where # is
  70.     the number in the order of such nodes created.
  71. '''
  72. def createLambertShader( color ):
  73.     # Create a Lambert shader of a given name and associated shaderGroup
  74.     shader, shaderGroup = pm.createSurfaceShader( 'lambert', name='VisSkel_Lambert' );
  75.     # Set the shader's color
  76.     shader.setColor( color )
  77.     return shader, shaderGroup
  78.    
  79. '''
  80.    Create a unique identifier string representing a color for a dictionary key.
  81. '''
  82. def colorKey( color )
  83.     return str(color.r)+str(color.g)+str(color.b)+str(color.a)
  84.  
  85. '''
  86.    This method takes a list of joint hierarchies and creates a series of spheres and cones
  87.    to create a renderable skeleton. The method also creates shaders to apply to the visible
  88.    skeleton, colored based on the colorized joint skeleton. If the skeleton was never bound,
  89.    then all the colors will likely be blue. This method takes care to not reoperate on joints
  90.    and will not duplicate shaders of the same color.
  91. '''
  92. def generateSkeleton( targets ):
  93.     # Keep a dictionary of targets (and their child joints) that we've hit so we don't operate on them again.
  94.     jointsHit = {}
  95.     # Dictionary mapping Colors to their shader/shaderGroups so we do not duplicate shaders with the same color.
  96.     shaderColors = {}
  97.    
  98.     for target in targets:
  99.         # Select the target joint and all its children via selecting the target joint with heirarcy flag
  100.         pm.select( target.name(), hi=True )
  101.         # Get those selected joints then clear selection.
  102.         jointHeirarchy = pm.selected()
  103.         pm.select(cl=True)
  104.        
  105.         for aJoint in jointHeirarchy:
  106.             # if this is not actually a joint, or if we've already operated on a joint with this name,
  107.             #   then we just skip it without throwing error.
  108.             if isinstance(aJoint, pm.nodetypes.Joint) and aJoint.name() not in jointsHit:
  109.                 # record joint as hit.
  110.                 jointsHit[aJoint.name()] = aJoint
  111.                 # Get the joint viewport display color so we have a colorized skeleton
  112.                 rawColor = aJoint.__apimfn__().dormantColor()
  113.                 color = pm.datatypes.Color( rawColor.r, rawColor.g, rawColor.b)
  114.                            
  115.                 key = colorKey( color )
  116.                 if key not in shaderColors:
  117.                     # If the color does not exist as a shader yet, create one.
  118.                     shader, shaderGroup = createLambertShader( color )
  119.                     shaderColors[key] = shaderGroup
  120.                 else:
  121.                     # Otherwise, simply get the existing shader
  122.                     shaderGroup = shaderColors[key]
  123.                
  124.                 placeBone( aJoint, shaderGroup )
  125.  
  126. # End of method definitions; Beginning of the script execution!
  127. # Jump the command log output a couple lines to make clear the difference between code reprint and output.
  128. print '\n\n\n'
  129.  
  130. #Get list of targets from what has been selected
  131. targets = pm.selected()
  132.  
  133. # Verify all selected target are joints.
  134. for target in targets:
  135.     if not isinstance(target, pm.nodetypes.Joint):
  136.         pm.error(target + ' is Type: ' + type(target).__name__ + '. Not the required Type: Joint')
  137.  
  138. # clear selections
  139. pm.select(cl=True)
  140.  
  141. generateSkeleton( targets )
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement