Esempio n. 1
0
    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()
Esempio n. 2
0
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
Esempio n. 3
0
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}
Esempio n. 4
0
def build(
    hips=None, chest=None, head=None, numSpineJoints=6, numHeadJoints=6, twistAxis="x", bendAxis="y", cleanUp=True
):
    """
    function to create the fk spine with head isolation...
    
    requires 3 objects to be selected or supplied - hips, chest, head
    
    hips: location of the first spine joint - this joint doesn't inherit any chest rotation
    chest: where the chest ctrl is placed. It's rotation is distributed from the second spine joint up to this point
    head: location of the last spine joint

    """

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    return returnDict
Esempio n. 5
0
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