Example #1
0
def build( root, fingerDict, side='rt', cleanUp=1 ):
    '''
    Builds an fk hand with extendable knuckles
    
    Args:
        root - node at the location of the wrist
        fingerDict - dictionary with keys for the name of each digit and values which are the root node for each digit:
            e.g. { 'thumb':'lf_thumb1_defJnt', 'index':'lf_index1_defJnt' }
            
            For each key in fingerDict a digit will be created with segments based on the number of child joints in the chain.
            
            Any joints with the same worldSpace location as their child will become 'extend' joints
    
    '''
    # Validate arguments
    if type(root) != type('hello') and type(root) != type(u'hello'):
        return showDialog( 'Argument Error', 'You must supply a root of type string or unicode' )
    
    if type(fingerDict) != type({}):
        return showDialog( 'Argument Error', "fingerDict must be supplied as a dictionary/nwith a key for the name of each digit and a root node as its value/n e.g.{ 'thumb':'lf_thumb1_defJnt', 'index':'lf_index1_defJnt' }")
    
    # Build and align root groups
    xformGrp = cmds.group(empty=1)
    xformGrp = cmds.rename(xformGrp, common.getName( node=xformGrp, side=side, rigPart='hand', function='xform', nodeType='grp'))
    common.align(node=xformGrp, target=root)
    
    rigGrp = cmds.duplicate(xformGrp)
    rigGrp = cmds.rename(rigGrp, common.getName( node=rigGrp, side=side, rigPart='hand', function='rig', nodeType='grp'))
    cmds.parent( rigGrp, xformGrp )
    
    # Root joint
    cmds.select(None)
    rootJnt = cmds.joint()
    rootJnt = cmds.rename(rootJnt, common.getName( node=rootJnt, side=side, rigPart='hand', function='root', nodeType='jnt'))
    common.align(rootJnt, xformGrp)
    cmds.parent(rootJnt, rigGrp)
    cmds.setAttr('%s.jointOrient' % rootJnt, 0, 0, 0 )
    
    # Build fingers
    for key in fingerDict.keys():
        fing = buildFinger( side=side, name=key, rootJnt=fingerDict[key], rootGrp=xformGrp, cleanUp=cleanUp )
        cmds.parent(fing['jnts'][0], rigGrp)
        
    # Cleanup
    if cleanUp:
        cmds.setAttr( '%s.visibility' % rigGrp, 0 )
        common.attrCtrl(nodeList=[rigGrp], attrList=['visibility'])
        
    return {'systemGrp':xformGrp}
Example #2
0
def attrCtrl(lock=True, keyable=False, channelBox=False, nodeList=[], attrList=[]):
    '''
    Takes a list of nodes and sets locks/unlocks shows/hides attributes in attrList
    
    '''
    if nodeList:
        for node in nodeList:
            if attrList:
                for attr in attrList:
                    if cmds.attributeQuery(attr, node=node, exists=True):
                        cmds.setAttr('%s.%s' % (node, attr), lock=lock, keyable=keyable, channelBox=channelBox)
            else:
                return showDialog( 'Argument Error', 'No nodes supplied for attribute control' )
    else:
        return showDialog( 'Argument Error', 'No nodes supplied for attribute control' )
Example #3
0
def align( node=None, target=None, translate=True, orient=True ):
    '''
    sets the translation and / or orientation of node to match target
    
    '''
    
    # Validate that the correct arguments have been supplied
    if not node or not target:
        # If node and target aren't explicitly supplied, check for a valid selection to use 
        sel = cmds.ls(sl=1, type='transform')
        if len( sel ) == 2:
            node, target = sel[0], sel[1]
        else:
            return showDialog( 'Argument Error', 'Cannot determine nodes to align' )

    targetMatrix = cmds.xform( target, q=True, ws=1, matrix=True )
    nodeMatrix = cmds.xform( node, q=True, ws=1, matrix=True )
    
    if translate and orient:
        cmds.xform ( node, ws=1, matrix=targetMatrix )
    elif translate:
        # set row4 x y z to row4 of targetMatrix
        nodeMatrix[ 12:-1 ] = targetMatrix[ 12:-1 ]
        cmds.xform ( node, ws=1, matrix=nodeMatrix )
    elif orient:
        # set row4 x y z to row4 of nodeMatrix
        targetMatrix[ 12:-1 ] = nodeMatrix[ 12:-1 ]
        cmds.xform ( node, ws=1, matrix=targetMatrix )
Example #4
0
def exportControl(fileName=None, ctrl=None):

    """
    Exports control to file
    
    """

    workspace = os.path.join(os.path.dirname(__file__), "..", "assets")

    if fileName == None:
        fileName = str(cmds.ls(selection=True)[0])

    ctrlFile = os.path.join(workspace, "%s_CTRL.ma" % fileName)
    if os.path.exists(ctrlFile):
        if (
            showDialog(
                title="WARNING",
                message="Character %s control file already exists. \n Overwrite File?" % fileName,
                button=["yes", "no"],
            )
            != "yes"
        ):
            return "User cancelled"

    if ctrl == None:
        ctrl = str(cmds.ls(selection=True)[0])

    cmds.select(ctrl)
    cmds.file(ctrlFile, es=1, f=1, type="mayaAscii")
Example #5
0
def writeJoints( char, jointList ):
    '''
    function to save joint data out to a json file
    joints are stored in a dictionary called jointDict with one key - 'joints'
    the value of jointDict['joints'] is another dictionary with a key corresponding to the name of each joint
    the value of each joint key is also a dictionary containing all the data for that joint
    
    ''' 
    joints = {}
    xformAttrs = ['tx', 'ty', 'tz', 'rx', 'ry', 'rz', 'sx', 'sy', 'sz', 'jox', 'joy', 'joz']
      
    # Populate data
    for j in jointList:
        jointData = {}
        for attr in xformAttrs:
            jointData.setdefault( attr, cmds.getAttr('%s.%s' % (j, attr)))
        
        joints.setdefault( j, jointData )
        
    jointDict = {'joints':joints}
    
    charDir  = common.getCharDir( char )
    jointFile = os.path.join( charDir, '%s_joints.py' % char)
    
    # Check to see if file exists
    if os.path.isfile(jointFile):
        if showDialog( title='WARNING', message='Overwrite existing joint data?', button=['yes', 'no'] ) != 'yes':
            return 'User cancelled'

    # Make sure a destination folder exists
    destDir = os.path.dirname( jointFile )
    if not os.path.exists( destDir ):
        if showDialog( title='WARNING', message='Character %s Does not exist.\n Would you like to create it now?' % char, button=['yes', 'no'] ) != 'yes':
            return 'User cancelled'
        else:
            os.makedirs( destDir )

    # Write data to disk
    f = open(jointFile, 'w')
    f.write(json.dumps(jointDict))
    f.close()
    showDialog( 'Success!', 'Joint data dumped to file:\n"%s_joints.py".' % jointFile )
Example #6
0
def exportSkel( char, jointList ):
    '''
    exports the charName_skel.ma file from the supplied jointlist.
    If file exists, asks whether you want to overwrite.
    
    '''
    skelFile = os.path.join(common.getCharDir( char ), '%s_skel.ma' % char)
    if os.path.exists(skelFile):
        if showDialog( title='WARNING', message='Character %s skeleton file Exists.\n Overwrite File?' % char, button=['yes', 'no'] ) != 'yes':
            return 'User cancelled'
        
    cmds.select(jointList)
    cmds.file(skelFile, es=1, f=1, type='mayaAscii')
Example #7
0
def importSkel( char ):
    '''
    imports the charName_skel.ma file from the character's directory if one exists.
    If no file exists, asks whether you want to import the default skel.
    
    '''
    skelFile = os.path.join(common.getCharDir( char ), '%s_skel.ma' % char)
    if not os.path.exists(skelFile):
        if showDialog( title='WARNING', message='Character %s skeleton file not found.\n Would you like to load default skeleton?' % char, button=['yes', 'no'] ) != 'yes':
            return 'User cancelled'
        skelFile = os.path.join(common.getCharDir( 'defaultChar' ), 'defaultChar_skel.ma')
        
    cmds.file(skelFile, i=1, dns=1)
Example #8
0
def pointsAlongVector( start='', end='', divisions=2 ):
    '''
    returns a list of points that lie on a line between start and end
    'divisions' specifies the number of points to return.
    divisions = 2 (default) will return the start and end points with one intermediate point: [ p1(start), p2, p3(end) ]
    
    start and end can be supplied as lists, tuples or nodes. If they are not supplied, and 2 scene nodes are selected
    will attempt to use their world space positions as start and end
        
    creates a vector by subtracting end from start
    stores length of vector
    normalizes vector
    multiplies normalized vector by length / divisions
    
    '''
    startPos, endPos = None, None
    if not start or not end and len( cmds.ls( sl=True ) ) == 2:
        startPos = cmds.xform( cmds.ls( sl=True )[0], translation=True, query=True, ws=True )
        endPos = cmds.xform( cmds.ls( sl=True )[1], translation=True, query=True, ws=True )
    else:
        if type( start ) == type( 'hello' ) or type( start ) == type( u'hello' ):
            startPos = cmds.xform( str(start), translation=True, query=True, ws=True )
        else:
            startPos = start
            
        if type( end ) == type( 'hello' ) or type( end ) == type( u'hello' ):    
            endPos = cmds.xform( str(end), translation=True, query=True, ws=True )
        else:
            endPos = end

    if not startPos or not endPos:
        return showDialog( 'Argument Error', 'Cannot determine start and end points' )
        
    startVec = om.MVector(startPos[0], startPos[1], startPos[2])
    endVec = om.MVector(endPos[0], endPos[1], endPos[2])
    newVec = endVec - startVec
    segLength = newVec.length() / divisions
    newVec.normalize()
    
    points = []
    
    points.append(tuple(startPos))

    for p in range( 1, divisions ):
        point = newVec * segLength * p + startVec
        points.append((point.x, point.y, point.z))
        
    points.append(tuple(endPos))
    
    return points
Example #9
0
def readJoints( char ):
    '''
    reads joint data for the specified character.
    First, attemps to locate charName_joints.py in the character's local directory.
    If this fails, loads in the data from the default character
    
    '''
    jointFile = os.path.join(common.getCharDir( char ), '%s_joints.py' % char)
    if not os.path.exists(jointFile):
        if showDialog( title='WARNING', message='Character %s joint data not found.\n Would you like to load default joint data?' % char, button=['yes', 'no'] ) != 'yes':
            return 'User cancelled'
        jointFile = os.path.join(common.getCharDir( 'defaultChar' ), 'defaultChar_joints.py')
        
    f = open(jointFile, 'r')
    jointDict = json.loads(f.readline())
    f.close()
    
    return jointDict
Example #10
0
def insertGroup( node=None ):
    '''
    creates an empty group aligned to the selected node and inserts it into the hierarchy;
    
    '''
    if not node:
        node = cmds.ls(sl=1)[0]
    if node:
        parent = cmds.listRelatives(node, p=1)
        grp = cmds.group(empty=1, n='%s_grp' % node)
        align(node=grp, target=node)
        if parent:
            cmds.parent(grp, parent)
            
        cmds.parent(node, grp)
        
        return grp
    else:
        return showDialog( 'Argument Error', 'Cannot determine the node you wish to group' )
Example #11
0
def importGeo(char):
    '''
    imports the charName_geo.ma file from the character's directory if one exists.
    If no file exists, asks whether you want to import the default geo.
    
    Returns a list of new nodes added to the scene (rnn flag)
    
    '''
    geoFile = os.path.join(common.getCharDir( char ), '%s_geo.ma' % char)
    if not os.path.exists(geoFile):
        if showDialog( title='WARNING', message='Character %s geometry file not found.\n Would you like to load default geometry?' % char, button=['yes', 'no'] ) != 'yes':
            return 'User cancelled'
        geoFile = os.path.join(common.getCharDir( 'defaultChar' ), 'defaultChar_geo.ma')
        
    importList = cmds.file(geoFile, i=1, dns=1, rnn=1)
    
    meshNodes = [ m for m in importList if m.split('_')[-1] == 'mesh' ]
    
    return meshNodes
Example #12
0
def importControl(fileName):

    """
    Import control from file
    
    """

    workspace = os.path.join(os.path.dirname(__file__), "..", "assets")

    ctrlFile = os.path.join(workspace, "%s_CTRL.ma" % fileName)

    if not os.path.exists(ctrlFile):
        if (
            showDialog(
                title="WARNING",
                message="Character %s control file not found.\n Please choose an existing control" % fileName,
                button=["ok"],
            )
            == "ok"
        ):
            return "User cancelled"

    cmds.file(ctrlFile, i=True, dns=True)
Example #13
0
def getSkinWeights(char="", meshes=[]):
    """
	saves skinweights of supplied or selected geometries to a file
	the data is store in nested dictionaries in this structure
	{geometry{vertexId{influenceId:weight}...}...}
	"""

    # abort if no char is given
    if char == "":
        return cmds.warning("No character selected. Please supply a character name in function call.")

        # abort if there no mesh supplied or selected
    if meshes == []:
        meshes = cmds.ls(sl=1)
        print("No meshes supplied as param, attempting to use selected objects(%s)." % meshes)
        if meshes == []:
            return cmds.warning("No mesh to export weights from. Please select a mesh.")

            # check if output file already exists
    charDir = common.getCharDir(char)
    skinWeightsFile = os.path.join(charDir, "%s_skin.py" % char)

    if os.path.isfile(skinWeightsFile):
        if (
            cmds.confirmDialog(title="Warning", message="Overwrite existing skin weights data?", button=["yes", "no"])
            != "yes"
        ):
            return "User cancelled"

    allWeights = {}

    for mesh in meshes:
        # find skinCluster
        clusterName = mel.eval("findRelatedSkinCluster " + mesh)

        # abort if there is no skinCluster
        if clusterName == "":
            cmds.warning("No skinCluster found, " + mesh + " is not bound to a skeleton?")
            meshes.remove(mesh)
            break

            # prune to get rid of 0 zero value indices
        normState = cmds.getAttr("%s.normalizeWeights" % clusterName)
        shapeName = cmds.listRelatives(mesh, shapes=True)[0]
        cmds.setAttr("%s.normalizeWeights" % clusterName, False)
        cmds.skinPercent(clusterName, shapeName, normalize=False, pruneWeights=0.001)
        cmds.setAttr("%s.normalizeWeights" % clusterName, normState)

        # get the MFnSkinCluster for clusterName
        selList = om.MSelectionList()
        selList.add(clusterName)
        clusterNode = om.MObject()
        selList.getDependNode(0, clusterNode)
        skinFn = oma.MFnSkinCluster(clusterNode)

        # get the MDagPath for all influence
        infDags = om.MDagPathArray()
        skinFn.influenceObjects(infDags)

        # create a dictionary whose key is the MPlug indice id and
        # whose value is the influence list id
        infIds = {}
        infs = []
        for i in xrange(infDags.length()):
            infPath = infDags[i].fullPathName()
            infId = int(skinFn.indexForInfluenceObject(infDags[i]))
            infIds[infId] = i
            infs.append(infPath)

            # get weightList and weight plugs
        weightListPlug = skinFn.findPlug("weightList")
        weightsPlug = skinFn.findPlug("weights")
        weightListAttr = weightListPlug.attribute()
        weightsAttr = weightsPlug.attribute()
        weightsInfIds = om.MIntArray()

        # the weights are stored in dictionary, the key is the vertId,
        # the value is another dictionary whose key is the influence id and
        # value is the weight for that influence
        # first key 'infs' is the list of influences in bind order
        weights = {}
        weights["infs"] = infs
        for vertId in xrange(weightListPlug.numElements()):
            vertWeights = {}
            weightsPlug.selectAncestorLogicalIndex(vertId, weightListAttr)

            weightsPlug.getExistingArrayAttributeIndices(weightsInfIds)

            infPlug = om.MPlug(weightsPlug)
            for infId in weightsInfIds:

                infPlug.selectAncestorLogicalIndex(infId, weightsAttr)

                try:
                    vertWeights[infIds[infId]] = infPlug.asDouble()
                except KeyError:
                    pass

            weights[vertId] = vertWeights

        allWeights[mesh] = weights

        # save data to file
    f = open(skinWeightsFile, "w")
    f.write(json.dumps(allWeights))
    f.close()
    showDialog("Succss!", 'Skin weights for [ %s ] saved to file:\n"%s_skin.py"' % (", ".join(meshes), skinWeightsFile))

    return allWeights
Example #14
0
def build(
    hips=None, chest=None, head=None, numSpineJoints=6, numHeadJoints=6, twistAxis="x", bendAxis="y", cleanUp=True
):
    """
    function to create the fk spine with head isolation...
    
    requires 3 objects to be selected or supplied - hips, chest, head
    
    hips: location of the first spine joint - this joint doesn't inherit any chest rotation
    chest: where the chest ctrl is placed. It's rotation is distributed from the second spine joint up to this point
    head: location of the last spine joint

    """

    axisDict = {"x": [1, 0, 0], "y": [0, 1, 0], "z": [0, 0, 1]}

    # Validate that the correct arguments have been supplied
    if not hips or not chest or not head:
        # If hips, chest anf head aren't explicitly supplied, check for a valid selection to use
        sel = cmds.ls(sl=1, type="transform")
        if len(sel) == 3:
            hips, chest, head = sel[0], sel[1], sel[2]
        else:
            return showDialog("Argument Error", "Cannot determine hips, chest and head points")

    # Get positions of spine and head joints
    spineLocs = common.pointsAlongVector(start=hips, end=chest, divisions=numSpineJoints - 1)
    headLocs = common.pointsAlongVector(start=chest, end=head, divisions=numHeadJoints - 1)
    spineLocs.extend(headLocs[1:])

    xformGrp = cmds.group(empty=1)
    xformGrp = cmds.rename(
        xformGrp, common.getName(node=xformGrp, side="cn", rigPart="spine", function="xform", nodeType="grp")
    )
    common.align(node=xformGrp, target=hips)
    aimConst = cmds.aimConstraint(
        chest, xformGrp, aimVector=axisDict[twistAxis], upVector=axisDict[bendAxis], worldUpVector=[1, 0, 0]
    )
    cmds.delete(aimConst)

    # Build control objects
    hipCtrl = controls.Control(
        side="cn", rigPart="spine", function="hips", nodeType="ctrl", size=1.25, color="green", aimAxis="twistAxis"
    )
    hipCtrl.circleCtrl()
    hipGrp = common.insertGroup(node=hipCtrl.control)
    hipGrp = cmds.rename(hipGrp, hipCtrl.control.replace("ctrl", "grp"))
    common.align(node=hipGrp, target=xformGrp)
    cmds.parent(hipGrp, xformGrp)

    chestCtrl = controls.Control(
        side="cn", rigPart="spine", function="chest", nodeType="ctrl", size=1.25, color="green", aimAxis="twistAxis"
    )
    chestCtrl.circleCtrl()
    chestGrp = common.insertGroup(node=chestCtrl.control)
    chestGrp = cmds.rename(chestGrp, chestCtrl.control.replace("ctrl", "grp"))
    common.align(node=chestGrp, orient=False, target=chest)
    common.align(node=chestGrp, translate=False, target=xformGrp)
    cmds.parent(chestGrp, hipCtrl.control)

    headCtrl = controls.Control(
        side="cn", rigPart="spine", function="head", nodeType="ctrl", size=1.25, color="green", aimAxis="twistAxis"
    )
    headCtrl.crownCtrl()
    headGrp = common.insertGroup(node=headCtrl.control)
    headGrp = cmds.rename(headGrp, headCtrl.control.replace("ctrl", "grp"))
    common.align(node=headGrp, target=head, orient=False)
    common.align(node=headGrp, target=xformGrp, translate=False)
    cmds.parent(headGrp, xformGrp)

    # Add attr to head ctrl for isolating head rotation
    cmds.addAttr(headCtrl.control, longName="isolate_rotation", at="double", keyable=True, min=0, max=1)

    # Build driven groups
    spineGrps = []
    for i in range(len(spineLocs)):
        g = cmds.group(empty=1)
        g = cmds.rename(
            g, common.getName(node=g, side="cn", rigPart="spine", function="driven%s" % str(i + 1), nodeType="grp")
        )
        spineGrps.append(g)
        cmds.setAttr("%s.t" % g, spineLocs[i][0], spineLocs[i][1], spineLocs[i][2])
        common.align(node=g, target=xformGrp, translate=False)
        if i > 0:
            cmds.parent(g, spineGrps[i - 1])
        else:
            cmds.parent(g, xformGrp)
            cmds.parentConstraint(hipCtrl.control, g)

    # Build joints
    spineJoints = []
    for i in range(len(spineLocs)):
        cmds.select(spineGrps[i])
        j = cmds.joint()
        common.align(node=j, target=xformGrp, translate=False)
        cmds.setAttr("%s.jointOrient" % j)
        j = cmds.rename(
            j, common.getName(node=j, side="cn", rigPart="spine", function="driven%s" % str(i + 1), nodeType="jnt")
        )
        spineJoints.append(j)
        cmds.setAttr("%s.displayLocalAxis" % j, 1)

    # set rotation orders
    leanAxis = [axis for axis in ["x", "y", "z"] if not axis in [twistAxis, bendAxis]][0]
    rotateOrder = "%s%s%s" % (twistAxis, leanAxis, bendAxis)
    rotateOrderDict = {"xyz": 0, "yzx": 1, "zxy": 2, "xzy": 3, "yxz": 4, "zyx": 5}

    for i in (
        [hipGrp, hipCtrl.control, chestGrp, chestCtrl.control, headGrp, headCtrl.control] + spineGrps + spineJoints
    ):
        cmds.setAttr("%s.rotateOrder" % i, rotateOrderDict[rotateOrder])

    # connect driven groups and joints below chest to chest control rotations
    spineBendUC = cmds.createNode("unitConversion")
    spineBendUC = cmds.rename(
        spineBendUC, common.getName(node=spineBendUC, side="cn", rigPart="spine", function="bend", nodeType="conv")
    )
    cmds.connectAttr("%s.r%s" % (chestCtrl.control, bendAxis), "%s.input" % spineBendUC)
    cmds.setAttr("%s.conversionFactor" % spineBendUC, 1.0 / (numSpineJoints - 1))

    spineLeanUC = cmds.createNode("unitConversion")
    spineLeanUC = cmds.rename(
        spineLeanUC, common.getName(node=spineLeanUC, side="cn", rigPart="spine", function="lean", nodeType="conv")
    )
    cmds.connectAttr("%s.r%s" % (chestCtrl.control, leanAxis), "%s.input" % spineLeanUC)
    cmds.setAttr("%s.conversionFactor" % spineLeanUC, 1.0 / (numSpineJoints - 1))

    for grp in spineGrps[1:numSpineJoints]:
        cmds.connectAttr("%s.output" % spineBendUC, "%s.r%s" % (grp, bendAxis))
        cmds.connectAttr("%s.output" % spineLeanUC, "%s.r%s" % (grp, leanAxis))

    for i in range(numSpineJoints - 1):
        spineTwistUC = cmds.createNode("unitConversion")
        spineTwistUC = cmds.rename(
            spineTwistUC,
            common.getName(node=spineTwistUC, side="cn", rigPart="spine", function="twist%s" % i, nodeType="conv"),
        )
        cmds.connectAttr("%s.r%s" % (chestCtrl.control, twistAxis), "%s.input" % spineTwistUC)
        cmds.setAttr("%s.conversionFactor" % spineTwistUC, 1.0 / (numSpineJoints - 1) * (i + 1))
        cmds.connectAttr("%s.output" % spineTwistUC, "%s.r%s" % (spineJoints[i + 1], twistAxis))

    # connect driven groups above chest to reverse chest control rotations + hips control rotations
    hipRotUC = cmds.createNode("unitConversion")
    hipRotUC = cmds.rename(
        hipRotUC, common.getName(node=hipRotUC, side="cn", rigPart="spine", function="hipRotate", nodeType="conv")
    )
    cmds.setAttr("%s.conversionFactor" % hipRotUC, -1)
    cmds.connectAttr("%s.r" % hipCtrl.control, "%s.input" % hipRotUC)
    hipRotMD = cmds.createNode("multiplyDivide")
    hipRotMD = cmds.rename(
        hipRotMD, common.getName(node=hipRotMD, side="cn", rigPart="spine", function="hipRotate", nodeType="multDiv")
    )
    cmds.connectAttr("%s.output" % hipRotUC, "%s.input1" % hipRotMD)
    cmds.connectAttr("%s.isolate_rotation" % headCtrl.control, "%s.input2X" % hipRotMD)
    cmds.connectAttr("%s.isolate_rotation" % headCtrl.control, "%s.input2Y" % hipRotMD)
    cmds.connectAttr("%s.isolate_rotation" % headCtrl.control, "%s.input2Z" % hipRotMD)

    chestRotUC = cmds.createNode("unitConversion")
    chestRotUC = cmds.rename(
        chestRotUC, common.getName(node=chestRotUC, side="cn", rigPart="spine", function="chestRotate", nodeType="conv")
    )
    cmds.setAttr("%s.conversionFactor" % chestRotUC, -1)
    cmds.connectAttr("%s.r" % chestCtrl.control, "%s.input" % chestRotUC)
    chestRotMD = cmds.createNode("multiplyDivide")
    chestRotMD = cmds.rename(
        chestRotMD,
        common.getName(node=chestRotMD, side="cn", rigPart="spine", function="chestRotate", nodeType="multDiv"),
    )
    cmds.connectAttr("%s.output" % chestRotUC, "%s.input1" % chestRotMD)
    cmds.connectAttr("%s.isolate_rotation" % headCtrl.control, "%s.input2X" % chestRotMD)
    cmds.connectAttr("%s.isolate_rotation" % headCtrl.control, "%s.input2Y" % chestRotMD)
    cmds.connectAttr("%s.isolate_rotation" % headCtrl.control, "%s.input2Z" % chestRotMD)

    headRotUC = cmds.createNode("unitConversion")
    headRotUC = cmds.rename(
        headRotUC, common.getName(node=headRotUC, side="cn", rigPart="spine", function="headRotate", nodeType="conv")
    )
    cmds.setAttr("%s.conversionFactor" % headRotUC, 1)
    cmds.connectAttr("%s.r" % headCtrl.control, "%s.input" % headRotUC)

    # negative hip and chest rotation are added to head rotation. The negative values are piped through a multiplier to blend the head isolation off and on
    spineRotNegPMA = cmds.createNode("plusMinusAverage")
    spineRotNegPMA = cmds.rename(
        spineRotNegPMA,
        common.getName(node=spineRotNegPMA, side="cn", rigPart="spine", function="rotateNeg", nodeType="pma"),
    )
    cmds.connectAttr("%s.output" % hipRotMD, "%s.input3D[0]" % spineRotNegPMA)
    cmds.connectAttr("%s.output" % chestRotMD, "%s.input3D[1]" % spineRotNegPMA)
    cmds.connectAttr("%s.output" % headRotUC, "%s.input3D[2]" % spineRotNegPMA)

    spineBendNegUC = cmds.createNode("unitConversion")
    spineBendNegUC = cmds.rename(
        spineBendNegUC,
        common.getName(node=spineBendNegUC, side="cn", rigPart="spine", function="bendNeg", nodeType="conv"),
    )
    cmds.connectAttr("%s.output3D%s" % (spineRotNegPMA, bendAxis), "%s.input" % spineBendNegUC)
    cmds.setAttr("%s.conversionFactor" % spineBendNegUC, 1.0 / (numHeadJoints - 2))

    spineLeanNegUC = cmds.createNode("unitConversion")
    spineLeanNegUC = cmds.rename(
        spineLeanNegUC,
        common.getName(node=spineLeanNegUC, side="cn", rigPart="spine", function="leanNeg", nodeType="conv"),
    )
    cmds.connectAttr("%s.output3D%s" % (spineRotNegPMA, leanAxis), "%s.input" % spineLeanNegUC)
    cmds.setAttr("%s.conversionFactor" % spineLeanNegUC, 1.0 / (numHeadJoints - 2))

    for grp in spineGrps[numSpineJoints:-1]:
        cmds.connectAttr("%s.output" % spineBendNegUC, "%s.r%s" % (grp, bendAxis))
        cmds.connectAttr("%s.output" % spineLeanNegUC, "%s.r%s" % (grp, leanAxis))

    # Direct output from chest control. If head isolation is off. All twist joints above it recieve 100% of its twisting
    chestTwistDirectUC = cmds.createNode("unitConversion")
    chestTwistDirectUC = cmds.rename(
        chestTwistDirectUC,
        common.getName(node=chestTwistDirectUC, side="cn", rigPart="spine", function="chestTwist", nodeType="conv"),
    )
    cmds.connectAttr("%s.r%s" % (chestCtrl.control, twistAxis), "%s.input" % chestTwistDirectUC)
    cmds.setAttr("%s.conversionFactor" % chestTwistDirectUC, 1.0)

    for i in range(numSpineJoints + 1, len(spineJoints)):
        # gradually negate hip twist from chest up
        hipTwistUC = cmds.createNode("unitConversion")
        hipTwistUC = cmds.rename(
            hipTwistUC,
            common.getName(node=hipTwistUC, side="cn", rigPart="spine", function="hipTwist%s" % i, nodeType="conv"),
        )
        cmds.connectAttr("%s.r%s" % (hipCtrl.control, twistAxis), "%s.input" % hipTwistUC)
        cmds.setAttr("%s.conversionFactor" % hipTwistUC, -1.0 / (numHeadJoints - 2) * (i - numSpineJoints))

        # gradually negate chest twist from chest up
        chestTwistUC = cmds.createNode("unitConversion")
        chestTwistUC = cmds.rename(
            chestTwistUC,
            common.getName(node=chestTwistUC, side="cn", rigPart="spine", function="chestTwist%s" % i, nodeType="conv"),
        )
        cmds.connectAttr("%s.r%s" % (chestCtrl.control, twistAxis), "%s.input" % chestTwistUC)
        cmds.setAttr("%s.conversionFactor" % chestTwistUC, 1.0 / (numHeadJoints - 2) * (len(spineJoints) - (i + 1)))

        # sum hip and chest negation
        spineTwistNegPMA = cmds.createNode("plusMinusAverage")
        spineTwistNegPMA = cmds.rename(
            spineTwistNegPMA,
            common.getName(
                node=spineTwistNegPMA, side="cn", rigPart="spine", function="twistNeg%s" % i, nodeType="pma"
            ),
        )
        cmds.connectAttr("%s.output" % hipTwistUC, "%s.input1D[0]" % spineTwistNegPMA)
        cmds.connectAttr("%s.output" % chestTwistUC, "%s.input1D[1]" % spineTwistNegPMA)

        # Distribute head twist down to chest
        spineTwistUC = cmds.createNode("unitConversion")
        spineTwistUC = cmds.rename(
            spineTwistUC,
            common.getName(node=spineTwistUC, side="cn", rigPart="spine", function="twist%s" % i, nodeType="conv"),
        )
        cmds.connectAttr("%s.r%s" % (headCtrl.control, twistAxis), "%s.input" % spineTwistUC)
        cmds.setAttr("%s.conversionFactor" % spineTwistUC, 1.0 / (numHeadJoints - 2) * (i - numSpineJoints))

        # Blend between hip and chest negation (head isolation on) and full inheritance of chest twist (head isolation off)
        spineTwistNegBC = cmds.createNode("blendColors")
        spineTwistNegBC = cmds.rename(
            spineTwistNegBC,
            common.getName(node=spineTwistNegBC, side="cn", rigPart="spine", function="twistNeg%s" % i, nodeType="bc"),
        )
        cmds.connectAttr("%s.output1D" % spineTwistNegPMA, "%s.color1R" % spineTwistNegBC)
        cmds.connectAttr("%s.output" % chestTwistDirectUC, "%s.color2R" % spineTwistNegBC)
        cmds.connectAttr("%s.isolate_rotation" % headCtrl.control, "%s.blender" % spineTwistNegBC)

        # Sum blended negation twist and head twist
        spineTwistPMA = cmds.createNode("plusMinusAverage")
        spineTwistPMA = cmds.rename(
            spineTwistPMA,
            common.getName(
                node=spineTwistPMA, side="cn", rigPart="spine", function="twistResult%s" % i, nodeType="pma"
            ),
        )
        cmds.connectAttr("%s.outputR" % spineTwistNegBC, "%s.input1D[0]" % spineTwistPMA)
        cmds.connectAttr("%s.output" % spineTwistUC, "%s.input1D[1]" % spineTwistPMA)

        # Force unit conversion to 1
        spineTwistResultUC = cmds.createNode("unitConversion")
        spineTwistResultUC = cmds.rename(
            spineTwistResultUC,
            common.getName(
                node=spineTwistResultUC, side="cn", rigPart="spine", function="twistResult%s" % i, nodeType="conv"
            ),
        )
        cmds.connectAttr("%s.output1D" % spineTwistPMA, "%s.input" % spineTwistResultUC)
        cmds.setAttr("%s.conversionFactor" % spineTwistResultUC, 1.0)

        cmds.connectAttr("%s.output" % spineTwistResultUC, "%s.r%s" % (spineJoints[i - 1], twistAxis))

    # Orient contstrain last head joint to second last head joint
    orientConst = cmds.orientConstraint(spineJoints[-2], spineJoints[-1])
    # Point constrain chest ctrl grp to its spine group
    pointConst = cmds.pointConstraint(spineGrps[numSpineJoints - 1], chestGrp)
    # Point constrain head ctrl grp to last spine group
    pointConst = cmds.pointConstraint(spineGrps[-1], headGrp)
    # Add orient constraint to headCtrl group - weighted between root noXformGrp and last spine grp - weight controlled by isolation attr
    orientConst = cmds.orientConstraint(xformGrp, chestCtrl.control, headGrp)[0]
    isolateRev = cmds.createNode("reverse")
    isolateRev = cmds.rename(
        isolateRev, common.getName(node=isolateRev, side="cn", rigPart="spine", function="headIsolate", nodeType="rev")
    )
    cmds.connectAttr("%s.isolate_rotation" % headCtrl.control, "%s.inputX" % isolateRev)
    cmds.connectAttr("%s.isolate_rotation" % headCtrl.control, "%s.%sW0" % (orientConst, xformGrp), f=1)
    cmds.connectAttr("%s.outputX" % isolateRev, "%s.%sW1" % (orientConst, chestCtrl.control), f=1)
    cmds.setAttr("%s.interpType" % orientConst, 2)

    # Clean up attributes and objects that need to be hidden / locked
    if cleanUp:
        cmds.setAttr("%s.visibility" % spineGrps[0], 0)
        common.attrCtrl(nodeList=[spineGrps[1]], attrList=["visibility"])
        common.attrCtrl(nodeList=[hipCtrl.control], attrList=["sx", "sy", "sz", "visibility"])
        common.attrCtrl(
            nodeList=[chestCtrl.control, headCtrl.control], attrList=["tx", "ty", "tz", "sx", "sy", "sz", "visibility"]
        )

    returnDict = collections.defaultdict(list)
    returnDict["xformGrp"].append(xformGrp)
    returnDict["hipCtrl"].append(hipCtrl.control)
    returnDict["chestCtrl"].append(chestCtrl.control)
    returnDict["headCtrl"].append(headCtrl.control)

    return returnDict
Example #15
0
def setSkinWeights(char="", meshes=[]):
    """
	applies skinweights from file to supplied or selected geometries
	(which need to already have a skincluster)
	"""

    # abort if no char is given
    if char == "":
        return cmds.warning("No character selected. Please supply a character name in function call.")

        # abort if there no mesh supplied or selected
    if meshes == []:
        meshes = cmds.ls(sl=1)
        print("No meshes supplied as param, attempting to use selected objects(%s)." % ", ".join(meshes))
        if meshes == []:
            return cmds.warning("No mesh to export weights from. Please select a mesh.")

            # get path to skin file
    charDir = common.getCharDir(char)
    skinWeightsFile = os.path.join(charDir, "%s_skin.py" % char)

    # use default skinWeightsFile if character specific file does not exist
    if not os.path.exists(skinWeightsFile):
        skinWeightsFile = os.path.join(common.getCharDir("defaultChar"), "defaultChar_skin.py")
        cmds.warning("Did not find skin weights file for selected character, using default character file.")

        # read skin weights from file
    f = open(skinWeightsFile, "r")
    allWeights = json.loads(f.readline())
    f.close()

    # compare meshes to keys of allWeights dictionary
    print("File contains skinweights for: " + ",".join(allWeights.keys()))
    for mesh in meshes:
        if mesh not in allWeights.keys():
            cmds.warning("No weights found for %s" % mesh)
            meshes.remove(mesh)

    for mesh in meshes:

        # find skinCluster
        clusterName = mel.eval("findRelatedSkinCluster " + mesh)

        if clusterName == "":
            cmds.warning("No skinclutser found on %s." % mesh)
            break

        weights = allWeights[mesh]

        # unlock influences
        infs = cmds.skinCluster(clusterName, q=True, weightedInfluence=True)
        for inf in infs:
            cmds.setAttr("%s.liw" % inf, False)

            # prune weights to get rid of weights not stored in skinWeightsFile
            # normalize needs to be turned off for the prune to work
        normState = cmds.getAttr("%s.normalizeWeights" % clusterName)
        shapeName = cmds.listRelatives(mesh, shapes=True)[0]
        cmds.setAttr("%s.normalizeWeights" % clusterName, False)
        cmds.skinPercent(clusterName, shapeName, normalize=False, pruneWeights=100.0)
        cmds.setAttr("%s.normalizeWeights" % clusterName, normState)

        # pop influences key
        if "infs" in weights:
            weights.pop("infs")

        # set weights in skinCluster.weightsList[].weights[] to infValue
        for vertId, weightData in weights.items():
            weightListAttr = "%s.weightList[%s]" % (clusterName, vertId)
            for infId, infValue in weightData.items():
                weightsAttr = ".weights[%s]" % infId
                cmds.setAttr(weightListAttr + weightsAttr, infValue)

    showDialog(
        "Succss!", 'Skin weights applied to [ %s ] from file:\n"%s_skin.py"' % (", ".join(meshes), skinWeightsFile)
    )

    return
Example #16
0
def build( joint=None, twistAxis='x', name='' ):
    '''
    Creates a duplicate of the specified joint which will remove the twist.
    Based on Victor Vinyal's nonroll setup
    Duplicates the joint and deletes all children apart from the first child joint ( there must at least a single child joint in the hierarchy )
    Creates an RP IKHandle with the pole vector set to zero
    Parents the pole vector to the original joint
    
    point constrains the nonRoll to the joint
    
    groups the nonRoll outside the hierarchy
    
    Also creates an 'info' locator which is parented to 'nonRoll' and aim constrained to 'nonRollEnd' using 'joint' as its up vector -
         - this is the node from which to read the twist value
    
    '''
        
    if not joint:
        if len(cmds.ls(sl=1, exactType='joint'))==1:
            joint = cmds.ls(sl=1, exactType='joint')[0]
        else:
            return showDialog( 'Argument Error', 'Please provide a joint' )
        
        
    prefix = '%s_%s' % (common.getSide(joint), name)
       
    # main group for nonRoll system
    main_grp = cmds.group( empty=1, n='%s_nonRoll_grp' % prefix )
    common.align( main_grp, joint )
    
    # Duplicate the joints and delete all but first child joint
    copies = cmds.duplicate( joint, name='%s_nonRoll_jnt' % prefix, rc=1 )
    nonRoll = copies[ 0 ]
    nonRollEnd = cmds.listRelatives( nonRoll, c=1, type='joint' )[ 0 ]
    deleteList = [ c for c in copies if not c in [ nonRoll, nonRollEnd ] ]
    if deleteList:
        cmds.delete( deleteList )        
    nonRollEnd = cmds.rename( nonRollEnd, '%s_nonRoll_end' % prefix )
    
    rad = cmds.getAttr( '%s.radius' % nonRoll ) * 1.5
    cmds.setAttr( '%s.radius' % nonRoll, rad )
    cmds.setAttr( '%s.radius' % nonRollEnd, rad )
    
    cmds.parent( nonRoll, main_grp )
    cmds.pointConstraint( joint, nonRoll )
    
    # build ikHandle
    ikHandle = cmds.ikHandle( sj=nonRoll, ee=nonRollEnd, n='%s_nonRoll_ikHandle' % prefix, sol='ikRPsolver' )[ 0 ]
    cmds.setAttr( '%s.poleVectorX' % ikHandle, 0 )
    cmds.setAttr( '%s.poleVectorY' % ikHandle, 0 )
    cmds.setAttr( '%s.poleVectorZ' % ikHandle, 0 )
    
    cmds.parent( ikHandle, joint )
    
    # build info locator
    info = cmds.spaceLocator( n='%s_nonRoll_info' % prefix )[ 0 ]
    common.align( info, joint )
    cmds.parent( info, nonRoll )
    
    if cmds.getAttr( '%s.t%s' % (nonRollEnd, twistAxis)) < 0:
        aimVec = ( -1, 0, 0 )
    else:
        aimVec = ( 1, 0, 0 )
    cmds.aimConstraint( nonRollEnd, info, aimVector=aimVec, wut='objectrotation', wuo=joint )
    
    returnDict = {
                  'main_grp':main_grp,
                  'nonRoll':nonRoll,
                  'nonRollEnd':nonRollEnd,
                  'ikHandle':ikHandle,
                  'info':info
                  }
    
    return returnDict
        
        
Example #17
0
def rebindSkinClusters(char="", meshes=[]):
    """
	delete and recreate skinclusters on supplied or selected meshes
	with influences from skinWeightsFile
	"""

    # abort if no char is given
    if char == "":
        return cmds.warning("No character selected. Please supply a character name in function call.")

        # abort if there no mesh supplied or selected
    if meshes == []:
        meshes = cmds.ls(sl=1)
        print("No meshes supplied as param, attempting to use selected objects(%s)." % ", ".join(meshes))
        if meshes == []:
            return cmds.warning("No mesh to found. Please select a mesh.")

            # confirm rebind
    if (
        cmds.confirmDialog(
            title="Warning",
            message="Delete and rebind skinclusters for [ %s ]?" % ", ".join(meshes),
            button=["yes", "no"],
        )
        != "yes"
    ):
        return "User cancelled"

        # get path to skin file
    charDir = common.getCharDir(char)
    skinWeightsFile = os.path.join(charDir, "%s_skin.py" % char)

    # use default skinWeightsFile if character specific file does not exist
    if not os.path.exists(skinWeightsFile):
        skinWeightsFile = os.path.join(common.getCharDir("defaultChar"), "defaultChar_skin.py")
        cmds.warning("Did not find skin weights file for selected character, using default character file.")

        # read skin weights from file
    f = open(skinWeightsFile, "r")
    allWeights = json.loads(f.readline())
    f.close()

    # remove meshes for which there is no infs-key or weight dictionary
    for mesh in meshes:
        if mesh not in allWeights.keys():
            cmds.warning("No weights dictionary found for %s" % mesh)
            meshes.remove(mesh)
        if "infs" not in allWeights[mesh].keys():
            cmds.warning("No Influences key found for %s" % mesh)
            meshes.remove(mesh)

    skinclusters = []
    for mesh in meshes:
        weights = allWeights[mesh]

        # unbind mesh if skincluster exists
        clusterName = mel.eval("findRelatedSkinCluster " + mesh)
        if clusterName != "":
            cmds.skinCluster(mesh, edit=True, unbind=True)

            # rebind
        skincluster = cmds.skinCluster(
            weights["infs"],
            mesh,
            name="skincluster_" + str(mesh),
            toSelectedBones=True,
            maximumInfluences=5,
            obeyMaxInfluences=False,
            skinMethod=0,
        )[0]
        skinclusters.append(skincluster)

    showDialog(
        "Succss!", 'Skinclusters rebound on [ %s ] from file:\n"%s_skin.py"' % (", ".join(meshes), skinWeightsFile)
    )
    cmds.select(meshes)

    return skinclusters