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)
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')
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
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
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
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
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)
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')
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
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)
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)