Ejemplo n.º 1
0
    def __init__(self, name, wireType, facingAxis, aOffset=(0,0,0), size=10, colorId=0, snap=None, ctlOffsets=[]):
        '''
        Initializes control curve
        
        snap - transform node (or nodes) to set initial position for home group (if None, set to origin)
        ctlOffsets - list of groups nodes above control
        '''
        
        self.crv = abRT.makeWireController(wireType, facingAxis, aOffset, size)
        self.crv = mc.rename(self.crv, name)
        
        # color control
        abRT.colorObj(self.crv, colorId)
        
        # set pivot to local origin
        mc.setAttr(self.crv+'.rp', 0,0,0)
        mc.setAttr(self.crv+'.sp', 0,0,0)
        
        # snap control to position if snap is defined, otherwise leave it at origin
        if snap:
            abRT.snapToPosition(snap, self.crv)

        # all controls have a home group, to "freeze" the local transforms
        self.home = abRT.groupFreeze(self.crv)
        self.home = mc.rename(self.home, name+'_hm')
        
        # add optional offset groups between home and actual control
        self.grp = {}
        
        for offsetGrp in ctlOffsets:
            self.grp[offsetGrp] = abRT.groupFreeze(self.crv)
            self.grp[offsetGrp] = mc.rename(self.grp[offsetGrp], name+'_'+offsetGrp)
Ejemplo n.º 2
0
def globalRig():
    """
    Make global teeth rig
    """
    # teeth aim locs
    globalGrp = 'CT_teethBlockGlobal_mod_0'
    locNum = 7
    name = 'CT_teethBlock'
    targetCrv = 'CT_teethBlockAim_crv_0'
    locs = []
    for locId in range(locNum):
        loc = mc.spaceLocator(n=name + '_aim_loc_%d' % locId)[0]
        mc.setAttr(loc + '.localScale', 0.1, 0.1, 0.1)
        rt.attachToMotionPath(targetCrv,
                              float(locId) / (locNum - 1), loc, True)
        locs.append(loc)
    mc.group(locs, n='CT_teethBlock_aim_loc_grp')
    rt.connectVisibilityToggle(locs, globalGrp, 'aimLocs', False)

    # teeth bind jnt for each aimLoc
    targetCrv = 'CT_teethBlockDrv_crv_0'
    jnts = []
    for jntId in range(locNum):
        mc.select(cl=True)
        jnt = mc.joint(n=name + '_bnd_jnt_%d' % jntId)
        mc.setAttr(jnt + '.radius', 0.5)
        rt.alignOnMotionPath(targetCrv,
                             float(jntId) / (locNum - 1),
                             jnt,
                             name + '_aim_loc_%d.matrix' % jntId,
                             True,
                             ua=1,
                             inverseUp=True)
        jnts.append(jnt)
    mc.group(jnts, n='CT_teethBlock_bnd_jnts_grp')
    rt.connectVisibilityToggle(jnts, globalGrp, 'bndJnts', False)

    jnts = mc.ls(sl=True)

    import utils.wrappers.abRiggingTools as abRT
    # add bnd jnts for bite
    # for each bndjnt, make another jnt below it
    for bndJnt in jnts:
        mc.select(cl=True)
        biteJnt = mc.joint(n=bndJnt + '_bite')
        mc.setAttr(biteJnt + '.radius', 0.5)
        abRT.snapToPosition(bndJnt, biteJnt)
        mc.xform(biteJnt, t=(0, -1, 0), r=True)
        mc.parentConstraint(bndJnt, biteJnt, mo=True)
        mc.parent(biteJnt, 'CT_teethBlock_bnd_jnts_grp')
Ejemplo n.º 3
0
def duplicateSnapObjToTransforms(obj, transformsList):
    '''
    Duplicate obj and match them to items in transformsList
    
    Returns list of duplicated objs
    '''

    objs = []

    for eachTransform in transformsList:
        dupObj = mc.duplicate(obj, n=eachTransform + '_' + obj)[0]
        abRT.snapToPosition(eachTransform, dupObj)
        mc.parent(dupObj, eachTransform)
        objs.append(dupObj)

    return objs
Ejemplo n.º 4
0
def duplicateSnapObjToTransforms(obj, transformsList):
    '''
    Duplicate obj and match them to items in transformsList
    
    Returns list of duplicated objs
    '''
    
    objs = []
    
    for eachTransform in transformsList:
        dupObj = mc.duplicate(obj, n=eachTransform+'_'+obj)[0]
        abRT.snapToPosition(eachTransform, dupObj)
        mc.parent(dupObj, eachTransform)
        objs.append(dupObj)
        
    return objs
Ejemplo n.º 5
0
def makeOffsetLoc(master, target):
    '''
    creates offsetLoc snapped to target, but parented under master 
    therefore, it inherits transforms from master, but has the offsets matching target
    used for space switching offsets
    
    add attribute target+'_offsetViz' to master
    
    return offsetLoc
    '''
    
    offsetLoc = mc.spaceLocator(n='%s_%s_offsetLoc'%(master, target))[0]
    abRT.snapToPosition(target, offsetLoc)
    mc.parent(offsetLoc, master)
    connectVisibilityToggle([offsetLoc], master, target+'_offsetViz', False)
    
    return offsetLoc
Ejemplo n.º 6
0
def makeOffsetLoc(master, target):
    '''
    creates offsetLoc snapped to target, but parented under master 
    therefore, it inherits transforms from master, but has the offsets matching target
    used for space switching offsets
    
    add attribute target+'_offsetViz' to master
    
    return offsetLoc
    '''

    offsetLoc = mc.spaceLocator(n='%s_%s_offsetLoc' % (master, target))[0]
    abRT.snapToPosition(target, offsetLoc)
    mc.parent(offsetLoc, master)
    connectVisibilityToggle([offsetLoc], master, target + '_offsetViz', False)

    return offsetLoc
Ejemplo n.º 7
0
    def __init__(self,
                 name,
                 wireType,
                 facingAxis,
                 aOffset=(0, 0, 0),
                 size=10,
                 colorId=0,
                 snap=None,
                 ctlOffsets=[]):
        '''
        Initializes control curve
        
        snap - transform node (or nodes) to set initial position for home group (if None, set to origin)
        ctlOffsets - list of groups nodes above control
        '''

        self.crv = abRT.makeWireController(wireType, facingAxis, aOffset, size)
        self.crv = mc.rename(self.crv, name)

        # color control
        abRT.colorObj(self.crv, colorId)

        # set pivot to local origin
        mc.setAttr(self.crv + '.rp', 0, 0, 0)
        mc.setAttr(self.crv + '.sp', 0, 0, 0)

        # snap control to position if snap is defined, otherwise leave it at origin
        if snap:
            abRT.snapToPosition(snap, self.crv)

        # all controls have a home group, to "freeze" the local transforms
        self.home = abRT.groupFreeze(self.crv)
        self.home = mc.rename(self.home, name + '_hm')

        # all controls also have a space group, for space-switching
        self.space = abRT.groupFreeze(self.crv)
        self.space = mc.rename(self.space, name + '_space')

        # add optional offset groups between space and actual control
        self.grp = {}

        for offsetGrp in ctlOffsets:
            self.grp[offsetGrp] = abRT.groupFreeze(self.crv)
            self.grp[offsetGrp] = mc.rename(self.grp[offsetGrp],
                                            name + '_' + offsetGrp)
Ejemplo n.º 8
0
def globalRig():
    """
    Make global teeth rig
    """
    # teeth aim locs
    globalGrp = 'CT_teethBlockGlobal_mod_0'
    locNum = 7
    name = 'CT_teethBlock'
    targetCrv = 'CT_teethBlockAim_crv_0'
    locs=[]
    for locId in range(locNum):
        loc = mc.spaceLocator(n=name+'_aim_loc_%d'%locId)[0]
        mc.setAttr(loc+'.localScale', 0.1,0.1,0.1)
        rt.attachToMotionPath(targetCrv, float(locId)/(locNum-1), loc, True)
        locs.append(loc)
    mc.group(locs, n='CT_teethBlock_aim_loc_grp')
    rt.connectVisibilityToggle(locs, globalGrp, 'aimLocs', False)
    
    # teeth bind jnt for each aimLoc
    targetCrv = 'CT_teethBlockDrv_crv_0'
    jnts=[]
    for jntId in range(locNum):
        mc.select(cl=True)
        jnt = mc.joint(n=name+'_bnd_jnt_%d'%jntId)
        mc.setAttr(jnt+'.radius', 0.5)
        rt.alignOnMotionPath(targetCrv, float(jntId)/(locNum-1), jnt, name+'_aim_loc_%d.matrix'%jntId, True, ua=1, inverseUp=True)
        jnts.append(jnt)
    mc.group(jnts, n='CT_teethBlock_bnd_jnts_grp')
    rt.connectVisibilityToggle(jnts, globalGrp, 'bndJnts', False)
    
    jnts = mc.ls(sl=True)
    
    import utils.wrappers.abRiggingTools as abRT
    # add bnd jnts for bite
    # for each bndjnt, make another jnt below it
    for bndJnt in jnts:
        mc.select(cl=True)
        biteJnt = mc.joint(n=bndJnt+'_bite')
        mc.setAttr(biteJnt+'.radius', 0.5)
        abRT.snapToPosition(bndJnt, biteJnt)
        mc.xform(biteJnt, t=(0,-1,0), r=True)
        mc.parentConstraint(bndJnt, biteJnt, mo=True)
        mc.parent(biteJnt, 'CT_teethBlock_bnd_jnts_grp')
Ejemplo n.º 9
0
def addElbowFkOffset(pvCtl, ikJnts, handCtl, handIkH, wristDrv, elbowDrnCons):
    '''
    ikJnts - (shoulder, elbow, wrist)
    '''
    prefix_side = ikJnts[0].split('_')[-1] + '_'

    armGrp = mc.group(em=True, n=prefix_side + 'armGrp')
    """
    NOT NEEDED - 
    Wrist control will be directed controlled by pvCtl
    
    elbowFKCtl = cs.ctlCurve(prefix_side+'elbowFKOffset_ctl', 'circle', 0, (0,0,0), size=3, colorId=22, snap=pvCtl)
    mc.parent(elbowFKCtl.home, armGrp)
    abRT.hideAttr(elbowFKCtl.crv, ['tx','ty','tz','sx','sy','sz','v'])
    
    # elbowOffsetCtl is in the pvCtl space
    # mc.parentConstraint(ikJnts[1], elbowFKCtl.grp['space'])
    elbowFKCtl.setSpaces([pvCtl], ['PoleVector'])
    """

    # duplicate joint chain (ikJnts[1:]) don't need the shoulder
    fkOffsetGrp = mc.group(em=True,
                           n=prefix_side + 'armFkOffset_grp',
                           p=armGrp)
    fkOffsetJnts = abRT.duplicateJointHierarchy(
        ikJnts[1:], [jnt.replace('IKX', 'FKOffset') for jnt in ikJnts[1:]],
        fkOffsetGrp)
    '''
    # get transforms from IK chain
    mc.parentConstraint(ikJnts[0], fkOffsetJnts[0]) # position & rotation for shoulder
    mc.connectAttr(ikJnts[1]+'.tx', fkOffsetJnts[1]+'.tx', f=True) # stretchy for upperArm
    mc.connectAttr(ikJnts[2]+'.tx', fkOffsetJnts[2]+'.tx', f=True) # stretchy for lowerArm
    '''

    # get offset rotations & rotations from ctrl
    pos = mc.xform(pvCtl, q=True, ws=True, t=True)
    mc.xform(fkOffsetJnts[0], t=pos, ws=True)
    # abRT.snapToPosition(elbowFKCtl.crv, fkOffsetJnts[0])
    mc.setAttr(fkOffsetJnts[0] + '.jointOrient', 0, 0, 0)
    mc.setAttr(fkOffsetJnts[0] + '.ry', 180)
    mc.setAttr(fkOffsetJnts[1] + '.jointOrient', 0, 0, 0)
    mc.setAttr(fkOffsetJnts[1] + '.r', 0, 0, 0)
    mc.parentConstraint(pvCtl, fkOffsetJnts[0], mo=True)

    # unlock rotations for pvCtl, so that we can rotate the elbow
    mc.setAttr(pvCtl + '.rx', l=False, k=True)
    mc.setAttr(pvCtl + '.ry', l=False, k=True)
    mc.setAttr(pvCtl + '.rz', l=False, k=True)
    """
    NOT NEEDED - 
    since FKOffset will drive the Hand
    the Hand will drive the ikHandle
    the ikHandle drive the ikJoints
    Therefore, the deformation system should still follow the ikJoints
    
    #===========================================================================
    # REPLACE IK DRIVERS WITH FKOFFSET DRIVERS
    #===========================================================================
    
    # 1. WRIST DRV (END OF CHAIN)
    # wristDrv = IKFKAlignedArm_L is responsible for driving the endLoc of the bendyCrv
    # therefore, reparent from IKWrist to FKOffsetWrist
    mc.parent(wristDrv, fkOffsetJnts[2])
    
    # 2. ELBOW DRV (START OF CHAIN)
    # elbowDrvCons is responsible for driving the startLoc of the bendyCrv
    mc.parentConstraint(fkOffsetJnts[1], elbowDrnCons)
    wal = mc.parentConstraint(elbowDrnCons, q=1, wal=1)
    targets = mc.parentConstraint(elbowDrnCons, q=1, tl=1)
    targetIndex = targets.index(ikJnts[1])
    #transfer connection from IK to FKOffset
    inConns = mc.listConnections(elbowDrnCons + '.' + wal[targetIndex], p=1, s=1)
    mc.connectAttr(inConns[0], elbowDrnCons+'.'+wal[2], f=True)
    # remove the old IK target
    mc.parentConstraint(ikJnts[1], elbowDrnCons, e=1, rm=1)
    """

    # add wristFKOffsetCtl
    wristFKCtl = cs.ctlCurve(prefix_side + 'wristFKOffset_ctl',
                             'circle',
                             0, (0, 0, 0),
                             size=2,
                             colorId=22,
                             snap=fkOffsetJnts[1],
                             ctlOffsets=['stretchy', 'IkOri'])
    mc.parent(wristFKCtl.home, armGrp)
    abRT.hideAttr(wristFKCtl.crv, ['tx', 'ty', 'tz', 'sx', 'sy', 'sz', 'v'])

    # wristOffsetCtl is in the FKOffset-elbow space
    # mc.parentConstraint(fkOffsetJnts[1], wristFKCtl.grp['space'])
    wristFKCtl.setSpaces([fkOffsetJnts[0]], ['Elbow'])

    # length for lower arm
    mc.addAttr(pvCtl, ln='length', at='double', dv=0, k=True)
    mc.connectAttr(pvCtl + '.length',
                   wristFKCtl.grp['stretchy'] + '.tx',
                   f=True)
    """
    NOT NEEDED ANYMORE-
    It will just follow orientation of FKOffsetElbow
    
    # wristOffsetCtl's align can be switched between parent (FKOffset) or IKHand
    # place a group aligned properly to hand under IKHand for better orientConstraint (since IKHand is in world-space orientation)
    IkHandAlignTarget = mc.group(em=True, n=handCtl+'_alignTarget')
    rt.parentSnap(IkHandAlignTarget, wristFKCtl.crv)
    mc.parent(IkHandAlignTarget, handCtl)
    rt.spaceSwitchSetup([IkHandAlignTarget, elbowFKCtl.crv], wristFKCtl.grp['IkOri'], wristFKCtl.crv, 'orientConstraint', ['IkHand','FkElbow'])
    """

    # create group to blend between IK & FKOffset
    blendGrp = mc.group(em=True, n=handCtl + '-IKFKOffsetBlend_grp', p=armGrp)
    abRT.snapToPosition(handCtl, blendGrp)
    fkOffsetWristTgt = mc.group(em=True, n=wristFKCtl.crv + '_spaceTgt')
    abRT.snapToPosition(handCtl, fkOffsetWristTgt)
    mc.parent(fkOffsetWristTgt, wristFKCtl.crv)
    mc.setAttr(fkOffsetWristTgt + '.t', 0, 0, 0)
    pCons = mc.parentConstraint(handCtl, fkOffsetWristTgt, blendGrp)[0]
    wal = mc.parentConstraint(pCons, q=True, wal=True)

    # connect blend for fkOffset (together with elbow)
    mc.addAttr(pvCtl,
               ln='elbowFkOffsetViz',
               at='double',
               dv=0,
               min=0,
               max=1,
               k=True)
    mc.connectAttr(pvCtl + '.elbowFkOffsetViz', wristFKCtl.crv + '.v', f=True)
    rev = mc.createNode('reverse', n=pvCtl + '_elbowFkOffsetViz_rev')
    mc.connectAttr(pvCtl + '.elbowFkOffsetViz', rev + '.inputX', f=True)
    mc.connectAttr(rev + '.outputX', pCons + '.' + wal[0], f=True)
    mc.connectAttr(pvCtl + '.elbowFkOffsetViz', pCons + '.' + wal[1], f=True)

    mc.parentConstraint(wristFKCtl.crv, fkOffsetJnts[1],
                        mo=True)  # final rotation & position for wristOffset
Ejemplo n.º 10
0
def buildSpineRig(hipMP, headMP, cogCtl, masterCtl):
    '''
    Set up motion system for the spine rig
    
    Return: (spineDrvCrv, spineTwistCrv)
    '''

    #===========================================================================
    # CREATE CONTROLS
    #===========================================================================
    # hip
    hipCtl = cs.ctlCurve('CT_hip_ctl',
                         'cube',
                         1,
                         colorId=22,
                         snap=hipMP,
                         ctlOffsets=['space'])
    mc.setAttr(hipCtl.crv + '.s', 0.3, 1, 1)
    mc.makeIdentity(hipCtl.crv, a=True, s=True)

    # spine-shaper
    spineCtl = cs.ctlCurve('CT_spine_ctl',
                           'circle',
                           0,
                           colorId=22,
                           size=18,
                           ctlOffsets=['point', 'orient'])

    # head
    headCtl = cs.ctlCurve('CT_head_ctl',
                          'cube',
                          1,
                          colorId=22,
                          snap=headMP,
                          ctlOffsets=['space'])
    mc.setAttr(headCtl.crv + '.s', 0.3, 1, 1)
    mc.makeIdentity(headCtl.crv, a=True, s=True)

    # group controls nicely
    ctrlGrp = mc.group(hipCtl.home,
                       spineCtl.home,
                       headCtl.home,
                       n='CT_control_grp_0')

    #===========================================================================
    # CREATE DEBUG GRP - to toggle visibility of "under-the-hood" stuff
    #===========================================================================

    debugGrp = mc.group(em=True, n='CT_debug_grp')
    abRT.hideAttr(debugGrp,
                  ['tx', 'ty', 'tz', 'sx', 'sy', 'sz', 'rx', 'ry', 'rz', 'v'])

    #===========================================================================
    # ADD TANGENT LOCS
    #===========================================================================

    hipTangentMP = ms.addTangentMPTo(hipCtl.crv,
                                     headCtl.crv,
                                     'x',
                                     default=0.1,
                                     reverse=False)
    headTangentMP = ms.addTangentMPTo(headCtl.crv,
                                      hipCtl.crv,
                                      'x',
                                      default=0.5,
                                      reverse=True)

    #===========================================================================
    # ADD MID POINT for spine-shaper control
    #===========================================================================
    midMP = ms.addMidMP(hipTangentMP, headTangentMP, hipCtl.crv, headCtl.crv,
                        (1, 0, 0), (0, 1, 0), 'CT_spineMid_mPt')
    spineCrvs, spineMPs = ms.createSplineMPs(
        (hipCtl.crv, hipTangentMP, spineCtl.crv, headTangentMP, headCtl.crv),
        12, 'CT_spine', (0, 5, 0))

    #===========================================================================
    # add SQUASH AND STRETCH to spineMPs
    #===========================================================================
    stretchAmts = {}
    for eachMP in spineMPs:
        stretchAmts[eachMP] = 1.5

    ms.addVolume(spineCrvs[0], stretchAmts)

    #===========================================================================
    # SPACE SWITCHING
    #===========================================================================

    # space switching for hipCtl

    hipAlignTgt = mc.group(em=True, n='CT_hip_alignTarget')
    abRT.snapToPosition(hipCtl.crv, hipAlignTgt)
    cogOffsetLoc = rt.makeOffsetLoc(cogCtl, hipAlignTgt)
    masterOffsetLoc = rt.makeOffsetLoc(masterCtl, hipAlignTgt)
    rt.spaceSwitchSetup((cogOffsetLoc, masterOffsetLoc), hipAlignTgt,
                        hipCtl.crv, 'orientConstraint', ('COG', 'Master'))

    hipSpaceTgt = mc.group(em=True, n='CT_hip_spaceTarget')
    abRT.snapToPosition(hipCtl.crv, hipSpaceTgt)
    rt.spaceSwitchSetup((cogOffsetLoc, masterOffsetLoc), hipSpaceTgt,
                        hipCtl.crv, 'parentConstraint', ('COG', 'Master'))

    mc.pointConstraint(hipSpaceTgt, hipAlignTgt, mo=True)
    mc.parentConstraint(hipAlignTgt, hipCtl.grp['space'], mo=True)

    # space switching for headCtl

    headAlignTgt = mc.group(em=True, n='CT_head_alignTarget')
    abRT.snapToPosition(headCtl.crv, headAlignTgt)
    cogOffsetLoc = rt.makeOffsetLoc(cogCtl, headAlignTgt)
    masterOffsetLoc = rt.makeOffsetLoc(masterCtl, headAlignTgt)
    rt.spaceSwitchSetup((hipCtl.crv, cogOffsetLoc, masterOffsetLoc),
                        headAlignTgt, headCtl.crv, 'orientConstraint',
                        ('Hip', 'COG', 'Master'))

    headSpaceTgt = mc.group(em=True, n='CT_head_spaceTarget')
    abRT.snapToPosition(headCtl.crv, headSpaceTgt)
    rt.spaceSwitchSetup((hipCtl.crv, cogOffsetLoc, masterOffsetLoc),
                        headSpaceTgt, headCtl.crv, 'parentConstraint',
                        ('Hip', 'COG', 'Master'))

    mc.pointConstraint(headSpaceTgt, headAlignTgt, mo=True)
    mc.parentConstraint(headAlignTgt, headCtl.grp['space'], mo=True)

    # group space groups nicely
    spaceGrp = mc.group(hipAlignTgt,
                        hipSpaceTgt,
                        headAlignTgt,
                        headSpaceTgt,
                        n='CT_spaceSwitching_grp')

    # space for spineCtl
    mc.parentConstraint(midMP, spineCtl.space)

    #===========================================================================
    # DRIVE ORIGINAL MPS (to drive the rest of the upper body)
    #===========================================================================
    mc.parentConstraint(hipCtl.crv, hipMP)
    mc.parentConstraint(headCtl.crv, headMP)
Ejemplo n.º 11
0
def buildSpineRig(hipMP, headMP, cogCtl, masterCtl):
    '''
    Set up motion system for the spine rig
    
    Return: (spineDrvCrv, spineTwistCrv)
    '''
    
    #===========================================================================
    # CREATE CONTROLS
    #===========================================================================
    # hip
    hipCtl = cs.ctlCurve('CT_hip_ctl', 'cube', 1, colorId=22, snap=hipMP, ctlOffsets=['space'])
    mc.setAttr(hipCtl.crv + '.s', 0.3, 1, 1)
    mc.makeIdentity(hipCtl.crv, a=True, s=True)
    
    # spine-shaper
    spineCtl = cs.ctlCurve('CT_spine_ctl', 'circle', 0, colorId=22, size=18, ctlOffsets=['point', 'orient'])
    
    # head
    headCtl = cs.ctlCurve('CT_head_ctl', 'cube', 1, colorId=22, snap=headMP, ctlOffsets=['space'])
    mc.setAttr(headCtl.crv + '.s', 0.3, 1, 1)
    mc.makeIdentity(headCtl.crv, a=True, s=True)
    
    # group controls nicely
    ctrlGrp = mc.group(hipCtl.home, spineCtl.home, headCtl.home, n='CT_control_grp_0')
    
    #===========================================================================
    # CREATE DEBUG GRP - to toggle visibility of "under-the-hood" stuff
    #===========================================================================

    debugGrp = mc.group(em=True, n='CT_debug_grp')
    abRT.hideAttr(debugGrp, ['tx', 'ty', 'tz', 'sx', 'sy', 'sz', 'rx', 'ry', 'rz', 'v'])

    #===========================================================================
    # ADD TANGENT LOCS
    #===========================================================================

    hipTangentMP = ms.addTangentMPTo(hipCtl.crv, headCtl.crv, 'x', default=0.1, reverse=False)
    headTangentMP = ms.addTangentMPTo(headCtl.crv, hipCtl.crv, 'x', default=0.5, reverse=True)
    
    #===========================================================================
    # ADD MID POINT for spine-shaper control
    #===========================================================================
    midMP = ms.addMidMP(hipTangentMP, headTangentMP, hipCtl.crv, headCtl.crv, (1,0,0), (0,1,0), 'CT_spineMid_mPt')
    spineCrvs, spineMPs = ms.createSplineMPs((hipCtl.crv, hipTangentMP, spineCtl.crv, headTangentMP, headCtl.crv), 12, 'CT_spine', (0,5,0))
    
    #===========================================================================
    # add SQUASH AND STRETCH to spineMPs
    #===========================================================================
    stretchAmts = {}
    for eachMP in spineMPs:
        stretchAmts[eachMP] = 1.5
        
    ms.addVolume(spineCrvs[0], stretchAmts)
    
    #===========================================================================
    # SPACE SWITCHING
    #===========================================================================
    
    # space switching for hipCtl

    hipAlignTgt = mc.group(em=True, n='CT_hip_alignTarget')
    abRT.snapToPosition(hipCtl.crv, hipAlignTgt)
    cogOffsetLoc = rt.makeOffsetLoc(cogCtl, hipAlignTgt)
    masterOffsetLoc = rt.makeOffsetLoc(masterCtl, hipAlignTgt)
    rt.spaceSwitchSetup((cogOffsetLoc, masterOffsetLoc), hipAlignTgt, hipCtl.crv, 'orientConstraint', ('COG', 'Master'))
    
    hipSpaceTgt = mc.group(em=True, n='CT_hip_spaceTarget')
    abRT.snapToPosition(hipCtl.crv, hipSpaceTgt)
    rt.spaceSwitchSetup((cogOffsetLoc, masterOffsetLoc), hipSpaceTgt, hipCtl.crv, 'parentConstraint', ('COG', 'Master'))
    
    mc.pointConstraint(hipSpaceTgt, hipAlignTgt, mo=True)
    mc.parentConstraint(hipAlignTgt, hipCtl.grp['space'], mo=True)
    
    # space switching for headCtl
    
    headAlignTgt = mc.group(em=True, n='CT_head_alignTarget')
    abRT.snapToPosition(headCtl.crv, headAlignTgt)
    cogOffsetLoc = rt.makeOffsetLoc(cogCtl, headAlignTgt)
    masterOffsetLoc = rt.makeOffsetLoc(masterCtl, headAlignTgt)
    rt.spaceSwitchSetup((hipCtl.crv, cogOffsetLoc, masterOffsetLoc), headAlignTgt, headCtl.crv, 'orientConstraint', ('Hip', 'COG', 'Master'))
    
    headSpaceTgt = mc.group(em=True, n='CT_head_spaceTarget')
    abRT.snapToPosition(headCtl.crv, headSpaceTgt)
    rt.spaceSwitchSetup((hipCtl.crv, cogOffsetLoc, masterOffsetLoc), headSpaceTgt, headCtl.crv, 'parentConstraint', ('Hip', 'COG', 'Master'))
    
    mc.pointConstraint(headSpaceTgt, headAlignTgt, mo=True)
    mc.parentConstraint(headAlignTgt, headCtl.grp['space'], mo=True)

    # group space groups nicely
    spaceGrp = mc.group(hipAlignTgt, hipSpaceTgt, headAlignTgt, headSpaceTgt, n='CT_spaceSwitching_grp')
    
    # space for spineCtl
    mc.parentConstraint(midMP, spineCtl.space)
    
    #===========================================================================
    # DRIVE ORIGINAL MPS (to drive the rest of the upper body)
    #===========================================================================
    mc.parentConstraint(hipCtl.crv, hipMP)
    mc.parentConstraint(headCtl.crv, headMP)