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}
def build( side = None, jntFoot = None, ctrlFoot = None, ikHandleLeg = None, mesh = None, stretchLoc = None, cleanUp = 0 ): ''' builds a reverse foot! creates roll pivots, adds attributes to foot control and sets up the contact lattice. function requires the side, foot joint (in richards limb module the extra_jnt), foot control and ik handle to be supplied. The character's mesh is needed for contact lattice deformer and will be used for getting the pivot locations from a set of specific vertices. DO NOT FORGET: If the rig is build before there is a skincluster attached to the mesh you will need to reorder the deformers. returns a dictionary containing corresponding objects for these keys: joints, pivots, ikHandles, lattice, systemsGrp, ctrls ''' # abort if not all arguments were supplied if not jntFoot or not ctrlFoot or not ikHandleLeg or not mesh or not stretchLoc: return cmds.warning( 'Argument Error: Please supply all arguments (side, joint_footExtraEnd, control, ikHandle, mesh).' ) # vertex indices for left / right pivotVertsLeft = [196, 199, 29, 28] latticeVertIdsLeft = ['0:1', '8:9', '28:29', '39:42', '47:48', '51:52', '55:58', '63:64', '67:70', '196', '199', '206:207', '211:212', '241:242', '253', '264:265', '268:273', '278:279', '282:285', '290:291', '294:297', '302:303', '409', '414', '418', '434', '437:438', '447:448'] pivotVertsRight = [219, 230, 36, 35] latticeVertIdsRight = ['14:15', '24:25', '35:36', '43:46', '49:50', '53:54', '59:62', '65:66', '71:74', '219', '230:232', '237:238', '248:249', '258', '261:262', '266:267', '274:277', '280:281', '286:289', '292:293', '298:301', '304:305', '424:426', '430:431', '441:443'] # set side relevant data, abort if no side specified if side in ['lf', 'left', 'lft']: pivotVerts = pivotVertsLeft latticeVertIds = latticeVertIdsLeft sideColor = 'blue' elif side in ['rt', 'right', 'rgt']: pivotVerts = pivotVertsRight latticeVertIds = latticeVertIdsRight sideColor = 'red' else: return cmds.warning( 'No valid side specified' ) # create output dictionary outDict = {} # add attributes to foot control, if attribute already exists skip it attrs = ['roll', 'rollBreak', 'side', 'toeTap', 'toeRaise', 'toeTwist', 'heelTwist', 'squashGroundContact'] for attr in attrs: if ( cmds.attributeQuery( attr, node=ctrlFoot, exists=True ) ) == True: print( 'Attribute %s already exists on %s.' % ( attr, ctrlFoot ) ) else: cmds.addAttr( ctrlFoot, longName=attr, attributeType='float', keyable = True ) useDefaultPivots = False # create pivot locators if useDefaultPivots == True: # set default pivot positions pivotOffset = 0.5 jntFootPos = cmds.xform( jntFoot, q = True, translation = True, ws = True ) pivotFrontPos = [ jntFootPos[0], jntFootPos[1], jntFootPos[2] + pivotOffset ] pivotRearPos = [ jntFootPos[0], jntFootPos[1], jntFootPos[2] - pivotOffset ] pivotLeftPos = [ jntFootPos[0] + pivotOffset, jntFootPos[1], jntFootPos[2] ] pivotRightPos = [ jntFootPos[0] - pivotOffset, jntFootPos[1], jntFootPos[2] ] else: # get pivot positions from vertices pivotFrontPos = cmds.xform( mesh + '.vtx[%s]' % pivotVerts[0], q = True, ws = True, t = True ) pivotRearPos = cmds.xform( mesh + '.vtx[%s]' % pivotVerts[1], q = True, ws = True, t = True ) pivotLeftPos = cmds.xform( mesh + '.vtx[%s]' % pivotVerts[2], q = True, ws = True, t = True ) pivotRightPos = cmds.xform( mesh + '.vtx[%s]' % pivotVerts[3], q = True, ws = True, t = True ) pivotFront = cmds.spaceLocator()[0] pivotFront = cmds.rename( pivotFront, common.getName( node=pivotFront, side=side, rigPart='foot', function='front_piv', nodeType='loc') ) cmds.xform( translation = pivotFrontPos ) pivotRear = cmds.spaceLocator()[0] pivotRear = cmds.rename( pivotRear, common.getName( node=pivotRear, side=side, rigPart='foot', function='rear_piv', nodeType='loc') ) cmds.xform( translation = pivotRearPos ) pivotLeft = cmds.spaceLocator()[0] pivotLeft = cmds.rename( pivotLeft, common.getName( node=pivotLeft, side=side, rigPart='foot', function='left_piv', nodeType='loc') ) cmds.xform( translation = pivotLeftPos ) pivotRight = cmds.spaceLocator()[0] pivotRight = cmds.rename( pivotRight, common.getName( node=pivotRight, side=side, rigPart='foot', function='right_piv', nodeType='loc') ) cmds.xform( translation = pivotRightPos ) cmds.parent( pivotFront, pivotRear ) cmds.parent( pivotRear, pivotLeft ) cmds.parent( pivotLeft, pivotRight ) pivotLocs = [pivotFront, pivotRear, pivotLeft, pivotRight] for pivotLoc in pivotLocs: cmds.setAttr( cmds.listRelatives( pivotLoc )[0] + '.localScale', .1, .1, .1 ) # reduce local scale #outDict['pivots'] = pivotLocs | done after creating ball locator # create ball and toe joint cmds.select( clear = True ) jntAnkle = cmds.joint() jntAnkle = cmds.rename(jntAnkle, common.getName( node=jntAnkle, side=side, rigPart='ankle', function='driven', nodeType='jnt')) cmds.xform( jntAnkle, ws = True, translation = ( cmds.xform( ikHandleLeg, q = True, t = True, ws = True ) ) ) cmds.setAttr( jntAnkle + '.radius', .75 * cmds.getAttr( jntFoot + '.radius' ) ) jntBall = cmds.joint() jntBall = cmds.rename(jntBall, common.getName( node=jntBall, side=side, rigPart='ball', function='driven', nodeType='jnt')) cmds.xform( jntBall, ws = True, t = ( cmds.xform( jntFoot, q = True, ws = True, t = True ) ) ) cmds.xform( jntBall, ws = True, relative = True, t = ( 0, 0, .5 * cmds.xform( pivotFront, q = True, t = True, ws = True )[2] ) ) cmds.setAttr( jntBall + '.radius', .75 * cmds.getAttr( jntFoot + '.radius' ) ) jntToe = cmds.joint() jntToe = cmds.rename(jntToe, common.getName( node=jntToe, side=side, rigPart='toe', function='driven', nodeType='jnt')) cmds.xform( jntToe, t = ( 0, 0, .5 * cmds.xform( pivotFront, q = True, t = True, ws = True )[2] ), relative = True, ws = True ) cmds.setAttr( jntToe + '.radius', cmds.getAttr( jntBall + '.radius' ) ) grpBufJnt = cmds.group ( empty = True ) grpBufJnt = cmds.rename( grpBufJnt, common.getName( node=grpBufJnt, side=side, rigPart='foot', function='jnt_buf', nodeType='grp' ) ) common.align( grpBufJnt, jntFoot, translate = True, orient = False ) cmds.parentConstraint( jntFoot, grpBufJnt, mo = False ) cmds.parent( jntAnkle, grpBufJnt ) grpJnts = cmds.group( empty = True ) grpJnts = cmds.rename( grpJnts, common.getName( node=grpJnts, side=side, rigPart='foot', function='jnts', nodeType='grp' ) ) common.align( grpJnts, ctrlFoot, translate = True, orient = False ) cmds.parent( grpBufJnt, grpJnts ) outDict['joints'] = [ jntAnkle, jntBall, jntToe ] # create toe IK handles ikHandleBall, ikEffectorBall = cmds.ikHandle( startJoint = jntAnkle, endEffector = jntBall, solver = 'ikSCsolver', name = '%s_ball_ikHandle' % side ) ikHandleToe, ikEffectorToe = cmds.ikHandle( startJoint = jntBall, endEffector = jntToe, solver = 'ikSCsolver', name = '%s_toe_ikHandle' % side ) cmds.parent( ikHandleBall, pivotRear ) cmds.parent( ikHandleToe, pivotFront ) outDict['ikHandles'] = [ ikHandleLeg, ikHandleBall, ikHandleToe ] # create ball pivot locator pivotBall = cmds.spaceLocator( name = common.getName( side=side, rigPart='foot', function='ball_piv', nodeType='loc') )[0] cmds.xform( pivotBall, ws = True, translation = cmds.xform( jntBall, q = True, ws = True, t = True ) ) pivotBall = cmds.parent( pivotBall, pivotFront )[0] pivotLocs.insert( 0, pivotBall ) outDict['pivots'] = pivotLocs # create simple clamps and connect roll, side attribute to pivot locators rollLimit = 180.0 cmds.addAttr( ctrlFoot + '.side', edit = True, min = -1 * rollLimit, max = rollLimit ) clampRollRear = cmds.shadingNode( 'clamp', asUtility = True ) clampRollRear = cmds.rename( clampRollRear, common.getName( node=clampRollRear, side=side, rigPart='rear', function='roll', nodeType='clamp') ) cmds.setAttr( clampRollRear + '.minR', -rollLimit ) cmds.connectAttr( ctrlFoot + '.roll', clampRollRear + '.inputR' ) cmds.connectAttr( clampRollRear + '.outputR', pivotRear + '.rotateX' ) clampRollLeft = cmds.shadingNode( 'clamp', asUtility = True ) clampRollLeft = cmds.rename( clampRollLeft, common.getName( node=clampRollLeft, side=side, rigPart='left', function='side', nodeType='clamp') ) cmds.setAttr( clampRollLeft + '.minR', -rollLimit ) cmds.connectAttr( ctrlFoot + '.side', clampRollLeft + '.inputR' ) cmds.connectAttr( clampRollLeft + '.outputR', pivotLeft + '.rotateZ' ) clampRollRight = cmds.shadingNode( 'clamp', asUtility = True ) clampRollRight = cmds.rename( clampRollRight, common.getName( node=clampRollRight, side=side, rigPart='right', function='side', nodeType='clamp') ) cmds.setAttr( clampRollRight + '.maxR', rollLimit ) cmds.connectAttr( ctrlFoot + '.side', clampRollRight + '.inputR' ) cmds.connectAttr( clampRollRight + '.outputR', pivotRight + '.rotateZ' ) # setup foot roll cmds.setAttr( ctrlFoot + '.rollBreak', 30.0 ) cmds.addAttr( ctrlFoot + '.rollBreak', edit = True, min = 0.0, max = rollLimit ) cmds.addAttr( ctrlFoot + '.roll', edit = True, min = -rollLimit, max = rollLimit ) clampRollBall = cmds.shadingNode( 'clamp', asUtility = True ) clampRollBall = cmds.rename( clampRollBall, common.getName( node=clampRollBall, side=side, rigPart='ball', function='roll', nodeType='clamp') ) cmds.connectAttr( ctrlFoot + '.rollBreak', clampRollBall + '.maxR' ) cmds.connectAttr( ctrlFoot + '.roll', clampRollBall + '.inputR' ) pmaRollBall = cmds.shadingNode( 'plusMinusAverage', asUtility = True ) cmds.setAttr( pmaRollBall + '.operation', 2 ) cmds.setAttr( pmaRollBall + '.input1D[0]', 180 ) cmds.connectAttr( ctrlFoot + '.rollBreak', pmaRollBall + '.input1D[1]' ) remapRollBall = cmds.shadingNode( 'remapValue', asUtility = True ) cmds.setAttr( remapRollBall + '.outputMin', -1 ) cmds.setAttr( remapRollBall + '.outputMax', 1 ) cmds.setAttr( remapRollBall + '.value[0].value_Position', 0 ) cmds.setAttr( remapRollBall + '.value[0].value_FloatValue', 1 ) cmds.setAttr( remapRollBall + '.value[1].value_Position', 1 ) cmds.setAttr( remapRollBall + '.value[1].value_FloatValue', 0 ) cmds.connectAttr( ctrlFoot + '.rollBreak', remapRollBall + '.inputMin' ) cmds.connectAttr( pmaRollBall + '.output1D', remapRollBall + '.inputMax' ) multRollBall = cmds.shadingNode( 'multiplyDivide', asUtility = True ) cmds.connectAttr( clampRollBall + '.outputR', multRollBall + '.input1X' ) cmds.connectAttr( remapRollBall + '.outValue', multRollBall + '.input2X' ) cmds.connectAttr( multRollBall + '.outputX', pivotBall + '.rotateX' ) clampRollFront = cmds.shadingNode( 'clamp', asUtility = True ) clampRollFront = cmds.rename( clampRollFront, common.getName( node=clampRollFront, side=side, rigPart='toe', function='roll', nodeType='clamp') ) pmaRollFront = cmds.shadingNode( 'plusMinusAverage', asUtility = True ) pmaRollFront = cmds.rename( pmaRollFront, common.getName( node=pmaRollFront, side=side, rigPart='toe', function='roll', nodeType='pma') ) cmds.connectAttr( ctrlFoot + '.rollBreak', clampRollFront + '.minR' ) cmds.connectAttr( ctrlFoot + '.roll', clampRollFront + '.inputR' ) cmds.setAttr( clampRollFront + '.maxR', rollLimit ) cmds.connectAttr( clampRollFront + '.outputR', pmaRollFront + '.input1D[0]' ) cmds.setAttr( pmaRollFront + '.operation', 2 ) cmds.connectAttr( ctrlFoot + '.rollBreak', pmaRollFront + '.input1D[1]' ) cmds.connectAttr( pmaRollFront + '.output1D', pivotFront + '.rotateX' ) # connect twist attributes cmds.connectAttr( ctrlFoot + '.toeTwist', pivotFront + '.rotateY' ) cmds.connectAttr( ctrlFoot + '.heelTwist', pivotRear + '.rotateY' ) # create pivot for toe raise, parent ball ikHandle and connect pivToeRaise = common.insertGroup( pivotFront ) pivToeRaise = cmds.rename( pivToeRaise, common.getName( node=pivToeRaise, side=side, rigPart='toe', function='raise_piv', nodeType='grp') ) cmds.parent( ikHandleBall, pivotFront ) cmds.connectAttr( ctrlFoot + '.toeRaise', pivToeRaise + '.rotateX' ) # create pivot for toe tap and connect pivToeTap = cmds.group( ikHandleToe ) pivToeTap = cmds.rename( pivToeTap, common.getName( node=pivToeTap, side=side, rigPart='toe', function='tap_piv', nodeType='grp') ) cmds.xform( pivToeTap, preserve = True, ws = True, piv = cmds.xform( jntBall, q = True, translation = True, ws = True) ) cmds.connectAttr( ctrlFoot + '.toeTap', pivToeTap + '.rotateX' ) # create lattice deformer latticeVerts = [] for vertId in latticeVertIds: latticeVerts.append( '%s.vtx[%s]' % (mesh, vertId) ) cmds.select( latticeVerts ) ffd, ffdLattice, ffdBase = cmds.lattice( divisions =(3, 2, 4), objectCentered = True, outsideLattice = 2, ofd = 0.25 ) ffd = cmds.rename( ffd, common.getName( node=ffd, side=side, rigPart='foot', function='contact', nodeType='ffd') ) ffdLattice = cmds.rename( ffdLattice, common.getName( node=ffdLattice, side=side, rigPart='foot', function='contact', nodeType='ffdlattice') ) ffdBase = cmds.rename( ffdBase, common.getName( node=ffdBase, side=side, rigPart='foot', function='contact', nodeType='ffdbase') ) cmds.addAttr( ctrlFoot + '.squashGroundContact', edit = True, min = 0.0 ) #, max = 1.0 cmds.setAttr( ctrlFoot + '.squashGroundContact', 1.0 ) cmds.connectAttr( ctrlFoot + '.squashGroundContact', ffd + '.envelope' ) outDict['lattice'] = ffd, ffdLattice, ffdBase # set up ground contact control ctrlGround = controls.Control( side = side, rigPart = "foot", function = "contact", nodeType = "ctrl", size = 1.5, color = sideColor, aimAxis = "x" ) ctrlGround.squareCtrl() cmds.rotate( 0, 45, 0, ctrlGround.control + '.cv[0:4]', relative = True, objectSpace = True ) cmds.xform( ctrlGround.control, ws = True, t = cmds.xform( jntFoot, q = True, ws = True , t = True ) ) cmds.addAttr( ctrlFoot, longName = 'showGroundCtrl', attributeType = 'bool', keyable = True ) cmds.connectAttr( ctrlFoot + '.showGroundCtrl', ctrlGround.control + '.visibility' ) cmds.setAttr( ctrlGround.control + '.scaleX', lock = True, keyable = False, channelBox = False ) cmds.setAttr( ctrlGround.control + '.scaleY', lock = True, keyable = False, channelBox = False ) cmds.setAttr( ctrlGround.control + '.scaleZ', lock = True, keyable = False, channelBox = False ) cmds.setAttr( ctrlGround.control + '.visibility', keyable = False, channelBox = False ) cmds.addAttr( ctrlGround.control, longName = 'followFoot', attributeType = 'float', keyable = True, min = 0.0, max = 1.0, dv = 1.0 ) ctrlGrpGround = common.insertGroup( ctrlGround.control ) constGrpGround = cmds.pointConstraint( ctrlFoot, ctrlGrpGround, mo = False, skip = 'y' )[0] cmds.setAttr( constGrpGround + '.enableRestPosition', 0 ) cmds.connectAttr( ctrlGround.control + '.followFoot', constGrpGround + '.' + cmds.pointConstraint( constGrpGround, q = True, weightAliasList = True )[0] ) # create base and top lattice ctrl joints topLatticePoints = ['[1][1][3]', '[0][1][2]', '[0][1][1]', '[1][1][0]', '[2][1][1]', '[2][1][2]'] baseLatticePoints = ['[1][0][3]', '[0][0][2]', '[0][0][1]', '[1][0][0]', '[2][0][1]', '[2][0][2]'] centerLatticePoints = [ '[1][0][1]', '[1][0][2]' ] latticeJntRotations = [0, -65, -115, -180, -245, -295] grpLatticeJnts = cmds.group( empty = True ) grpLatticeJnts = cmds.rename( grpLatticeJnts, common.getName( node=grpLatticeJnts, side=side, rigPart='foot', function='ffd_jnts', nodeType='grp' ) ) common.align( grpLatticeJnts, ctrlFoot, translate = True, orient = False ) topLatticeJnts = [] baseLatticeJnts = [] for latticePoints in [ baseLatticePoints, topLatticePoints ]: i = 0 if latticePoints == topLatticePoints: pos = 'top' if latticePoints == baseLatticePoints: pos = 'base' for latticePoint in latticePoints: i += 1 cmds.select( clear = True ) latticeJnt = cmds.joint() latticeJnt = cmds.rename( latticeJnt, common.getName( node=latticeJnt, side=side, rigPart='foot', function='ffd_%s%s' % ( pos,i ), nodeType='jnt' ) ) cmds.xform( latticeJnt, ws = True, t = cmds.xform( '%s.pt%s' % ( ffdLattice, latticePoint ), q = True, ws = True, t = True ) ) cmds.setAttr( latticeJnt + '.radius', .5 ) cmds.setAttr( latticeJnt + '.rotateY', latticeJntRotations[i-1] ) latticeJnt = cmds.parent( latticeJnt, grpLatticeJnts )[0] common.insertGroup( latticeJnt ) if pos == 'top': topLatticeJnts.append( latticeJnt ) if pos == 'base': baseLatticeJnts.append( latticeJnt ) # center lattice joint cmds.select( clear = True ) centerLatticeJnt = cmds.joint() centerLatticeJnt = cmds.rename( centerLatticeJnt, common.getName( node=centerLatticeJnt, side=side, rigPart='foot', function='ffd_center', nodeType='jnt' ) ) cmds.setAttr( centerLatticeJnt + '.radius', .5 ) clpPos1 = cmds.xform( '%s.pt%s' % ( ffdLattice, centerLatticePoints[0] ), q = True, ws = True, t = True ) clpPos2 = cmds.xform( '%s.pt%s' % ( ffdLattice, centerLatticePoints[1] ), q = True, ws = True, t = True ) clpPos = [0,0,0] clpPos[0] = clpPos1[0] + 0.5 * ( clpPos2[0] - clpPos1[0] ) clpPos[1] = clpPos1[1] + 0.5 * ( clpPos2[1] - clpPos1[1] ) clpPos[2] = clpPos1[2] + 0.5 * ( clpPos2[2] - clpPos1[2] ) cmds.xform( centerLatticeJnt, ws = True, t = clpPos) centerLatticeJnt = cmds.parent( centerLatticeJnt, grpLatticeJnts)[0] common.insertGroup( centerLatticeJnt ) baseLatticeJnts.append( centerLatticeJnt ) # create ground reader locators grpReadLocs = cmds.group( empty = True ) grpReadLocs = cmds.rename( grpReadLocs, common.getName( node=grpReadLocs, side=side, rigPart='foot', function='read_locs', nodeType='grp' ) ) i = 0 for latticeJnt in baseLatticeJnts: i += 1 locBase = cmds.spaceLocator() cmds.setAttr( cmds.listRelatives( locBase )[0] + '.localScale', .2, .2, .2 ) locBase = cmds.rename( locBase, common.getName( node=locBase, side=side, rigPart='ground', function='base%s' % i, nodeType='loc' ) ) cmds.setAttr( locBase + '.visibility', 0 ) locReader = cmds.spaceLocator() cmds.setAttr( cmds.listRelatives( locReader )[0] + '.localScale', .2, .2, .2 ) locReader = cmds.rename( locReader, common.getName( node=locReader, side=side, rigPart='ground', function='read%s' % i, nodeType='loc' ) ) locTop = cmds.spaceLocator() cmds.setAttr( cmds.listRelatives( locTop )[0] + '.localScale', .2, .2, .2 ) locTop = cmds.rename( locTop, common.getName( node=locTop, side=side, rigPart='ground', function='top%s' % i, nodeType='loc' ) ) locReader = cmds.parent( locReader, locBase )[0] constRead = cmds.pointConstraint( locTop, locReader, mo = False ) locBase = cmds.parent( locBase, ctrlGround.control )[0] locTop = cmds.parent( locTop, grpReadLocs )[0] cmds.xform( locTop, ws = True, t = cmds.xform( latticeJnt, q = True, ws = True , t = True ) ) constBase = cmds.pointConstraint( locTop, locBase, mo = False, skip = 'y' ) # remap reader output and connect to lattice joint remapRead = cmds.shadingNode( 'remapValue', asUtility = True ) remapRead = cmds.rename( remapRead, common.getName( node=remapRead, side=side, rigPart='ground', function='read%s' % i, nodeType='rmv') ) cmds.setAttr( remapRead + '.inputMax', -1) cmds.setAttr( remapRead + '.outputMax', 1) cmds.connectAttr( locReader + '.translateY', remapRead + '.inputValue', f = True ) cmds.connectAttr( remapRead + '.outValue', latticeJnt + '.translateY', f = True ) if latticeJnt == centerLatticeJnt: # set min max on center remap to enable center drag remapRead = cmds.rename( remapRead, common.getName( node=remapRead, side=side, rigPart='ground', function='read_center', nodeType='rmv') ) cmds.setAttr( remapRead + '.inputMin', 0 ) cmds.setAttr( remapRead + '.outputMin', 0 ) cmds.setAttr( remapRead + '.inputMax', 1 ) cmds.setAttr( remapRead + '.outputMax', 1 ) cmds.setAttr( remapRead + '.value[0].value_FloatValue', 0 ) cmds.setAttr( remapRead + '.value[0].value_Position', -0.02 ) cmds.setAttr( remapRead + '.value[0].value_Interp', 1 ) cmds.setAttr( remapRead + '.value[1].value_FloatValue', -1 ) cmds.setAttr( remapRead + '.value[1].value_Position', 0.25 ) cmds.setAttr( remapRead + '.value[1].value_Interp', 1 ) cmds.setAttr( remapRead + '.value[2].value_FloatValue', 1 ) cmds.setAttr( remapRead + '.value[2].value_Position', -0.25 ) cmds.setAttr( remapRead + '.value[2].value_Interp', 1 ) else: # connect remap output to top joints tz to enhance squishyness cmds.connectAttr( remapRead + '.outValue', topLatticeJnts[i-1] + '.translateZ', f = True ) # bind lattice clusterLattice = cmds.skinCluster( topLatticeJnts + baseLatticeJnts, ffdLattice ,tsb=True, skinMethod = 0, nw = 1) clusterLattice = cmds.rename( clusterLattice, common.getName( node=clusterLattice, side=side, rigPart='foot', function='lattice', nodeType='skinCluster') ) # create system and const groups grpConst = cmds.group( empty = True, name = side + '_foot_const_grp' ) common.align( grpConst, ctrlFoot, translate = True, orient = False ) cmds.parentConstraint( ctrlFoot, grpConst, mo = True ) grpSystem = cmds.group( empty = True, name = side + '_foot_grp' ) common.align( grpSystem, ctrlFoot, translate = True, orient = False ) # grouping grpConst = cmds.parent( grpConst, grpSystem )[0] grpJnts = cmds.parent( grpJnts, grpSystem )[0] ctrlGrpGround = cmds.parent( ctrlGrpGround, grpSystem )[0] grpReadLocs = cmds.parent( grpReadLocs, pivotBall )[0] grpLatticeJnts = cmds.parent( grpLatticeJnts, pivotBall )[0] pivotRight = cmds.parent( pivotRight, grpConst )[0] cmds.setAttr( ffdLattice + '.inheritsTransform', 0 ) ffdLattice, ffdBase = cmds.parent( ffdLattice, ffdBase, pivotBall ) # group ik handle cmds.parent( ikHandleLeg, pivotBall ) for each in cmds.listRelatives( ikHandleLeg ): if cmds.nodeType( each ) == 'pointConstraint': cmds.delete( each ) # constrain stretch locator for each in cmds.listRelatives( stretchLoc ): if cmds.nodeType( each ) == 'pointConstraint': cmds.delete( each ) cmds.parentConstraint( pivotBall , stretchLoc, mo = True, weight = 1 ) # constrain low curve jnt grp lowCurveGrp = None systemGrpLimb = cmds.listRelatives( cmds.listRelatives( stretchLoc, p = True ), p = True ) for each in cmds.listRelatives( systemGrpLimb ): if ( ( side + '_leg_low_curve' ) in each ) and ( cmds.nodeType( each ) == 'transform' ): lowCurveGrp = each if lowCurveGrp: for each in cmds.listRelatives( lowCurveGrp ): if cmds.nodeType( each ) == 'parentConstraint': cmds.delete( each ) cmds.parentConstraint( pivotBall, lowCurveGrp, mo = True ) else: print( 'Could not find leg_low_curve_#_jnt_grp, please constrain manually to ball pivot locator.' ) # hide const / utility grp if cleanUp == 1: cmds.setAttr( grpConst + '.visibility', 0 ) cmds.setAttr( grpJnts + '.visibility', 0 ) outDict['systemsGrp'] = grpSystem cmds.select( ctrlFoot ) print('DO NOT FORGET: If the rig is build before there is a skincluster attached to the mesh you will need to reorder the deformers.') print('Reverse Foot %s created.' % side) return outDict
def buildFinger( side, name, rootJnt, rootGrp, cleanUp ): # Get aim axis - this presumes the rootJnt is NOT an extend joint childJnt = cmds.listRelatives( rootJnt, c=1, type='joint' )[0] childPos = cmds.getAttr('%s.t' % childJnt)[0] childPosAbs = [ math.fabs(value) for value in childPos ] twistIndex = childPosAbs.index(max(childPosAbs)) twistAxis = ['x', 'y', 'z'][ twistIndex ] # Determine whether the joints have a negative translation along the twist axis neg = False if childPos[ twistIndex ] < 0.0: neg = True # Duplicate joint chain dupJnts = cmds.duplicate( rootJnt, rc=1 ) print dupJnts jnts=[] ctrls = [] index=1 for d in range(len(dupJnts)): if isExtendJnt(dupJnts[d]): j = cmds.rename(dupJnts[d], common.getName( node=dupJnts[d], side=side, rigPart='hand', function='%sExtend%s' % ( name, index ), nodeType='jnt')) grp = common.insertGroup( node=j ) grp = cmds.rename( grp, j.replace('jnt', 'grp') ) # Connect twistAxis translate to ctrl and ctrl rotatePivotTrnaslate back to ctrl.translate cmds.connectAttr('%s.t%s' % (ctrls[index-2], twistAxis), '%s.t%s' % ( j, twistAxis ) ) rotPivTransUC = cmds.createNode('unitConversion') rotPivTransUC = cmds.rename(rotPivTransUC, common.getName( node=rotPivTransUC, side=side, rigPart='hand', function='%sNegTrans%s' % ( name, index ), nodeType='conv')) cmds.setAttr( '%s.conversionFactor' % rotPivTransUC, -1.0 ) cmds.connectAttr( '%s.t' % ctrls[index-2], '%s.input' % rotPivTransUC ) cmds.connectAttr( '%s.output' % rotPivTransUC, '%s.rotatePivotTranslate' % ctrls[index-2] ) else: j = cmds.rename(dupJnts[d], common.getName( node=dupJnts[d], side=side, rigPart='hand', function='%s%s' % ( name, index ), nodeType='jnt')) if d < (len(dupJnts)-1): # Build control c = controls.Control( side=side, rigPart="hand", function='%s%s' % ( name, index ), nodeType="ctrl", size=0.15, color=side, aimAxis=twistAxis, flip=neg ) c.pinCtrl() grp = common.insertGroup( node=c.control ) grp = cmds.rename( grp, c.control.replace('ctrl', 'grp') ) common.align( node=grp, target=j ) if d == 0: cmds.parent( grp, rootGrp ) cmds.parent( j, rootGrp ) else: cmds.parent(grp, ctrls[index-2]) cmds.pointConstraint(j, grp) ctrls.append(c.control) # Connect joint rotations to ctrl rotations cmds.connectAttr('%s.r' % c.control, '%s.r' % j) index = index + 1 jnts.append( j ) if cleanUp: lockAxes = ['t%s' % axis for axis in ['x', 'y', 'z'] if not axis == twistAxis] attrList=lockAxes + ['sx', 'sy', 'sz', 'visibility'] for c in ctrls: common.attrCtrl(nodeList=[c], attrList=attrList) #common.attrCtrl(nodeList=[ctrls[-1]], attrList='t%s' % twistAxis) return {'jnts':jnts, 'ctrls':ctrls}
def build ( char=None, cleanUp=False ): ''' Builds the specified character ''' #Build root structure rootSys = root.build() if not char: char = 'defaultChar' # import geo geoList = geo.importGeo(char) for g in geoList: cmds.parent( g, rootSys['geoGrp'] ) # Import joints joints.importSkel(char) # Parent joints to root defJnts group jnts = cmds.ls(type='joint') for j in jnts: p = cmds.listRelatives(j, p=1) if not p: cmds.parent(j, rootSys['defJntsGrp']) # Build spine spineSys = spine.build( hips='cn_spine_01_defJnt', chest='cn_spine_06_defJnt', head='cn_spine_11_defJnt',numSpineJoints=6, numHeadJoints=6, twistAxis='x', bendAxis='y', cleanUp=cleanUp ) cmds.parent(spineSys['xformGrp'], rootSys['systemsGrp']) spineTarg = cmds.group(empty=True) spineTarg = cmds.rename(spineTarg, common.getName(side='cn', rigPart='spine', function='const', nodeType='grp')) common.align(spineTarg, spineSys['xformGrp']) cmds.parent(spineTarg, rootSys['constGrp']) cmds.parentConstraint( spineTarg, spineSys['xformGrp'] ) # Build limbs lf_arm = anom.systems.limb.build( startJoint='lf_shoulder_1_defJnt', middleJoint='lf_arm_1_defJnt', endJoint='lf_hand_defJnt', extraJoint='lf_hand_end_defJnt', side='lf', name='arm', twistJointCount=6 ) cmds.parent( lf_arm['limbSystem_grp'], rootSys['systemsGrp'] ) rt_arm = anom.systems.limb.build( startJoint='rt_shoulder_1_defJnt', middleJoint='rt_arm_1_defJnt', endJoint='rt_hand_defJnt', extraJoint='rt_hand_end_defJnt', side='rt', name='arm', twistJointCount=6 ) cmds.parent( rt_arm['limbSystem_grp'], rootSys['systemsGrp'] ) lf_leg = anom.systems.limb.build( startJoint='lf_leg_1_defJnt', middleJoint='lf_knee_1_defJnt', endJoint='lf_foot_defJnt', extraJoint='lf_foot_end_defJnt', side='lf', name='leg', twistJointCount=5, isLeg=True ) cmds.parent( lf_leg['limbSystem_grp'], rootSys['systemsGrp'] ) rt_leg = anom.systems.limb.build( startJoint='rt_leg_1_defJnt', middleJoint='rt_knee_1_defJnt', endJoint='rt_foot_defJnt', extraJoint='rt_foot_end_defJnt', side='rt', name='leg', twistJointCount=5, isLeg=True ) cmds.parent( rt_leg['limbSystem_grp'], rootSys['systemsGrp'] ) # Build hands lf_hand = anom.systems.hand.build( side='lf', root='lf_hand_root_defJnt', fingerDict={'thumb':'lf_hand_thumb1_defJnt', 'index':'lf_hand_index1_defJnt', 'mid':'lf_hand_mid1_defJnt', 'pinky':'lf_hand_pinky1_defJnt'}, cleanUp=cleanUp ) cmds.parent (lf_hand['systemGrp'], rootSys['systemsGrp']) cmds.parentConstraint( lf_arm['jointList'][2], lf_hand['systemGrp'], mo=1 ) # Sorry - I know it's horrible but time's running out!! (Bad, bad Duncan... :p) rt_hand = anom.systems.hand.build( side='rt', root='rt_hand_root_defJnt', fingerDict={'thumb':'rt_hand_thumb1_defJnt', 'index':'rt_hand_index1_defJnt', 'mid':'rt_hand_mid1_defJnt', 'pinky':'rt_hand_pinky1_defJnt'}, cleanUp=cleanUp ) cmds.parent (rt_hand['systemGrp'], rootSys['systemsGrp']) cmds.parentConstraint( rt_arm['jointList'][2], rt_hand['systemGrp'], mo=1 ) # Build feet lf_foot = reverseFoot.build( side = 'lf', jntFoot = lf_leg['jointList'][-1], ctrlFoot = lf_leg['end_ctrl'], ikHandleLeg = lf_leg['ikHandle'], mesh = 'cn_body_render_mesh', stretchLoc = lf_leg['stretch_positions'][1], cleanUp = cleanUp ) cmds.parent( lf_foot['systemsGrp'], rootSys['systemsGrp']) rt_foot = reverseFoot.build( side = 'rt', jntFoot = rt_leg['jointList'][-1], ctrlFoot = rt_leg['end_ctrl'], ikHandleLeg = rt_leg['ikHandle'], mesh = 'cn_body_render_mesh', stretchLoc = rt_leg['stretch_positions'][1], cleanUp = cleanUp ) cmds.parent( rt_foot['systemsGrp'], rootSys['systemsGrp']) # Build AutoHips lf_autoHip = autoHip.createAutoHip(lf_leg['start_ctrl'], spineSys['hipCtrl'][0], lf_leg['end_ctrl']) rt_autoHip = autoHip.createAutoHip(rt_leg['start_ctrl'], spineSys['hipCtrl'][0], rt_leg['end_ctrl']) cmds.parent( lf_autoHip['autoHipSystem_grp'], rt_autoHip['autoHipSystem_grp'], rootSys['systemsGrp']) # Build Rivets lf_shoulder_rivet = rivet.build( targ=lf_arm['start_ctrl'], mesh='cn_body_render_mesh', side='lf', rigPart='arm', cleanUp=cleanUp ) cmds.parent( lf_shoulder_rivet['follicle'], rootSys['constGrp'] ) cmds.pointConstraint( lf_shoulder_rivet['constGrp'], cmds.listRelatives(lf_arm['start_ctrl'], p=1)[0] ) rt_shoulder_rivet = rivet.build( targ=rt_arm['start_ctrl'], mesh='cn_body_render_mesh', side='rt', rigPart='arm', cleanUp=cleanUp ) cmds.parent( rt_shoulder_rivet['follicle'], rootSys['constGrp'] ) cmds.pointConstraint( rt_shoulder_rivet['constGrp'], cmds.listRelatives(rt_arm['start_ctrl'], p=1)[0] ) lf_eye_rivet = rivet.build( targ='lf_head_eye_defJnt', mesh='cn_body_render_mesh', side='lf', rigPart='eye', cleanUp=cleanUp ) cmds.parent( lf_eye_rivet['follicle'], rootSys['constGrp'] ) rt_eye_rivet = rivet.build( targ='rt_head_eye_defJnt', mesh='cn_body_render_mesh', side='rt', rigPart='eye', cleanUp=cleanUp ) cmds.parent( rt_eye_rivet['follicle'], rootSys['constGrp'] ) connectToPuppet() # Bind skin cmds.select( cmds.listRelatives(rootSys['geoGrp']) ) anom.core.skinWeights.rebindSkinClusters( char ) anom.core.skinWeights.setSkinWeights( char ) cmds.reorderDeformers( 'lf_foot_contact_ffd', 'skincluster_cn_body_render_mesh', 'cn_body_render_mesh' ) # Make everything follow root the evil way | global scale cmds.parentConstraint( rootSys['constGrp'][0], rootSys['systemsGrp'][0], mo=1 ) cmds.scaleConstraint ( rootSys['constGrp'][0], rootSys['systemsGrp'][0], mo=1 ) cmds.connectAttr( rootSys['systemsGrp'][0] + '.scale', rootSys['defJntsGrp'][0] + '.scale' ) invScale = cmds.shadingNode( 'multiplyDivide', asUtility = True, name = 'root_systems_invScale_md' ) cmds.setAttr( invScale + '.operation', 2 ) cmds.setAttr( invScale + '.input1', 1, 1, 1, type='double3' ) cmds.connectAttr( rootSys['systemsGrp'][0] + '.scale', invScale + '.input2' ) #connect autoHip to inverse world scale cmds.connectAttr( invScale + '.output', lf_autoHip['placer'][0] + '.scale' ) cmds.connectAttr( invScale + '.output', rt_autoHip['placer'][0] + '.scale' ) #connect follicles to systemGrp scale this fixes errors from the offset at extreme scaling values for fol in [ lf_shoulder_rivet['follicle'], rt_shoulder_rivet['follicle'], lf_eye_rivet['follicle'], rt_eye_rivet['follicle'] ]: cmds.connectAttr( rootSys['systemsGrp'][0] + '.scale', fol+'.scale' ) cmds.setAttr( fol+'.v', 0 ) # finally hide defJnts if cleanUp: cmds.setAttr( rootSys['offsetCtrl'][0].control +'.jointsVisibility', 0 ) # create a Layer for the meshes cmds.createDisplayLayer( name='MESH_layer', empty=True ) cmds.editDisplayLayerMembers( 'MESH_layer', rootSys['geoGrp'], noRecurse=True ) cmds.setAttr( 'MESH_layer.displayType', 2 ) # unselectable cmds.select( clear=True )
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
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
def build( startJoint=None, middleJoint=None, endJoint=None, extraJoint=None, side=None, name=None, twistJointCount=None, isLeg=False, cleanUp=True ): if not startJoint or not middleJoint or not endJoint or not extraJoint or not side or not name or not twistJointCount: print 'limb: Error! Must supply all arguments.' return # first reconstruct the joints for our system joint1 = cmds.createNode( 'joint', n=side+"_"+name+'_start_drvJnt' ) joint2 = cmds.createNode( 'joint', n=side+"_"+name+'_middle_drvJnt' ) joint3 = cmds.createNode( 'joint', n=side+"_"+name+'_end_jnt' ) joint4 = cmds.createNode( 'joint', n=side+"_"+name+'_extra_drvJnt' ) common.align( node=joint1, target=startJoint ) cmds.setAttr('%s.jointOrient' % joint1, 0,0,0) common.align( node=joint2, target=middleJoint ) cmds.setAttr('%s.jointOrient' % joint2, 0,0,0) common.align( node=joint3, target=endJoint ) cmds.setAttr('%s.jointOrient' % joint3, 0,0,0) common.align( node=joint4, target=extraJoint ) cmds.setAttr('%s.jointOrient' % joint4, 0,0,0) cmds.parent( joint4, joint3 ) cmds.parent( joint3, joint2 ) cmds.parent( joint2, joint1 ) if isLeg: cmds.setAttr( joint2+'.preferredAngle', 0, 0, -90 ) else: cmds.setAttr( joint2+'.preferredAngle', 0, -90, 0 ) cmds.makeIdentity( joint1, apply=True ) # auto color controls using the 'side' argument myColor = 'green' if side == 'lf': myColor = 'blue' elif side == 'rt': myColor = 'red' # creation of the start control (shoulder or hips offset) limbStartCtrl = controls.Control( side=side, rigPart='limb', function=name+'_start', nodeType='ctrl', size=0.4, color=myColor, aimAxis='y' ) limbStartCtrl.pinCtrl() common.align( node=limbStartCtrl.control, target=joint1, orient=False ) limbStartCtrlGrp = common.insertGroup( node=limbStartCtrl.control ) # creation of the end control (hand or foot) limbEndCtrl = controls.Control( side=side, rigPart='limb', function=name+'_end', nodeType='ctrl', size=0.4 + 0.2*isLeg, color=myColor, aimAxis='x' ) limbEndCtrl.cubeCtrl() common.align( node=limbEndCtrl.control, target=joint3, orient=False ) limbEndCtrlGrp = common.insertGroup( node=limbEndCtrl.control ) # entire system group systemGrp = cmds.group( empty=True, n=side+'_'+name+'_xform_grp') cmds.parent( joint1, systemGrp ) # # NON ROLLs CREATION # startNonRoll = nonRoll.build(joint=joint1, name = name+'Start') cmds.parent(startNonRoll['main_grp'], systemGrp) upNonRoll = nonRoll.build(joint=joint2, name = name+'Mid') cmds.parent(upNonRoll['main_grp'], joint1) lowNonRoll = nonRoll.build(joint=joint3, name = name+'End') cmds.parent(lowNonRoll['main_grp'], joint2) ''' if isLeg: if side == 'lf': aimUp = (0, 1, 0) elif side == 'rt': aimUp = (0, -1, 0) cmds.aimConstraint( lowNonRollEnd, lowNonRollLoc, aimVector=aimVec, upVector=aimUp, worldUpType='objectrotation', worldUpVector=aimWorldUp, worldUpObject=joint3 ) if isLeg: common.align( node=lowNonRollLocGrp, target=joint3 ) else: common.align( node=lowNonRollLocGrp, target=joint2 ) common.align( node=lowNonRollLocGrp, target=joint3, orient=False ) cmds.setAttr( lowNonRollGrp+'.v', 0 ) cmds.setAttr( lowTwistIkHandle+'.poleVector', 0, 0, 0 ) if not isLeg: if side == 'rt': cmds.setAttr( lowNonRollLocGrp+'.r', 0, 0, 0 ) else: if side == 'lf': cmds.setAttr( lowNonRollLocGrp+'.r', 90, 0, 0 ) ''' # create stretch setup ssStartPos = cmds.group( empty=True, n=side+'_'+name+'_stretchStart_loc') ssEndPos = cmds.group( empty=True, n=side+'_'+name+'_stretchEnd_loc') common.align( node=ssStartPos, target=joint1, orient=False ) cmds.pointConstraint( limbEndCtrl.control, ssEndPos ) ssGrp = cmds.group( ssStartPos, ssEndPos, n=side+'_'+name+'_stretchLocs_grp') cmds.parent( ssGrp, systemGrp ) # sums the two separate distances to create the stretch originalUpLimbTx = cmds.getAttr( joint2+'.translateX' ) originalLowLimbTx = cmds.getAttr( joint3+'.translateX' ) limbSize = common.getDistance( joint1, joint2 ) + common.getDistance( joint2, joint3 ) dbNode = cmds.createNode( 'distanceBetween', n=side+'_'+name+'_stretch_distance') cmds.connectAttr( ssStartPos+'.t', dbNode+'.point1' ) cmds.connectAttr( ssEndPos+'.t', dbNode+'.point2' ) # creates a keyframe-based stretch factor ssKeyUp = cmds.createNode( 'animCurveUL', n=side+'_'+name+'_upStretch_key' ) cmds.connectAttr( dbNode+'.distance', ssKeyUp+'.input' ) cmds.connectAttr( ssKeyUp+'.output', joint2+'.translateX' ) ssKeyLow = cmds.createNode( 'animCurveUL', n=side+'_'+name+'_LowStretch_key' ) cmds.connectAttr( dbNode+'.distance', ssKeyLow+'.input' ) cmds.connectAttr( ssKeyLow+'.output', joint3+'.translateX' ) # set driven key values cmds.setDrivenKeyframe( joint2+'.translateX', currentDriver=dbNode+'.distance', driverValue=limbSize, value=originalUpLimbTx, itt='linear', ott='linear' ) cmds.setDrivenKeyframe( joint2+'.translateX', currentDriver=dbNode+'.distance', driverValue=limbSize*2, value=originalUpLimbTx*2, itt='linear', ott='spline' ) cmds.setInfinity( joint2+'.translateX', poi='linear' ) cmds.setDrivenKeyframe( joint3+'.translateX', currentDriver=dbNode+'.distance', driverValue=limbSize, value=originalLowLimbTx, itt='linear', ott='linear' ) cmds.setDrivenKeyframe( joint3+'.translateX', currentDriver=dbNode+'.distance', driverValue=limbSize*2, value=originalLowLimbTx*2, itt='linear', ott='spline' ) cmds.setInfinity( joint3+'.translateX', poi='linear' ) # create the twistSections twistUp = 'z' if isLeg: twistUp = 'y' doNotInvertUp = False if isLeg and side == 'rt': doNotInvertUp = True upTwistDict = twistSection.build( side=side, name='up_'+name, startPos=joint1, endPos=joint2, jointCount=twistJointCount, worldUpVector=twistUp, worldUpObject=startNonRoll['nonRoll'], twistReader=startNonRoll['info'], doNotInvertUp=doNotInvertUp ) lowTwistDict = twistSection.build( side=side, name='low_'+name, startPos=joint2, endPos=joint3, jointCount=twistJointCount, worldUpVector=twistUp, worldUpObject=upNonRoll['nonRoll'], twistReader=lowNonRoll['info'], doNotInvertUp=doNotInvertUp ) # create the joints that will skin the twistSection curves # to get that nice bendy effect for free # start with the shoulder/hips joint mdNode = None crvJntA1 = cmds.createNode( 'joint', n=side+'_'+name+'_up_curve_1_jnt') crvJntA2 = cmds.createNode( 'joint', n=side+'_'+name+'_up_curve_2_jnt') cmds.parent( crvJntA2, crvJntA1 ) cmds.parent( crvJntA1, systemGrp ) cmds.addAttr( limbEndCtrl.control, ln='start_tangent', min=0, dv=0.1, k=True ) if side == 'lf': cmds.connectAttr( limbEndCtrl.control+'.start_tangent', crvJntA2+'.translateX' ) else: mdNode = cmds.createNode( 'multiplyDivide', n=side+'_'+name+'_pma' ) cmds.setAttr( mdNode+'.input2', -1, -1, -1 ) cmds.connectAttr( limbEndCtrl.control+'.start_tangent', mdNode+'.input1X' ) cmds.connectAttr( mdNode+'.outputX', crvJntA2+'.translateX' ) common.align( node=crvJntA1, target=joint1 ) # elbow/knee joints avgGrp = cmds.group( empty=True, n=side+'_'+name+'_avg_grp' ) crvJntB1 = cmds.createNode( 'joint', n=side+'_'+name+'_cn_curve_1_avgJnt') crvJntB2 = cmds.createNode( 'joint', n=side+'_'+name+'_cn_curve_2_avgJnt') cmds.parent( crvJntB2, crvJntB1 ) cmds.parent( crvJntB1, avgGrp ) cmds.setAttr( crvJntB1+'.rotateY', 180 ) # flip crvJntC1 = cmds.createNode( 'joint', n=side+'_'+name+'_cn_curve_3_avgJnt') crvJntC2 = cmds.createNode( 'joint', n=side+'_'+name+'_cn_curve_4_avgJnt') cmds.parent( crvJntC2, crvJntC1 ) cmds.parent( crvJntC1, avgGrp ) cmds.addAttr( limbEndCtrl.control, ln='bend_tangent', min=0, dv=0.85, k=True ) if mdNode: cmds.connectAttr( limbEndCtrl.control+'.bend_tangent', mdNode+'.input1Y' ) cmds.connectAttr( mdNode+'.outputY', crvJntB2+'.translateX' ) cmds.connectAttr( mdNode+'.outputY', crvJntC2+'.translateX' ) else: cmds.connectAttr( limbEndCtrl.control+'.bend_tangent', crvJntB2+'.translateX' ) cmds.connectAttr( limbEndCtrl.control+'.bend_tangent', crvJntC2+'.translateX' ) cmds.pointConstraint( joint2, avgGrp ) cons = cmds.orientConstraint( joint1, joint2, avgGrp )[0] cmds.setAttr( cons+'.interpType', 0 ) # noFlip # wrist/foot joints crvJntD1 = cmds.createNode( 'joint', n=side+'_'+name+'_low_curve_1_jnt') crvJntD2 = cmds.createNode( 'joint', n=side+'_'+name+'_low_curve_2_jnt') crvJntD1Grp = cmds.group( crvJntD1, n=crvJntD1+'_grp' ) cmds.parent( crvJntD2, crvJntD1 ) cmds.parent( crvJntD1Grp, systemGrp ) cmds.setAttr( crvJntD1+'.rotateY', 180 ) # flip common.align( node=crvJntD1Grp, target=joint3 ) cmds.parentConstraint( limbEndCtrl.control, crvJntD1Grp, mo=True ) cmds.addAttr( limbEndCtrl.control, ln='end_tangent', min=0, dv=0.2, k=True ) if mdNode: cmds.connectAttr( limbEndCtrl.control+'.end_tangent', mdNode+'.input1Z' ) cmds.connectAttr( mdNode+'.outputZ', crvJntD2+'.translateX' ) else: cmds.connectAttr( limbEndCtrl.control+'.end_tangent', crvJntD2+'.translateX' ) # extra jnt follow orientation of endCtrl cmds.orientConstraint( limbEndCtrl.control, joint3, mo=True ) # constrains entire limb to startCtrl cmds.orientConstraint( limbStartCtrl.control, startNonRoll['main_grp'], mo=True ) # skin the twistSection curves to these joints skinClsUp = cmds.skinCluster( crvJntA1, crvJntA2, crvJntB1, crvJntB2, upTwistDict['twist_curve'] )[0] cmds.skinPercent( skinClsUp, upTwistDict['twist_curve']+'.cv[0]', transformValue=[(crvJntA1, 1)]) cmds.skinPercent( skinClsUp, upTwistDict['twist_curve']+'.cv[1]', transformValue=[(crvJntA2, 1)]) cmds.skinPercent( skinClsUp, upTwistDict['twist_curve']+'.cv[2]', transformValue=[(crvJntB2, 1)]) cmds.skinPercent( skinClsUp, upTwistDict['twist_curve']+'.cv[3]', transformValue=[(crvJntB1, 1)]) skinClsLow = cmds.skinCluster( crvJntC1, crvJntC2, crvJntD1, crvJntD2, lowTwistDict['twist_curve'] )[0] cmds.skinPercent( skinClsLow, lowTwistDict['twist_curve']+'.cv[0]', transformValue=[(crvJntC1, 1)]) cmds.skinPercent( skinClsLow, lowTwistDict['twist_curve']+'.cv[1]', transformValue=[(crvJntC2, 1)]) cmds.skinPercent( skinClsLow, lowTwistDict['twist_curve']+'.cv[2]', transformValue=[(crvJntD2, 1)]) cmds.skinPercent( skinClsLow, lowTwistDict['twist_curve']+'.cv[3]', transformValue=[(crvJntD1, 1)]) # # IKHANDLE CREATION # ikHandle, effector = cmds.ikHandle( startJoint=joint1, endEffector=joint3, solver='ikRPsolver', n=side+'_'+name+'_ikHandle' ) pvCtrl = controls.Control( side=side, rigPart=name, function='poleVec', nodeType="ctrl", size=0.3, color=myColor, aimAxis="twistAxis" ) pvCtrl.cubeCtrl() # snaps the poleVector control to the middle joint common.align( node=pvCtrl.control, target=joint2, orient=False ) pvCtrlGrp = common.insertGroup( node=pvCtrl.control ) cmds.poleVectorConstraint( pvCtrl.control, ikHandle ) cmds.setAttr( pvCtrl.control+'.tz', -5 ) # invert poleVector position if it's a leg if isLeg: cmds.setAttr( pvCtrl.control+'.tz', 5 ) # auto follow foot control cmds.pointConstraint( limbEndCtrl.control, pvCtrlGrp, mo=True ) cmds.orientConstraint( limbEndCtrl.control, pvCtrlGrp, skip=['x'], mo=True ) # ikHandle follow endCtrl cmds.pointConstraint( limbEndCtrl.control, ikHandle ) # extra attributes to endCtrl cmds.addAttr( limbEndCtrl.control, ln='twist', k=True ) cmds.connectAttr( limbEndCtrl.control+'.twist', ikHandle+'.twist' ) ## ik lock # add attribute to control if ( cmds.attributeQuery( 'lock', node=limbEndCtrl.control, exists=True ) ) == True: print( 'Attribute %s already exists on %s.' % ( 'lock', limbEndCtrl ) ) else: cmds.addAttr( limbEndCtrl.control, longName='lock', attributeType='float', keyable=True, min=0.0, max=1.0, dv=0.0 ) # create distance locs startLoc = cmds.spaceLocator( name=side + '_' + name + '_start_loc' )[0] middleLoc = cmds.spaceLocator( name=side + '_' + name + '_middle_loc' )[0] endLoc = cmds.spaceLocator( name=side + '_' + name + '_end_loc' )[0] upDist = cmds.createNode( 'distanceDimShape' ) lowDist = cmds.createNode( 'distanceDimShape' ) cmds.connectAttr( cmds.listRelatives(startLoc)[0] + '.worldPosition[0]', upDist + '.startPoint' ) cmds.connectAttr( cmds.listRelatives(middleLoc)[0] + '.worldPosition[0]', upDist + '.endPoint' ) cmds.connectAttr( cmds.listRelatives(middleLoc)[0] + '.worldPosition[0]', lowDist + '.startPoint' ) cmds.connectAttr( cmds.listRelatives(endLoc)[0] + '.worldPosition[0]', lowDist + '.endPoint' ) cmds.pointConstraint( limbStartCtrl.control, startLoc ) cmds.pointConstraint( pvCtrl.control, middleLoc ) cmds.pointConstraint( limbEndCtrl.control, endLoc ) # create and connect blend utilities bl2aLockUp = cmds.shadingNode( 'blendTwoAttr', asUtility=True ) bl2aLockUp = cmds.rename(bl2aLockUp, common.getName(node=bl2aLockUp, side=side, rigPart=name, function='lock_up', nodeType='bl2a')) bl2aLockLow = cmds.shadingNode( 'blendTwoAttr', asUtility=True ) bl2aLockLow = cmds.rename(bl2aLockLow, common.getName(node=bl2aLockLow, side=side, rigPart=name, function='lock_low', nodeType='bl2a')) cmds.connectAttr( ssKeyUp+'.output', bl2aLockUp + '.input[0]' ) cmds.connectAttr( upDist + '.distance', bl2aLockUp + '.input[1]' ) cmds.connectAttr( limbEndCtrl.control + '.lock', bl2aLockUp + '.attributesBlender' ) cmds.connectAttr( bl2aLockUp + '.output', joint2 + '.translateX', force = True ) cmds.connectAttr( ssKeyLow+'.output', bl2aLockLow + '.input[0]' ) cmds.connectAttr( lowDist + '.distance', bl2aLockLow + '.input[1]' ) cmds.connectAttr( limbEndCtrl.control + '.lock', bl2aLockLow + '.attributesBlender' ) cmds.connectAttr( bl2aLockLow + '.output', joint3 + '.translateX', force = True ) # get distance nodes transforms and rename upDist = cmds.listRelatives( upDist, parent=True )[0] upDist = cmds.rename( upDist, common.getName(node=upDist, side=side, rigPart=name, function='up', nodeType='distance') ) lowDist = cmds.listRelatives( lowDist, parent=True )[0] lowDist = cmds.rename( lowDist, common.getName(node=lowDist, side=side, rigPart=name, function='low', nodeType='distance') ) # negate distance output if side = rt if side == 'rt': mdivLockRev = cmds.shadingNode( 'multiplyDivide', asUtility=True) mdivLockRev = cmds.rename( mdivLockRev, common.getName(node=mdivLockRev, side=side, rigPart=name, function='lock_dist_rev', nodeType='mdiv') ) cmds.setAttr( mdivLockRev + '.input2', -1, -1, -1 ) cmds.connectAttr( upDist + '.distance', mdivLockRev + '.input1X', force=True ) cmds.connectAttr( mdivLockRev + '.outputX', bl2aLockUp + '.input[1]', force=True ) cmds.connectAttr( lowDist + '.distance', mdivLockRev + '.input1Y', force=True ) cmds.connectAttr( mdivLockRev + '.outputY', bl2aLockLow + '.input[1]', force=True ) # group lock utilities lockGrp = cmds.group( startLoc, middleLoc, endLoc, upDist, lowDist, name=side + '_' + name + '_lock_grp' ) # # CLEAN UP # # hide objects if cleanUp: cmds.setAttr( ikHandle+'.v', 0 ) cmds.parent( ikHandle, limbEndCtrl.control ) cmds.setAttr( lowTwistDict['twist_curve']+'.inheritsTransform', 0 ) cmds.setAttr( upTwistDict['twist_curve']+'.inheritsTransform', 0 ) for mp in cmds.listRelatives( lowTwistDict['motionPaths_group'] ) + cmds.listRelatives( upTwistDict['motionPaths_group'] ): cmds.setAttr( mp+'.inheritsTransform', 0 ) if isLeg: cmds.setAttr( limbStartCtrl.control+'.v', 0 ) # hides first control of the leg # parenting everything under one group cmds.parent( limbStartCtrlGrp, limbEndCtrlGrp, pvCtrlGrp, systemGrp ) # ctrls hideGrp = cmds.group( joint1, startNonRoll['main_grp'], ssGrp, lockGrp, crvJntA1, crvJntD1Grp, lowTwistDict['twist_curve'], upTwistDict['twist_curve'], avgGrp, lowTwistDict['motionPaths_group'], upTwistDict['motionPaths_group'], upTwistDict['joints_group'], lowTwistDict['joints_group'], name=systemGrp.replace('_grp', '_hide_grp'), parent=systemGrp ) cmds.setAttr( hideGrp+'.v', 0 ) cmds.parentConstraint( limbStartCtrl.control, hideGrp, mo=True ) # lock and hide attributes cmds.setAttr( limbStartCtrl.control + '.sx', lock=True, keyable=False, channelBox=False ) cmds.setAttr( limbStartCtrl.control + '.sy', lock=True, keyable=False, channelBox=False ) cmds.setAttr( limbStartCtrl.control + '.sz', lock=True, keyable=False, channelBox=False ) cmds.setAttr( limbStartCtrl.control + '.visibility', lock=True, keyable=False, channelBox=False ) cmds.setAttr( pvCtrl.control + '.rx', lock=True, keyable=False, channelBox=False ) cmds.setAttr( pvCtrl.control + '.ry', lock=True, keyable=False, channelBox=False ) cmds.setAttr( pvCtrl.control + '.rz', lock=True, keyable=False, channelBox=False ) cmds.setAttr( pvCtrl.control + '.sx', lock=True, keyable=False, channelBox=False ) cmds.setAttr( pvCtrl.control + '.sy', lock=True, keyable=False, channelBox=False ) cmds.setAttr( pvCtrl.control + '.sz', lock=True, keyable=False, channelBox=False ) cmds.setAttr( pvCtrl.control + '.visibility', lock=True, keyable=False, channelBox=False ) cmds.setAttr( limbEndCtrl.control + '.visibility', lock=True, keyable=False, channelBox=False ) cmds.setAttr( limbEndCtrl.control + '.sx', lock=True, keyable=False, channelBox=False ) cmds.setAttr( limbEndCtrl.control + '.sy', lock=True, keyable=False, channelBox=False ) cmds.setAttr( limbEndCtrl.control + '.sz', lock=True, keyable=False, channelBox=False ) returnDic = { 'ikHandle' : ikHandle, 'jointList' : [ joint1, joint2, joint3, joint4 ], 'poleVector' : pvCtrl, 'poleVector_grp' : pvCtrlGrp, 'start_ctrl' : limbStartCtrl.control, 'end_ctrl' : limbEndCtrl.control, 'end_ctrl_grp' : limbEndCtrlGrp, 'skinJoints_group' : [ upTwistDict['joints_group'], lowTwistDict['joints_group'] ], 'limbSystem_grp' : systemGrp, 'stretch_positions': [ ssStartPos, ssEndPos ] } return returnDic