def __finaliseCtrl(self): """ This function is in charge for orienting, scaling and zeroing out the control """ self.__aimCtrl() if self.size != 1: shapes = cmds.listRelatives(self.control, shapes=True) for s in shapes: cmds.select("%s.cv[:]" % s) cmds.scale(self.size, self.size, self.size, r=1) cmds.select(clear=True) cmds.delete(self.control, ch=1) if self.group == True: common.insertGroup(self.control) # self.controlGrp = self.__groupHier(self.control) if self.flip == True: self.__flip()
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( 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