示例#1
0
 def addFKChain(self, startJoint, endJoint, parent):
     '''Create chain of FK ctrls on given joints, returns list of created ctrls
     - parent = parent of the first ctrl
     '''
     RIGLOG.debug('adding FKChain')
     jointList = mpJoint.getJointList(startJoint, endJoint)
     ctrlParent = parent
     fkCtrls = []
     prevCtrl = None
     for idx, joint in enumerate(jointList):
         zero, fkCtrl = self.addCtrl('%02d' % idx,
                                     type='FK',
                                     shape='sphere',
                                     parent=ctrlParent,
                                     xform=joint)
         #first ctrl should do translation of joint, so chain moves with ctrls
         if idx == 0:
             cmds.pointConstraint(fkCtrl, joint, mo=True)
         cmds.orientConstraint(fkCtrl, joint,
                               mo=True)  #every joint driven by ori cns
         ctrlParent = fkCtrl
         mpAttr.lockAndHide(fkCtrl, 't')  #translate not needed on fk chain
         fkCtrls.append(fkCtrl)
         if prevCtrl:
             mpRig.addPickParent(fkCtrl, prevCtrl)  #for pickwalk later
         prevCtrl = fkCtrl
         mpRig.addSnapParent(fkCtrl, joint)  #for snapping FK to IK
     return fkCtrls
示例#2
0
文件: generic.py 项目: BenBarker/mpyr
    def build(self):
        FKChain.build(self)
        #add offset between each ctrl
        curls = list()
        for idx, ctrl in enumerate(self.ctrls):
            #get zero null:
            zero = cmds.listRelatives(ctrl, p=1)[0]
            self.name.desc = 'Curl%02d' % idx
            curlNull = cmds.group(em=True, n=self.name.get(), p=zero)
            cmds.xform(curlNull,
                       ws=True,
                       m=cmds.xform(zero, q=True, ws=True, m=True))
            cmds.parent(ctrl, curlNull)
            curls.append(curlNull)
        #make curl ctrl
        curlZero, curlCtrl = self.addCtrl('curl',
                                          type='FK',
                                          shape='spoon',
                                          parent=self.pinParent,
                                          xform=self.ctrls[0],
                                          size=3.5)
        mpAttr.lockAndHide(curlCtrl, 't')

        #connect curl ctrl
        for curl in curls:
            for axis in 'xyz':
                cmds.connectAttr(curlCtrl + '.r%s' % axis,
                                 curl + '.r%s' % axis)
示例#3
0
文件: rigbase.py 项目: BenBarker/mpyr
    def lock(self):
        '''Lock and hide nodes that shouldn't be touched'''
        RIGLOG.info('locking rig')

        cmds.setAttr(self.rigNode + '.rigVersion', lock=True)
        cmds.setAttr(self.rigNode + '.buildDate', lock=True)
        cmds.setAttr(self.rigNode + '.builtBy', lock=True)

        for node in (self.limbNode, self.geoNode, self.skeletonNode,
                     self.rigNode):
            mpAttr.lockAndHide(node, ['t', 'r', 's', 'v'])
        for limb in self.limbs:
            mpAttr.lockAndHide(limb.limbNode, ['t', 'r', 's', 'v'])
示例#4
0
文件: ctrl.py 项目: BenBarker/mpyr
def addCtrl(ctrlname,
            shape='sphere',
            size=1.0,
            segments=13,
            parent=None,
            color=None,
            shapeXform=None,
            xform=None):
    '''make a ctrl with a given shape out of a curve, parented under a zero null
    shape: sphere,cube,circle,cross,pyramid,line,spoon
    size: defaults to 1.0
    segments: used on round shapes, defaults to 13
    parent: object to parent under (if any)
    color: maya color name or color index
    shapeXform: a matrix or object (uses worldMatrix) to transform ctrl shape with. This is only cosmetic.
    xform: an object, vector, or matrix to xform the transform and rotationOrder of the ctrl
    '''
    #get shape with name
    crv = getCurve(shape, size=size, segments=segments)

    #rename and make zero null
    crv = cmds.rename(crv, ctrlname)
    zero = cmds.createNode('transform', n=crv + "_Zero")
    attr.hideAnimChannels(zero)

    #lock scale
    #In the rare cases that a ctrl must be scaled this can simply be unlocked.
    #Otherwise this saves a lot of headache later IMO.
    attr.lockAndHide(crv, 's')

    #parent under zero null so it's local xforms are zero
    cmds.parent(crv, zero)

    #set color based on argument, or position (based on name) if not specified
    if not color:
        color = getPositionColor(ctrlname)
    setColor(ctrlname, color)

    #do transforming (if given)
    if shapeXform:
        cluster = cmds.cluster(crv)
        xfMatrix = rigmath.Transform(shapeXform)
        cmds.xform(cluster, ws=True, m=xfMatrix.get())
        cmds.delete(crv, ch=True)
    else:
        shapeXform = rigmath.Transform()

    if parent:
        cmds.parent(zero, parent)

    #store shape transform for later, if needed
    cmds.addAttr(crv, dt='matrix', ln='shapeMatrix')
    shapeXform.scale(size)
    cmds.setAttr(crv + '.shapeMatrix', *shapeXform.get(), type='matrix')

    #flag
    setAsCtrl(crv)

    if xform:
        #if name of node then math matrix and rotate order
        if isinstance(xform, str) and cmds.objExists(xform):
            matchMatrix = cmds.xform(xform, q=True, ws=True, m=True)
            attr.matchAttr(xform, zero, "rotateOrder")
            attr.matchAttr(xform, crv, "rotateOrder")
        #otherwise just match matrix.
        #wrapping a Transform here for convenience
        else:
            try:
                matchMatrix = rigmath.Transform(xform).get()
            except RuntimeError:
                raise RuntimeError(
                    "Couldn't find object or transform %s to match" % xform)
        cmds.xform(zero, ws=True, m=matchMatrix)
    return (zero, crv)
示例#5
0
    def addFKIKChain(self, startJoint, endJoint, localParent, worldParent):
        '''Create a chain of FK ctrls with a blended IKRP solver. Requires three or more joints in chain.
        Also creates a "stub" joint with an SC solver at the end of the chain, so that the last joint's
        rotation is blended between the IK end ctrl and the last FK ctrl properly.
        - localParent = drives translation of FK chain always, rotation when local space is on. IK ignores.
        - worldParent = drives rotation when 'world' space is blended on. Drives IK translate and rotate.
        Returns list of [FkCtrl1,FKCtrl2,...,IKAim,IKEnd]
        '''
        jointList = mpJoint.getJointList(startJoint, endJoint)
        if len(jointList) < 3:
            raise RuntimeError('FKIKChain needs at least three joints')
        fkCtrls = self.addFKChain(startJoint, endJoint, localParent)
        aimCtrl, endCtrl = self.addIKChain(startJoint, endJoint, worldParent)

        #lock mid ctrls axes so the FK system can only rotate on one plane.
        #This is needed so the IK system, which is always on a plane, can snap to the FK system
        #First find which axis will be locked by checking its local axes against the
        #normal vector of the chain. The highest dot product is the most parallel.
        #Note: I may need to lock joint DoF as well, sometimes Maya injects tiny rotation values there
        #when in IK mode.
        midJointIdx = int(len(jointList) / 2)
        midJoint = jointList[midJointIdx]
        startV = mpMath.Vector(startJoint)
        midV = mpMath.Vector(midJoint)
        endV = mpMath.Vector(endJoint)
        chainMid = midV - startV
        chainEnd = endV - startV
        chainMid.normalize()
        chainEnd.normalize()
        chainNormal = chainMid.cross(chainEnd)
        chainNormal.normalize()
        axes = ['x', 'y', 'z']
        for ctrl in fkCtrls[1:-1]:
            ctrlXform = mpMath.Transform(ctrl)
            dots = list()
            dots.append(abs(ctrlXform.xAxis().dot(chainNormal)))
            dots.append(abs(ctrlXform.yAxis().dot(chainNormal)))
            dots.append(abs(ctrlXform.zAxis().dot(chainNormal)))
            del axes[dots.index(max(dots))]
            for axis in axes:
                mpAttr.lockAndHide(ctrl, ['r%s' % axis])

        #constrain fk ctrls to local/world
        firstFKZero = cmds.listRelatives(fkCtrls[0], p=True)[0]
        cmds.parentConstraint(localParent, firstFKZero, mo=True)

        #make a stub joint and an SCIKsolver
        #This is using Maya's built in 'ikBlend' blends rotate on the last joint
        self.name.desc = 'ikStub'
        cmds.select(cl=True)
        stubJoint = cmds.joint(n=self.name.get())
        cmds.parent(stubJoint, endJoint)
        stubPos = endV + ((endV - midV) * 0.5)
        cmds.xform(stubJoint, t=stubPos.get(), ws=True)
        self.name.desc = 'iKStubHandle'
        stubHandle, stubEffector = cmds.ikHandle(n=self.name.get(),
                                                 solver='ikSCsolver',
                                                 sj=endJoint,
                                                 ee=stubJoint)
        self.name.desc = 'stubEffector'
        stubEffector = cmds.rename(stubEffector, self.name.get())
        cmds.parent(stubHandle, self.noXform)
        cmds.parentConstraint(endCtrl, stubHandle, mo=True)
        mpCache.flag(stubJoint,
                     False)  #don't want stub joints saved in jointSRTs

        #Construct the blend
        FKIKblender = self.addAttrLimb(ln=mpName.FKIKBLENDATTR,
                                       at='float',
                                       min=0,
                                       max=1,
                                       dv=0,
                                       k=True)
        effector, handle = mpJoint.getIKNodes(endJoint)
        cmds.connectAttr(FKIKblender, handle + '.ikBlend')
        cmds.connectAttr(FKIKblender, stubHandle + '.ikBlend')

        #switch ctrl vis
        for ctrl in (aimCtrl, endCtrl):
            shape = cmds.listRelatives(ctrl, s=True)[0]
            mpAttr.connectWithAdd(FKIKblender, shape + '.v', 0.4999999)
        for ctrl in fkCtrls:
            shape = cmds.listRelatives(ctrl, s=True)[0]
            adder = mpAttr.connectWithAdd(FKIKblender, shape + '.v',
                                          -0.4999999)
            mpAttr.connectWithReverse(adder + '.output',
                                      shape + '.v',
                                      force=True)

        #setup IK->FK snapping messages
        #Since the IK end ctrl and the last FK ctrl can have totally different oris,
        #make a null matching the IK's ori under the FK ctrl to act as a snap target
        self.name.desc = 'ikEndSnap'
        endSnapNull = cmds.group(em=True, n=self.name.get(), p=fkCtrls[-1])
        cmds.xform(endSnapNull,
                   ws=True,
                   m=cmds.xform(endCtrl, q=True, ws=True, m=True))
        mpRig.addSnapParent(endCtrl, endSnapNull)
        mpRig.addSnapParent(aimCtrl, fkCtrls[0])
        mpRig.addSnapParent(aimCtrl, fkCtrls[1])
        mpRig.addSnapParent(aimCtrl, fkCtrls[2])

        #cleanup
        for hideObject in (handle, stubHandle, stubJoint):
            cmds.setAttr(hideObject + '.v', 0)
            mpAttr.lockAndHide(hideObject, 'v')

        fkCtrls.extend([aimCtrl, endCtrl])
        return fkCtrls
示例#6
0
文件: leg.py 项目: BenBarker/mpyr
    def build(self):
        jointList = mpJoint.getJointList(self.startJoint, self.endJoint)
        if len(jointList) < 5:
            raise RuntimeError(
                'LegFKIK requires at least 5 joints in chain: hip/knee/ankle/ball/toetip. Got %s'
                % len(jointList))

        #start with standard blend setup and FKIKChain
        self.addPinBlend()
        legCtrls = self.addFKIKChain(jointList[0], jointList[-3],
                                     self.pinBlend, self.pinWorld)

        #add FK offsets to ball
        ballFKZero, ballFKCtrl = self.addCtrl('%02d' % len(jointList[:-2]),
                                              type='FK',
                                              shape='sphere',
                                              parent=legCtrls[-3],
                                              xform=jointList[-2])
        mpAttr.lockAndHide(ballFKCtrl, 't')
        cmds.orientConstraint(ballFKCtrl, jointList[-2], mo=True)

        #addFKIKChain returns list with [...,lastFK,IKAim,IKEnd], so grabbing last FK for pick parent:
        mpRig.addPickParent(ballFKCtrl, legCtrls[-3])

        #create classic 'reverse foot' setup
        if self.heel:
            heelPos = mpMath.Transform(self.heel)
        else:
            RIGLOG.warning(
                'No ".heel" joint specified on LegFKIK, guessing pivot')
            #take the ball->toe length, double it, and go back from the ball that much
            heelOffset = mpMath.Vector(jointList[-2])  #ball
            heelOffset -= mpMath.Vector(jointList[-1])  #minus toe
            heelOffset *= 2
            heelOffset + mpMath.Vector(jointList[-2])  #add back to ball
            heelPos = mpMath.Transform(
                jointList[-2])  #heel equal ball plus our new vector
            heelPos += heelOffset

        #Make ik single chains for ball and toe
        self.name.desc = 'ikHandleBall'
        ballHandle, ballEffector = cmds.ikHandle(n=self.name.get(),
                                                 solver='ikSCsolver',
                                                 sj=jointList[-3],
                                                 ee=jointList[-2])
        self.name.desc = 'ikHandleToe'
        toeHandle, toeEffector = cmds.ikHandle(n=self.name.get(),
                                               solver='ikSCsolver',
                                               sj=jointList[-2],
                                               ee=jointList[-1])

        self.name.desc = 'ballEffector'
        ballEffector = cmds.rename(ballEffector, self.name.get())
        cmds.parent(ballHandle, self.noXform)
        self.name.desc = 'toeEffector'
        toeEffector = cmds.rename(toeEffector, self.name.get())
        cmds.parent(toeHandle, self.noXform)

        #Make foot controls
        #These transforms are for cosmetic SRT of the foot controls
        anklePos = mpMath.Vector(jointList[-3])
        heelVec = mpMath.Vector(heelPos)
        footCtrlXform = mpMath.Transform()
        footCtrlXform.scale(2, 0.4, 4)
        footCtrlXform.translate(0, heelVec.y - anklePos.y, 0)
        toeCtrlXform = mpMath.Transform()
        toeCtrlXform.setFromEuler(0, 90, 0)

        footZero, footCtrl = self.addCtrl('Foot',
                                          shape='cube',
                                          type='IK',
                                          parent=self.pinWorld,
                                          xform=mpMath.Vector(jointList[-3]),
                                          shapeXform=footCtrlXform)
        heelZero, heelCtrl = self.addCtrl('Heel',
                                          shape='circle',
                                          type='IK',
                                          parent=footCtrl,
                                          xform=heelPos,
                                          shapeXform=toeCtrlXform)
        toeTipZero, toeTipCtrl = self.addCtrl('ToeTip',
                                              shape='circle',
                                              type='IK',
                                              parent=heelCtrl,
                                              xform=jointList[-1],
                                              shapeXform=toeCtrlXform)
        ballZero, ballCtrl = self.addCtrl('Ball',
                                          shape='circle',
                                          type='IK',
                                          parent=toeTipCtrl,
                                          xform=jointList[-2],
                                          shapeXform=toeCtrlXform)

        cmds.parentConstraint(ballCtrl, ballHandle, mo=True)
        cmds.parentConstraint(toeTipCtrl, toeHandle, mo=True)

        #Blend already exists, but this will grab the right attr
        FKIKblender = self.addAttrLimb(ln=mpName.FKIKBLENDATTR,
                                       at='float',
                                       min=0,
                                       max=1,
                                       dv=0,
                                       k=True)
        cmds.connectAttr(FKIKblender, ballHandle + '.ikBlend')
        cmds.connectAttr(FKIKblender, toeHandle + '.ikBlend')

        #constrain legIK endctrl to new foot ctrl
        ankleIKCtrl = legCtrls[-1]
        mpAttr.unlockAndShow(ankleIKCtrl, 'r')
        cmds.parentConstraint(ballCtrl, ankleIKCtrl, mo=True)

        #swap out foot for old IK handle ctrl
        #First retrieve effector, handle, aim, and endNull from IK system
        effector, handle = mpJoint.getIKNodes(jointList[-3])
        handleCns = cmds.listConnections(handle + '.tx', s=1, d=0)[0]
        endNull = cmds.listConnections(handleCns +
                                       '.target[0].targetTranslate',
                                       s=1,
                                       d=0)[0]
        endNullCns = cmds.listConnections(endNull + '.tx', s=1, d=0)[0]
        aimCtrl = legCtrls[-2]
        aimCtrlZero = cmds.listRelatives(aimCtrl, p=True)[0]

        #delete old aimCtrl blend cns
        cmds.delete(cmds.listConnections(aimCtrlZero + '.tx', s=1, d=0)[0])
        cmds.pointConstraint(self.pinWorld, footCtrl, aimCtrlZero, mo=True)

        #delete old IK ctrl and wire IK to new foot ctrl
        cmds.delete(endNullCns)
        cmds.parentConstraint(ballCtrl, endNull, mo=True)
        self.deleteCtrl(legCtrls[-1])

        #add new pickwalk/snap info
        mpRig.addPickParent(footCtrl, legCtrls[-2])
        mpRig.addPickParent(ballCtrl, footCtrl)
        mpRig.addPickParent(toeTipCtrl, ballCtrl)
        mpRig.addPickParent(heelCtrl, toeTipCtrl)

        #Make some nulls to act as snap targets. This is because IK and FK controls might have different axis order or initial positions.
        self.name.desc = 'ikAnkleSnapTarget'
        ikAnkleSnapTarget = cmds.group(em=True,
                                       n=self.name.get(),
                                       p=legCtrls[-3])
        cmds.xform(ikAnkleSnapTarget,
                   ws=True,
                   m=cmds.xform(footCtrl, ws=True, q=True, m=True))
        mpRig.addSnapParent(footCtrl, ikAnkleSnapTarget)

        self.name.desc = 'ikBallSnapTarget'
        ikBallSnapTarget = cmds.group(em=True, n=self.name.get(), p=ballFKCtrl)
        cmds.xform(ikBallSnapTarget,
                   ws=True,
                   m=cmds.xform(ballCtrl, ws=True, q=True, m=True))
        mpRig.addSnapParent(ballCtrl, ikBallSnapTarget)

        self.name.desc = 'fkBallSnapTarget'
        fkBallSnapTarget = cmds.group(em=True, n=self.name.get(), p=ballCtrl)
        cmds.xform(fkBallSnapTarget,
                   ws=True,
                   m=cmds.xform(ballFKCtrl, ws=True, q=True, m=True))
        mpRig.addSnapParent(ballFKCtrl, fkBallSnapTarget)

        self.name.desc = 'ikToeSnapTarget'
        ikToeSnapTarget = cmds.group(em=True, n=self.name.get(), p=ballFKCtrl)
        cmds.xform(ikToeSnapTarget,
                   ws=True,
                   m=cmds.xform(toeTipCtrl, ws=True, q=True, m=True))
        mpRig.addSnapParent(toeTipCtrl, ikToeSnapTarget)

        #add new ctrls to vis switch
        for ctrl in (footCtrl, heelCtrl, toeTipCtrl, ballCtrl):
            shape = cmds.listRelatives(ctrl, s=True)[0]
            mpAttr.connectWithAdd(FKIKblender, shape + '.v', 0.4999999)
        for ctrl in [ballFKCtrl]:
            shape = cmds.listRelatives(ctrl, s=True)[0]
            adder = mpAttr.connectWithAdd(FKIKblender, shape + '.v',
                                          -0.4999999)
            revNode = mpAttr.connectWithReverse(adder + '.output',
                                                shape + '.v',
                                                force=True)

        #cleanup
        for item in [ballHandle, toeHandle, handle]:
            mpAttr.visOveride(item, 0)
示例#7
0
文件: leg.py 项目: BenBarker/mpyr
    def build(self):
        jointList = mpJoint.getJointList(self.startJoint, self.endJoint)
        if len(jointList) < 5:
            raise RuntimeError(
                'LegFKIK requires at least 5 joints in chain: hip/knee/ankle/ball/toetip. Got %s'
                % len(jointList))

        #Internally the dog leg is driven by a 3 joint ik system made here.
        #This three joint IK has the same total length as hip->ball joint chain.
        length = mpJoint.getChainLength(jointList[0], jointList[-2])
        halfLength = length / 2.0

        hip = mpMath.Vector(jointList[0])
        knee = mpMath.Vector(jointList[1])
        ball = mpMath.Vector(jointList[-2])

        legBaseV = ball - hip
        legBaseMidV = legBaseV * 0.5
        binormalLength = -1 * math.sqrt(
            0.5 * legBaseV.length()**2 / halfLength**2)

        #Find the isoceles triange that is coplanar with the leg chain,
        #and whose tall legs sum to the same length as the dogleg.
        #The top vertex of this triangle is where we want the mid joint on our
        #three joint system
        kneeV = knee - hip
        kneeV.normalize()
        ballV = ball - hip
        ballV.normalize()
        chainNormal = kneeV.cross(ballV)
        chainNormal.normalize()
        chainBinorm = chainNormal.cross(kneeV)
        chainBinorm *= binormalLength
        midJointPos = (legBaseMidV + chainBinorm) + hip

        #make driver joints
        cmds.select(cl=True)
        self.name.desc = 'driverJoint01'
        driverJnt1 = cmds.joint(n=self.name.get(), p=hip.get())
        self.name.desc = 'driverJoint02'
        driverJnt2 = cmds.joint(n=self.name.get(), p=midJointPos.get())
        self.name.desc = 'driverJoint03'
        driverJnt3 = cmds.joint(n=self.name.get(), p=ball.get())

        #start with standard blend setup and FKIKChain on hip->ankle
        self.addPinBlend()
        legCtrls = self.addFKIKChain(jointList[0], jointList[-3],
                                     self.pinBlend, self.pinWorld)
        ikEnd = legCtrls[-1]
        effector, handle = mpJoint.getIKNodes(jointList[-3])

        #add FK offsets to ball
        ballFKZero, ballFKCtrl = self.addCtrl('%02d' % len(jointList[:-2]),
                                              type='FK',
                                              shape='sphere',
                                              parent=legCtrls[-3],
                                              xform=jointList[-2])
        mpAttr.lockAndHide(ballFKCtrl, 't')
        cmds.orientConstraint(ballFKCtrl, jointList[-2], mo=True)
        mpRig.addPickParent(ballFKCtrl, legCtrls[-3])

        #Make IK Chain on driver joints
        oldpart = self.name.part
        self.name.part += "Driver"
        driverAimCtrl, driverEndCtrl = self.addIKChain(driverJnt1, driverJnt3,
                                                       self.pinWorld)
        self.name.part = oldpart

        #set ctrl flags false on driver ctrls.
        #This way animators will never touch them and they won't snap/reset/etc.
        driverEndNull = cmds.listRelatives(driverEndCtrl, p=True)[0]
        mpCtrl.setAsCtrl(driverEndCtrl, False)
        mpCtrl.setAsCtrl(driverAimCtrl, False)
        #and delete shapes so they aren't visible
        for ctrl in (driverEndCtrl, driverAimCtrl):
            self.ctrls.remove(ctrl)
            cmds.delete(cmds.listRelatives(ctrl, s=True)[0])

        #make single chain on ankle->ball and ball->tip for ankle roll and toe tap
        self.name.desc = 'ikHandleBall'
        ballHandle, ballEffector = cmds.ikHandle(n=self.name.get(),
                                                 solver='ikSCsolver',
                                                 sj=jointList[-3],
                                                 ee=jointList[-2])
        self.name.desc = 'ikHandleToe'
        toeHandle, toeEffector = cmds.ikHandle(n=self.name.get(),
                                               solver='ikSCsolver',
                                               sj=jointList[-2],
                                               ee=jointList[-1])

        self.name.desc = 'ballEffector'
        ballEffector = cmds.rename(ballEffector, self.name.get())
        cmds.parent(ballHandle, self.noXform)
        self.name.desc = 'toeEffector'
        toeEffector = cmds.rename(toeEffector, self.name.get())
        cmds.parent(toeHandle, self.noXform)

        #Make a ankle roll ctrl and toe tap ctrl
        #These transforms are for cosmetic SRT of the foot controls
        footCtrlXform = mpMath.Transform()
        footCtrlXform.scale(2, 0.4, 4)
        toeCtrlXform = mpMath.Transform()
        toeCtrlXform.setFromEuler(0, 90, 0)

        footZero, footCtrl = self.addCtrl('Foot',
                                          shape='cube',
                                          type='IK',
                                          parent=self.pinWorld,
                                          xform=mpMath.Vector(jointList[-2]),
                                          shapeXform=footCtrlXform)
        toeTipZero, toeTipCtrl = self.addCtrl('ToeTip',
                                              shape='circle',
                                              type='IK',
                                              parent=footCtrl,
                                              xform=jointList[-1],
                                              shapeXform=toeCtrlXform)
        ballZero, ballCtrl = self.addCtrl('Ball',
                                          shape='circle',
                                          type='IK',
                                          parent=toeTipCtrl,
                                          xform=jointList[-2],
                                          shapeXform=toeCtrlXform)

        #parent constrain single chains under new ctrls
        cmds.parentConstraint(ballCtrl, ballHandle, mo=True)
        cmds.parentConstraint(toeTipCtrl, toeHandle, mo=True)
        cmds.parentConstraint(footCtrl, driverEndNull, mo=True)

        #parent constrain ankle IK to new foot ctrls
        driverEffector, driverHandle = mpJoint.getIKNodes(driverJnt3)
        mpAttr.unlockAndShow(ikEnd, 'r')
        ikEndNull = cmds.listRelatives(ikEnd, p=True)[0]
        cmds.parentConstraint(ballCtrl, ikEndNull, mo=True)
        cmds.parentConstraint(toeTipCtrl, driverHandle, mo=True)

        #parent constrain ball ctrl to driver knee joint
        cmds.parentConstraint(driverJnt2, ballZero, mo=True)

        #Blend already exists, but this will grab the right attr
        FKIKblender = self.addAttrLimb(ln=mpName.FKIKBLENDATTR,
                                       at='float',
                                       min=0,
                                       max=1,
                                       dv=0,
                                       k=True)
        cmds.connectAttr(FKIKblender, ballHandle + '.ikBlend')
        cmds.connectAttr(FKIKblender, toeHandle + '.ikBlend')

        #add new pickwalk/snap info
        mpRig.addPickParent(footCtrl, legCtrls[-2])
        mpRig.addPickParent(ballCtrl, footCtrl)
        mpRig.addPickParent(toeTipCtrl, ballCtrl)

        #Make some nulls to act as snap targets. This is because IK and FK controls might have different axis order or initial positions.
        self.name.desc = 'ikAnkleSnapTarget'
        ikAnkleSnapTarget = cmds.group(em=True,
                                       n=self.name.get(),
                                       p=jointList[-2])
        cmds.xform(ikAnkleSnapTarget,
                   ws=True,
                   m=cmds.xform(footCtrl, ws=True, q=True, m=True))
        mpRig.addSnapParent(footCtrl, ikAnkleSnapTarget)

        self.name.desc = 'ikBallSnapTarget'
        ikBallSnapTarget = cmds.group(em=True, n=self.name.get(), p=ballFKCtrl)
        cmds.xform(ikBallSnapTarget,
                   ws=True,
                   m=cmds.xform(ballCtrl, ws=True, q=True, m=True))
        mpRig.addSnapParent(ballCtrl, ikBallSnapTarget)

        self.name.desc = 'fkBallSnapTarget'
        fkBallSnapTarget = cmds.group(em=True,
                                      n=self.name.get(),
                                      p=jointList[-2])
        cmds.xform(fkBallSnapTarget,
                   ws=True,
                   m=cmds.xform(ballFKCtrl, ws=True, q=True, m=True))
        mpRig.addSnapParent(ballFKCtrl, fkBallSnapTarget)

        self.name.desc = 'ikToeSnapTarget'
        ikToeSnapTarget = cmds.group(em=True, n=self.name.get(), p=ballFKCtrl)
        cmds.xform(ikToeSnapTarget,
                   ws=True,
                   m=cmds.xform(toeTipCtrl, ws=True, q=True, m=True))
        mpRig.addSnapParent(toeTipCtrl, ikToeSnapTarget)

        #add new ctrls to vis switch
        for ctrl in (footCtrl, toeTipCtrl, ballCtrl):
            shape = cmds.listRelatives(ctrl, s=True)[0]
            mpAttr.connectWithAdd(FKIKblender, shape + '.v', 0.4999999)
        for ctrl in [ballFKCtrl]:
            shape = cmds.listRelatives(ctrl, s=True)[0]
            adder = mpAttr.connectWithAdd(FKIKblender, shape + '.v',
                                          -0.4999999)
            mpAttr.connectWithReverse(adder + '.output',
                                      shape + '.v',
                                      force=True)

        #cleanup
        for item in [ballHandle, toeHandle, handle]:
            mpAttr.visOveride(item, 0)
        mpAttr.visOveride(driverJnt1, 0)