Beispiel #1
0
def getCurveStretch(crv, name):
    '''
    connects crv to a curveInfo node and divides it's default length by the arcLength from it.
    :param crv: curve to measure
    :return: {'crvInfo':newCurveInfoNode, 'stretchFactor':newMultiplyDivideNode}
    '''

    curveInfo = pmc.createNode('curveInfo', name='%s_crvLength_utl' % name)
    crv.worldSpace[0].connect(curveInfo.inputCurve)
    globalScaleFactor = coreUtils.multiply(1.0, curveInfo.arcLength.get(), name='%s_crvLengthGlobalScale_utl' % name)
    stretchFactor = coreUtils.divide(globalScaleFactor.outputX, curveInfo.arcLength, '%s_crvStretchFactor_utl' % name)

    return {'crvInfo': curveInfo, 'stretchFactor': stretchFactor, 'globalScaleFactor':globalScaleFactor}
Beispiel #2
0
    def build(self, joints, alignIkToJointsUpAxis):

        # duplicate joints
        self.resultJoints = coreUtils.duplicateJoints(joints,
                                                      name='%s_result_XX_jnt' %
                                                      self.name)
        self.fkJoints = coreUtils.duplicateJoints(joints,
                                                  name='%s_fk_XX_jnt' %
                                                  self.name)
        self.ikJoints = coreUtils.duplicateJoints(joints,
                                                  name='%s_ik_XX_jnt' %
                                                  self.name)
        self.jointBufferGrp = coreUtils.addChild(
            self.rigGrp, 'group', '%s_jointsBuffer_srt' % self.name)
        coreUtils.align(self.jointBufferGrp, self.resultJoints[0])
        self.resultJoints[0].setParent(self.jointBufferGrp)
        self.fkJoints[0].setParent(self.jointBufferGrp)
        self.ikJoints[0].setParent(self.jointBufferGrp)

        ctrlSize = coreUtils.getDistance(self.resultJoints[0],
                                         self.resultJoints[1]) * .25

        # Orientation for controls and aim constraints
        axis = 'x'
        aimVec = (1, 0, 0)
        if self.resultJoints[1].tx.get() < 0.0:
            axis = '-x'
            aimVec = (-1, 0, 0)

        self.settingsCtrl = controls.squareChamferCtrl(
            name='%s_settings_ctrl' % self.name, size=ctrlSize * .33)
        self.settingsCtrl.setParent(self.interfaceGrp)
        pmc.addAttr(self.settingsCtrl,
                    ln='ik_fk_blend',
                    at='double',
                    k=1,
                    h=0,
                    maxValue=1.0,
                    minValue=0.0)
        settingsBuffer = coreUtils.addParent(
            self.settingsCtrl, 'group', '%s_settings_buffer_srt' % self.name)
        settingsOffset = ctrlSize * 2
        if axis == '-x':
            settingsOffset *= -1
        self.settingsCtrl.ty.set(settingsOffset)
        endSrt = coreUtils.decomposeMatrix(self.resultJoints[2].worldMatrix[0],
                                           name='%s_endWorldMtxToSrt_utl' %
                                           self.name)
        endSrt.outputTranslate.connect(settingsBuffer.t)
        endSrt.outputRotate.connect(settingsBuffer.r)
        endSrt.outputScale.connect(settingsBuffer.s)
        self.ctrls.append(self.settingsCtrl)

        # Create a dummy input to connect parts of the limb to
        self.baseInput = coreUtils.addChild(self.inputGrp,
                                            'group',
                                            name='%s_base_in_srt' % self.name)
        coreUtils.align(self.baseInput, joints[0])
        baseMtx = coreUtils.isDecomposed(self.baseInput)

        # set up blending
        for rj, ij, fj in zip(self.resultJoints, self.ikJoints, self.fkJoints):
            coreUtils.ikFkBlend(ij,
                                fj,
                                rj,
                                blendAttr='%s.ik_fk_blend' % self.settingsCtrl)

        # fk controls
        self.fkCtrlsGrp = coreUtils.addChild(self.interfaceGrp, 'group',
                                             '%s_self.fkCtrls_hrc' % self.name)
        self.settingsCtrl.ik_fk_blend.connect(self.fkCtrlsGrp.visibility)
        buffer = None
        self.fkCtrls = []
        for i in range(len(self.fkJoints) - 1):
            fj = self.fkJoints[i]
            num = str(i + 1).zfill(2)
            c = controls.circleBumpCtrl(name='%s_fk_%s_ctrl' %
                                        (self.name, num),
                                        axis=axis,
                                        radius=ctrlSize)
            coreUtils.align(c, fj)
            buffer = coreUtils.addParent(
                c, 'group', '%s_fk%s_buffer_srt' % (self.name, num))
            if i == 0:
                buffer.setParent(self.fkCtrlsGrp)
                coreUtils.connectAttrs(c, fj, ['t', 'r', 's'])
            else:
                buffer.setParent(self.fkCtrls[-1])
                m = coreUtils.decomposeLocalMatrix(c, depth=1)
                m.outputTranslate.connect(fj.t)
                m.outputScale.connect(fj.s)
                c.rotate.connect(fj.r)
            self.fkCtrls.append(c)
            self.ctrls.append(c)

        # rotate order
        for node in [
                self.fkCtrls[1], self.fkJoints[1], self.ikJoints[1],
                self.resultJoints[1]
        ]:
            node.rotateOrder.set(3)

        # ik controls
        self.ikCtrl = controls.boxCtrl(name='%s_ik_ctrl' % self.name,
                                       size=ctrlSize)
        if alignIkToJointsUpAxis:
            aimAxis = 'x'
            if pmc.xform(joints[2], q=1, t=1, ws=1) > pmc.xform(
                    joints[3], q=1, t=1, ws=1):
                aimAxis = '-x'
            elif pmc.xform(joints[2], q=1, t=1, ws=1) < pmc.xform(
                    joints[3], q=1, t=1, ws=1):
                aimAxis = 'x'
            pmc.xform(self.ikCtrl,
                      ws=1,
                      m=coreUtils.getAimMatrix(
                          start=self.resultJoints[2],
                          end=self.resultJoints[3],
                          axis=aimAxis,
                          upAxis='y',
                          worldUpAxis=alignIkToJointsUpAxis,
                          upNode=self.resultJoints[2]))
        else:
            coreUtils.align(self.ikCtrl, self.ikJoints[2], orient=0)
        self.ikCtrlsGrp = coreUtils.addChild(self.interfaceGrp, 'group',
                                             '%s_ikCtrls_hrc' % self.name)
        self.ikCtrl.setParent(self.ikCtrlsGrp)
        ikBuffer = coreUtils.addParent(self.ikCtrl, 'group',
                                       '%s_ik_buffer_srt' % self.name)
        ikFkRev = coreUtils.reverse(self.settingsCtrl.ik_fk_blend,
                                    '%s_ikFkBlendReverse_UTL' % self.name)
        ikFkRev.outputX.connect(self.ikCtrlsGrp.visibility)
        self.ctrls.append(self.ikCtrl)

        pmc.addAttr(self.ikCtrl,
                    longName='stretch',
                    at='double',
                    minValue=0,
                    maxValue=1,
                    defaultValue=0,
                    keyable=True)
        pmc.addAttr(self.ikCtrl, longName='twist', at='double', keyable=True)
        pmc.addAttr(self.ikCtrl,
                    longName='soft',
                    at='double',
                    minValue=0,
                    defaultValue=0,
                    keyable=True)
        pmc.addAttr(self.ikCtrl,
                    longName='mid_pin',
                    at='double',
                    keyable=True,
                    minValue=0,
                    maxValue=1)
        pmc.addAttr(self.ikCtrl,
                    longName='force_straight',
                    at='double',
                    keyable=True,
                    h=0,
                    minValue=0.0,
                    maxValue=1.0)

        # Soft non-stretchy IK stuff
        ik_grp = coreUtils.addChild(self.rigGrp,
                                    'group',
                                    name='%s_ik_hrc' % self.name)
        self.ikBufferGrp = coreUtils.addChild(ik_grp,
                                              'group',
                                              name='%s_ik_srt' % self.name)
        coreUtils.align(self.ikBufferGrp, self.jointBufferGrp)

        self.softBlend_loc = coreUtils.createAlignedNode(
            self.ikCtrl, 'locator', name='%s_ik_softBlend_loc' % self.name)
        self.softBlend_loc.setParent(ik_grp)

        self.ctrl_loc = coreUtils.createAlignedNode(self.ikCtrl,
                                                    'locator',
                                                    name='%s_ikCtrl_loc' %
                                                    self.name)
        self.ctrl_loc.setParent(ik_grp)
        pmc.parentConstraint(self.ikCtrl, self.ctrl_loc)

        aim_loc = coreUtils.addChild(self.ikBufferGrp,
                                     'locator',
                                     name='%s_softIkaim_loc' % self.name)
        pmc.aimConstraint(self.ctrl_loc, aim_loc, upVector=(0, 0, 0))

        btm_loc = coreUtils.createAlignedNode(self.ikCtrl,
                                              'locator',
                                              name='%s_ikBtm_loc' % self.name)
        btm_loc.setParent(aim_loc)

        chainLen = abs(self.ikJoints[1].tx.get() + self.ikJoints[2].tx.get())

        ctrlDist = coreUtils.distanceBetweenNodes(aim_loc,
                                                  self.ctrl_loc,
                                                  name='%s_ikCtrl_utl' %
                                                  self.name)
        globalScaleDiv = coreUtils.divide(1.0,
                                          baseMtx.outputScaleX,
                                          name='%s_globalScaleDiv_utl' %
                                          self.name)
        isStretchedMult = coreUtils.multiply(ctrlDist.distance,
                                             globalScaleDiv.outputX,
                                             name='%s_isStretched_utl' %
                                             self.name)

        softDist = coreUtils.distanceBetweenNodes(btm_loc,
                                                  self.softBlend_loc,
                                                  name='%s_soft_utl' %
                                                  self.name)
        stretchDist = coreUtils.distanceBetweenNodes(aim_loc,
                                                     self.softBlend_loc,
                                                     name='%s_stretch_utl' %
                                                     self.name)

        chainLenMinusSoft = coreUtils.minus([chainLen, self.ikCtrl.soft],
                                            name='%s_chainLenMinusSoft_utl' %
                                            self.name)

        isStretchedCond = pmc.createNode('condition',
                                         name='%s_isStretched_utl' % self.name)
        isStretchedCond.operation.set(2)
        isStretchedMult.outputX.connect(isStretchedCond.firstTerm)
        chainLenMinusSoft.output1D.connect(isStretchedCond.secondTerm)
        isStretchedMult.outputX.connect(isStretchedCond.colorIfFalseR)

        isSoftCond = pmc.createNode('condition',
                                    name='%s_isSoft_utl' % self.name)
        isSoftCond.operation.set(2)
        self.ikCtrl.soft.connect(isSoftCond.firstTerm)
        isSoftCond.colorIfFalseR.set(chainLen)

        ctrlDistMinusSoftChain = coreUtils.minus(
            [isStretchedMult.outputX, chainLenMinusSoft.output1D],
            name='%s_ctrlDistMinusSoftChain_utl' % self.name)

        divideBySoft = coreUtils.safeDivide(ctrlDistMinusSoftChain.output1D,
                                            self.ikCtrl.soft,
                                            name='%s_divideBySoft_utl' %
                                            self.name)

        invert = coreUtils.multiply(divideBySoft.outputX,
                                    -1,
                                    name='%s_invertSoft_utl' % self.name)

        exp = coreUtils.power(2.718282,
                              invert.outputX,
                              name='%s_exponential_utl' % self.name)

        multiplyBySoft = coreUtils.multiply(exp.outputX,
                                            self.ikCtrl.soft,
                                            name='%s_multiplyBySoft_utl' %
                                            self.name)

        minusFromChainLen = coreUtils.minus([chainLen, multiplyBySoft.outputX],
                                            name='%s_minusFromChainLen_utl' %
                                            self.name)

        minusFromChainLen.output1D.connect(isSoftCond.colorIfTrueR)

        isSoftCond.outColorR.connect(isStretchedCond.colorIfTrueR)

        isStretchedCond.outColorR.connect(btm_loc.tx)

        # IK Solvers
        ikHandleGrp = coreUtils.createAlignedNode(self.ikCtrl,
                                                  'group',
                                                  name='%s_ikHandle_srt' %
                                                  self.name)
        ikHandleGrp.setParent(self.softBlend_loc)
        pmc.orientConstraint(self.ikCtrl, ikHandleGrp, mo=1)

        ikHandle = pmc.ikHandle(solver='ikRPsolver',
                                name='%s_ikHandle' % self.name,
                                startJoint=self.ikJoints[0],
                                endEffector=self.ikJoints[2],
                                setupForRPsolver=1)[0]
        ikHandle.setParent(ikHandleGrp)
        self.ikCtrl.twist.connect(ikHandle.twist)

        endIkHandle = pmc.ikHandle(solver='ikSCsolver',
                                   name='%s_end_ikHandle' % self.name,
                                   startJoint=self.ikJoints[2],
                                   endEffector=self.ikJoints[3],
                                   setupForRPsolver=1)[0]
        endIkHandle.setParent(ikHandleGrp)

        # Pole Vector
        pvAimGrp = coreUtils.addChild(self.ikBufferGrp,
                                      'group',
                                      name='%s_pvAim_srt' % self.name)
        pmc.aimConstraint(btm_loc,
                          pvAimGrp,
                          mo=0,
                          u=(0, 0, 0),
                          aimVector=aimVec)
        self.pvCtrl = controls.crossCtrl(name='%s_pv_ctrl' % self.name,
                                         size=ctrlSize)
        poleOffset = 3
        if '-' in axis:
            poleOffset = -3
        self.pvCtrl.setParent(self.ikJoints[1])
        self.pvCtrl.t.set((0, 0, ctrlSize * poleOffset))
        self.pvCtrl.setParent(self.ikCtrlsGrp)
        self.pvBufferGrp = coreUtils.addParent(self.pvCtrl, 'group',
                                               '%s_pv_buffer_srt' % self.name)
        pmc.poleVectorConstraint(self.pvCtrl, ikHandle)
        self.ctrls.append(self.pvCtrl)

        # stretchy soft IK stuff

        pc = pmc.pointConstraint(btm_loc, self.ctrl_loc, self.softBlend_loc)
        stretchRev = coreUtils.reverse(self.ikCtrl.stretch,
                                       name='%s_stretchReverse_utl' %
                                       self.name)
        stretchRev.outputX.connect('%s.%sW0' %
                                   (pc.nodeName(), btm_loc.nodeName()))
        self.ikCtrl.stretch.connect('%s.%sW1' %
                                    (pc.nodeName(), self.ctrl_loc.nodeName()))

        scaledSoftDist = coreUtils.multiply(globalScaleDiv.outputX,
                                            softDist.distance,
                                            name='%s_scaledSoftDist_utl' %
                                            self.name)

        # Stretchy Mid
        midLen = coreUtils.multiply((self.ikJoints[1].tx.get() / chainLen),
                                    scaledSoftDist.outputX,
                                    name='%s_midLen_utl' % self.name)

        stretchMidLen = coreUtils.multiply(self.ikCtrl.stretch,
                                           midLen.outputX,
                                           name='%s_stretchMidLen_utl' %
                                           self.name)

        stretchMidLenPlusBoneLen = coreUtils.add(
            [self.ikJoints[1].tx.get(), stretchMidLen.outputX],
            name='%s_stretchMidLenPlusBoneLen_utl' % self.name)

        pinUpperDist = coreUtils.distanceBetweenNodes(self.ikBufferGrp,
                                                      self.pvCtrl,
                                                      name='%s_pinUpper_utl' %
                                                      self.name)
        pinMult = 1.0
        if '-' in axis:
            pinMult = -1.0
        pinUpper_uc = coreUtils.convert(pinUpperDist.distance,
                                        pinMult,
                                        name='%s_pinUpperDist_utk' % self.name)
        pinUpperGlobalScale = coreUtils.multiply(
            globalScaleDiv.outputX,
            pinUpper_uc.output,
            name='%s_pinUpperGlobalScale_utl' % self.name)
        pinUpperBlend = coreUtils.blend(
            input1=pinUpperGlobalScale.outputX,
            input2=stretchMidLenPlusBoneLen.output1D,
            blendAttr=self.ikCtrl.mid_pin,
            name='%s_pinUpper_utl' % self.name)

        # Stretchy Bot
        botLen = coreUtils.multiply((self.ikJoints[2].tx.get() / chainLen),
                                    scaledSoftDist.outputX,
                                    name='%s_botLen_utl' % self.name)

        stretchBotLen = coreUtils.multiply(self.ikCtrl.stretch,
                                           botLen.outputX,
                                           name='%s_stretchBotLen_utl' %
                                           self.name)

        stretchBotLenPlusBoneLen = coreUtils.add(
            [self.ikJoints[2].tx.get(), stretchBotLen.outputX],
            name='%s_stretchBotLenPlusBoneLen_utl' % self.name)

        pinLowerDist = coreUtils.distanceBetweenNodes(self.softBlend_loc,
                                                      self.pvCtrl,
                                                      name='%s_pinLower_utl' %
                                                      self.name)
        pinLower_uc = coreUtils.convert(pinLowerDist.distance,
                                        pinMult,
                                        name='%s_pinLowerDist_utl' % self.name)
        pinLowerGlobalScale = coreUtils.multiply(
            globalScaleDiv.outputX,
            pinLower_uc.output,
            name='%s_pinLowerGlobalScale_utl' % self.name)
        pinLowerBlend = coreUtils.blend(
            input1=pinLowerGlobalScale.outputX,
            input2=stretchBotLenPlusBoneLen.output1D,
            blendAttr=self.ikCtrl.mid_pin,
            name='%s_pinLower_utl' % self.name)

        # Add ability to force straight arm
        straightUpper_md = coreUtils.multiply(
            stretchDist.distance,
            self.ikJoints[1].tx.get() / chainLen,
            name='%s_midLenTimesChainLen_utl' % self.name)
        straightLower_md = coreUtils.multiply(
            stretchDist.distance,
            self.ikJoints[2].tx.get() / chainLen,
            name='%s_botLenTimesChainLen_utl' % self.name)
        straightUpperBlend = coreUtils.blend(
            input1=straightUpper_md.outputX,
            input2=pinUpperBlend.outputR,
            blendAttr=self.ikCtrl.force_straight,
            name='%s_straightUpper_utl' % self.name)
        straightLowerBlend = coreUtils.blend(
            input1=straightLower_md.outputX,
            input2=pinLowerBlend.outputR,
            blendAttr=self.ikCtrl.force_straight,
            name='%s_straightLower_utl' % self.name)
        straightUpperBlend.outputR.connect(self.ikJoints[1].tx)
        straightLowerBlend.outputR.connect(self.ikJoints[2].tx)

        # connect to base input
        d = coreUtils.isDecomposed(self.baseInput)
        coreUtils.connectDecomposedMatrix(d, self.jointBufferGrp)
        coreUtils.connectDecomposedMatrix(d, self.ikBufferGrp)

        # Add basic space switching to ik ctrl, pole vector and top fk ctrl - additional spaces can be added at any point
        pvTargets = componentUtils.addSpaceSwitch(self.pvBufferGrp,
                                                  'pv', ['limb'],
                                                  type='parent',
                                                  ctrlNode=self.pvCtrl,
                                                  targetNodes=[pvAimGrp])
        ikTargets = componentUtils.addSpaceSwitch(ikBuffer,
                                                  'ik', ['limb'],
                                                  type='parent',
                                                  ctrlNode=self.ikCtrl,
                                                  targetNodes=[self.baseInput])
        fkTargets = componentUtils.addSpaceSwitch(self.fkCtrls[0].getParent(),
                                                  'fk', ['limb'],
                                                  type='rotate',
                                                  ctrlNode=self.fkCtrls[0],
                                                  targetNodes=[self.baseInput])
        d.outputTranslate.connect(self.fkCtrls[0].getParent().t)
        d.outputScale.connect(self.fkCtrls[0].getParent().s)
Beispiel #3
0
    def build(self, joints, numJoints, axis, upAxis, worldUpAxis, reverse,
              ctrlInterval):

        # Create curves
        positions = [pmc.xform(joint, q=1, ws=1, t=1) for joint in joints]
        self.fkCrv = curveUtils.curveThroughPoints(positions=positions,
                                                   name='%s_fkCrv' % self.name)
        self.fkCrv.setParent(self.rigGrp)

        self.ikCrv = curveUtils.curveThroughPoints(positions=positions,
                                                   name='%s_ikCrv' % self.name)
        self.ikCrv.setParent(self.rigGrp)

        # controls
        ctrlSize = coreUtils.getDistance(joints[0], joints[-1]) * .5

        #base
        self.baseCtrl = controls.hexCtrl(name='%s_base_ctrl' % self.name,
                                         axis=axis,
                                         radius=ctrlSize)
        self.baseCtrl.setParent(self.interfaceGrp)
        coreUtils.align(self.baseCtrl, joints[0])
        baseBuffer = coreUtils.addParent(self.baseCtrl,
                                         'group',
                                         name='%s_base_buffer_srt' % self.name)
        self.ctrls.append(self.baseCtrl)

        self.baseSubCtrl = controls.hexCtrl(name='%s_baseSub_ctrl' % self.name,
                                            axis=axis,
                                            radius=ctrlSize * .8)
        self.baseSubCtrl.setParent(self.baseCtrl)
        coreUtils.align(self.baseSubCtrl, joints[0])
        self.ctrls.append(self.baseSubCtrl)

        baseMtx = coreUtils.isDecomposed(self.baseSubCtrl)
        # Create offset srt so that spine can be offset from body controls
        baseSrt = coreUtils.addChild(self.rigGrp, 'group',
                                     '%s_base_srt' % self.name)
        offsetSrt = coreUtils.addChild(baseSrt, 'group',
                                       '%s_offset_srt' % self.name)
        coreUtils.connectDecomposedMatrix(baseMtx, baseSrt)
        offsetMtx = coreUtils.isDecomposed(offsetSrt)

        # settings
        self.settingsCtrl = controls.squareChamferCtrl(
            size=ctrlSize * .2, axis=axis, name='%s_settings_ctrl' % self.name)
        self.settingsCtrl.setParent(self.baseSubCtrl)
        b = coreUtils.addParent(self.settingsCtrl,
                                'group',
                                name='%s_settings_buffer_srt' % self.name)
        coreUtils.align(b, self.baseSubCtrl)
        pmc.setAttr('%s.t%s' % (b.name(), upAxis), ctrlSize * -1.5)
        self.ctrls.append(self.settingsCtrl)

        #FK
        self.fkCtrls = []
        fkOffsetSrt = coreUtils.addChild(self.baseSubCtrl, 'group',
                                         '%s_fkOffset_srt' % self.name)
        coreUtils.connectAttrs(offsetSrt, fkOffsetSrt, ['t', 'r', 's'])
        for i in range(len(joints) - 1):
            num = str(i + 1).zfill(2)
            ctrlNum = str((i / ctrlInterval) + 1).zfill(2)
            c = None
            if i % ctrlInterval == 0:
                c = controls.hexCtrl(name='%s_fk_%s_ctrl' %
                                     (self.name, ctrlNum),
                                     axis=axis,
                                     radius=ctrlSize * .5)
                self.ctrls.append(c)
            else:
                c = coreUtils.pmc.group(empty=1,
                                        name='%s_fk_%s_srt' % (self.name, num))
                self.ctrls[-1].t.connect(c.t)
                self.ctrls[-1].r.connect(c.r)
                self.ctrls[-1].s.connect(c.s)
            b = coreUtils.addParent(c,
                                    'group',
                                    name='%s_fk%s_buffer_srt' %
                                    (self.name, num))
            coreUtils.align(b, joints[i])
            if i == 0:
                b.setParent(fkOffsetSrt)
            else:
                b.setParent(self.fkCtrls[-1])
            self.fkCtrls.append(c)
        # reverse fk
        self.fkRevCtrls = []
        if reverse:
            for i in range(len(joints) - 1):
                num = str(i + 1).zfill(2)
                ctrlNum = str((i / ctrlInterval) + 1).zfill(2)
                c = None
                if i % ctrlInterval == 0:
                    c = controls.hexCtrl(name='%s_fkReverse_%s_ctrl' %
                                         (self.name, ctrlNum),
                                         axis=axis,
                                         radius=ctrlSize * .4)
                    self.ctrls.append(c)
                else:
                    c = coreUtils.pmc.group(empty=1,
                                            name='%s_fkReverse_%s_srt' %
                                            (self.name, num))
                    self.ctrls[-1].t.connect(c.t)
                    self.ctrls[-1].r.connect(c.r)
                    self.ctrls[-1].s.connect(c.s)
                b = coreUtils.addParent(c,
                                        'group',
                                        name='%s_fkReverse%s_buffer_srt' %
                                        (self.name, num))
                coreUtils.align(b, joints[len(joints) - i - 1])
                if i == 0:
                    b.setParent(self.fkCtrls[-1])
                else:
                    b.setParent(self.interfaceGrp)
                self.fkRevCtrls.append(c)

            srtList = []
            for i in range(len(self.fkRevCtrls)):
                num = str(i + 1).zfill(2)
                fkCtrl = self.fkCtrls[len(self.fkCtrls) - i - 1]
                revCtrl = self.fkRevCtrls[i]
                multMtx = None
                if i == 0:
                    multMtx = coreUtils.multiplyMatrices(
                        [
                            fkCtrl.worldMatrix[0],
                            revCtrl.parentInverseMatrix[0],
                            revCtrl.worldMatrix[0]
                        ],
                        name='%s_localFkReverseMtx%s_utl' % (self.name, num))
                    d = coreUtils.decomposeMatrix(
                        revCtrl.worldMatrix[0],
                        name='%s_localFkReverseMtx01ToSrt_utl' % self.name)
                    revCtrl.rotateOrder.connect(d.inputRotateOrder)
                    d.outputTranslate.connect(
                        self.fkCrv.controlPoints[len(joints) - 1])
                    d.outputTranslate.connect(
                        self.ikCrv.controlPoints[len(joints) - 1])
                    srtList.append(d)
                elif i == len(self.fkRevCtrls) - 1:
                    multMtx = coreUtils.multiplyMatrices(
                        [
                            offsetSrt.worldMatrix[0],
                            self.fkCtrls[len(self.fkCtrls) -
                                         i].worldInverseMatrix[0],
                            revCtrl.worldMatrix[0]
                        ],
                        name='%s_localFkReverseMtx%s_utl' % (self.name, num))
                else:
                    multMtx = coreUtils.multiplyMatrices(
                        [
                            fkCtrl.worldMatrix[0],
                            self.fkCtrls[len(self.fkCtrls) -
                                         i].worldInverseMatrix[0],
                            revCtrl.worldMatrix[0]
                        ],
                        name='%s_localFkReverseMtx%s_utl' % (self.name, num))
                d = coreUtils.decomposeMatrix(
                    multMtx.matrixSum,
                    name='%s_localFkReverseMtx%sToSrt_utl' % (self.name, num))
                self.baseCtrl.rotateOrder.connect(d.inputRotateOrder)
                if i < len(self.fkRevCtrls) - 1:
                    d.outputTranslate.connect(self.fkRevCtrls[i +
                                                              1].getParent().t)
                    d.outputRotate.connect(self.fkRevCtrls[i +
                                                           1].getParent().r)
                    d.outputScale.connect(self.fkRevCtrls[i + 1].getParent().s)
                d.outputTranslate.connect(
                    self.fkCrv.controlPoints[len(self.fkRevCtrls) - (i + 1)])
                d.outputTranslate.connect(
                    self.ikCrv.controlPoints[len(self.fkRevCtrls) - (i + 1)])
                srtList.append(d)
        else:
            srtList = []
            for i in range(len(self.fkCtrls)):
                num = str(i + 1).zfill(2)
                ctrl = self.fkCtrls[i]
                d = coreUtils.decomposeMatrix(ctrl.worldMatrix[0],
                                              name='%s_localFkMtx%sToSrt_utl' %
                                              (self.name, num))
                ctrl.rotateOrder.connect(d.inputRotateOrder)
                d.outputTranslate.connect(self.fkCrv.controlPoints[i])
                d.outputTranslate.connect(self.ikCrv.controlPoints[i])
                srtList.append(d)

        #IK
        # hip
        self.startCtrl = controls.squareCtrl(name='%s_start_ctrl' % self.name,
                                             axis=axis,
                                             size=ctrlSize)
        coreUtils.align(self.startCtrl, self.baseCtrl)
        startBuffer = coreUtils.addParent(self.startCtrl,
                                          'group',
                                          name='%s_start_buffer_srt' %
                                          self.name)
        if reverse:
            startBuffer.setParent(self.interfaceGrp)
            self.ctrls.append(self.startCtrl)
            srtList[-1].outputTranslate.connect(startBuffer.t)
            srtList[-1].outputRotate.connect(startBuffer.r)
            srtList[-1].outputScale.connect(startBuffer.s)
        else:
            startBuffer.setParent(self.baseSubCtrl)

        # end
        self.endCtrl = controls.squareCtrl(name='%s_end_ctrl' % self.name,
                                           axis=axis,
                                           size=ctrlSize)
        coreUtils.align(self.endCtrl, joints[-1])
        endBuffer = coreUtils.addParent(self.endCtrl,
                                        'group',
                                        name='%s_end_buffer_srt' % self.name)
        if reverse:
            endBuffer.setParent(self.interfaceGrp)
            self.ctrls.append(self.endCtrl)
            srtList[0].outputTranslate.connect(endBuffer.t)
            srtList[0].outputRotate.connect(endBuffer.r)
            srtList[0].outputScale.connect(endBuffer.s)
        else:
            endBuffer.setParent(self.fkCtrls[-1])
            d = coreUtils.decomposeMatrix(endBuffer.worldMatrix[0],
                                          name='%s_endMtxToSrt_utl' %
                                          self.name)
            self.endCtrl.rotateOrder.connect(d.inputRotateOrder)
            d.outputTranslate.connect(self.fkCrv.controlPoints[len(joints) -
                                                               1],
                                      f=1)
            d.outputTranslate.connect(self.ikCrv.controlPoints[len(joints) -
                                                               1],
                                      f=1)
            srtList.append(d)

        # rotate orders for ctrls
        rotateOrderDict = {'x': 0, 'y': 2, 'z': 1}
        for ctrl in self.ctrls:
            ctrl.rotateOrder.set(rotateOrderDict[axis])

        # crvInfo
        crvInfo = pmc.createNode('curveInfo',
                                 name='%s_ikCrvInfo_utl' % self.name)
        crvShape = coreUtils.getShape(self.fkCrv)
        crvShape.worldSpace[0].connect(crvInfo.inputCurve)

        # stretch
        pmc.addAttr(self.mainGrp, longName='stretch', at='double', k=0, h=1)
        restLenMD = coreUtils.multiply(crvInfo.arcLength.get(),
                                       baseMtx.outputScaleX,
                                       name='%s_restLength_utl' % self.name)
        stretchMD = coreUtils.divide(restLenMD.outputX,
                                     crvInfo.arcLength,
                                     name='%s_stretchFactor_utl' % self.name)
        stretchMD.outputX.connect(self.mainGrp.stretch)

        # ik curve skinning
        endGuideJoint = coreUtils.addChild(self.rigGrp, 'joint',
                                           '%s_endGuide_jnt' % self.name)
        endJointBuffer = coreUtils.addParent(endGuideJoint,
                                             'group',
                                             name='%s_endJnt_buffer_srt' %
                                             self.name)
        endJoint = coreUtils.addChild(endJointBuffer, 'joint',
                                      '%s_end_jnt' % self.name)
        srt = srtList[-1]
        if reverse:
            srt = srtList[0]
        srt.outputTranslate.connect(endJointBuffer.t)
        srt.outputRotate.connect(endJointBuffer.r)
        srt.outputScale.connect(endJointBuffer.s)
        self.endCtrl.t.connect(endGuideJoint.t)
        self.endCtrl.r.connect(endGuideJoint.r)
        self.endCtrl.t.connect(endJoint.t)
        self.endCtrl.r.connect(endJoint.r)

        startGuideJoint = coreUtils.addChild(self.rigGrp, 'joint',
                                             '%s_startGuide_jnt' % self.name)
        startJointBuffer = coreUtils.addParent(startGuideJoint,
                                               'group',
                                               name='%s_startJnt_buffer_srt' %
                                               self.name)
        startJoint = coreUtils.addChild(startJointBuffer, 'joint',
                                        '%s_start_jnt' % self.name)
        srt = srtList[-1]
        if not reverse:
            srt = srtList[0]
        srt.outputTranslate.connect(startJointBuffer.t)
        srt.outputRotate.connect(startJointBuffer.r)
        srt.outputScale.connect(startJointBuffer.s)
        self.startCtrl.t.connect(startGuideJoint.t)
        self.startCtrl.r.connect(startGuideJoint.r)
        self.startCtrl.t.connect(startJoint.t)
        self.startCtrl.r.connect(startJoint.r)

        jointScaleMD = coreUtils.divide(1.0,
                                        self.mainGrp.stretch,
                                        name='%s_ikJointScale_utl' % self.name)

        coreUtils.connectAttrToMany(jointScaleMD.outputX, [
            startJoint.sx, startJoint.sy, startJoint.sz, endJoint.sx,
            endJoint.sy, endJoint.sz
        ])

        guideSkin = pmc.skinCluster(endGuideJoint,
                                    startGuideJoint,
                                    self.fkCrv,
                                    dr=1)
        endJointBuffer.worldInverseMatrix[0].connect(
            guideSkin.bindPreMatrix[0])
        startJointBuffer.worldInverseMatrix[0].connect(
            guideSkin.bindPreMatrix[1])

        skin = pmc.skinCluster(endJoint, startJoint, self.ikCrv, dr=2)
        endJointBuffer.worldInverseMatrix[0].connect(skin.bindPreMatrix[0])
        startJointBuffer.worldInverseMatrix[0].connect(skin.bindPreMatrix[1])

        # create attribute on settings control to choose upAxis and avoid flipping
        enumString = ''
        axes = ['x', 'y', 'z']
        for a in axes:
            if a != axis:
                enumString += (a + ':')
        pmc.addAttr(self.settingsCtrl,
                    ln='upAxis',
                    at='enum',
                    enumName=enumString,
                    k=1,
                    h=0)
        upVecCond = pmc.createNode('condition',
                                   name='%s_upVec_utl' % self.name)
        self.settingsCtrl.upAxis.connect(upVecCond.firstTerm)
        if axis == 'x':
            upVecCond.colorIfTrue.set((0, 1, 0))
        else:
            upVecCond.colorIfTrue.set((1, 0, 0))
        if axis == 'y':
            upVecCond.colorIfFalse.set((0, 0, 1))
        else:
            upVecCond.colorIfFalse.set((0, 1, 0))

        upAxisCond = pmc.createNode('condition',
                                    name='%s_upAxis_utl' % self.name)
        self.settingsCtrl.upAxis.connect(upAxisCond.firstTerm)
        if axis == 'x':
            upAxisCond.colorIfTrueR.set(1)
        else:
            upAxisCond.colorIfTrueR.set(0)
        if axis == 'y':
            upAxisCond.colorIfFalseR.set(2)
        else:
            upAxisCond.colorIfFalseR.set(1)

        # pathNodes
        mps = curveUtils.nodesAlongCurve(crv=self.ikCrv,
                                         numNodes=numJoints,
                                         name=self.name,
                                         followAxis=axis,
                                         upNode=self.baseSubCtrl,
                                         upAxis=upAxis,
                                         upVec=worldUpAxis)
        for i in range(len(mps['mpNodes'])):
            mp = mps['mpNodes'][i]
            upVecCond.outColor.connect(mp.worldUpVector)
            upAxisCond.outColorR.connect(mp.upAxis)

            if i < numJoints / 2:
                self.startCtrl.worldMatrix[0].connect(mp.worldUpMatrix, f=1)
            else:
                self.endCtrl.worldMatrix[0].connect(mp.worldUpMatrix, f=1)
            self.baseCtrl.rotateOrder.connect(mp.rotateOrder)
        for grp in mps['grps']:
            grp.setParent(self.rigGrp)
            self.baseCtrl.rotateOrder.connect(grp.rotateOrder)

        # twisting
        self.twistReader = coreUtils.isolateTwist(
            mps['grps'][(numJoints / 2)].worldMatrix[0],
            mps['grps'][(numJoints / 2) - 1].worldInverseMatrix[0],
            name=self.name,
            axis=axis)
        twistAttr = pmc.Attribute('%s.outputRotate%s' %
                                  (self.twistReader[2].name(), axis.upper()))
        twistSrtList = []
        for i in range(numJoints / 2):
            mp = mps['mpNodes'][i]
            grp = mps['grps'][i]
            g = coreUtils.addChild(grp, 'group',
                                   grp.name().replace('grp', 'twist_srt'))
            self.baseCtrl.rotateOrder.connect(g.rotateOrder)
            baseMtx.outputScale.connect(g.s)
            uc = coreUtils.convert(twistAttr, (1.0 / (numJoints - 1)) * i,
                                   name=g.name().replace('_srt', '_utl'))
            uc.output.connect(pmc.Attribute('%s.r%s' % (g.name(), axis)))
            twistSrtList.append(g)
        for i in range(numJoints - (numJoints / 2)):
            index = i + (numJoints / 2)
            mp = mps['mpNodes'][index]
            grp = mps['grps'][index]
            g = coreUtils.addChild(grp, 'group',
                                   grp.name().replace('grp', 'twist_srt'))
            self.baseCtrl.rotateOrder.connect(g.rotateOrder)
            baseMtx.outputScale.connect(g.s)
            uc = coreUtils.convert(twistAttr, (-1.0 / (numJoints - 1)) *
                                   ((numJoints - (numJoints / 2) - i) - 1),
                                   name=g.name().replace('_srt', '_utl'))
            uc.output.connect(pmc.Attribute('%s.r%s' % (g.name(), axis)))
            twistSrtList.append(g)

        # squetch
        for i in range(numJoints):
            attr = pmc.addAttr(self.settingsCtrl,
                               longName='squetch_%s_amount' %
                               str(i + 1).zfill(2),
                               at='double',
                               k=1,
                               h=0)
            blend = coreUtils.blend(self.mainGrp.stretch,
                                    1.0,
                                    name='blend_%s_squetch_%s_UTL' %
                                    (self.name, str(i + 1).zfill(2)),
                                    blendAttr=self.settingsCtrl.attr(
                                        'squetch_%s_amount' %
                                        str(i + 1).zfill(2)))
            scaleDict = {
                'x': mps['grps'][i].sx,
                'y': mps['grps'][i].sy,
                'z': mps['grps'][i].sz
            }
            for key in scaleDict.keys():
                if key != axis:
                    blend.outputR.connect(scaleDict[key])

        # expose joints
        for i in range(numJoints):
            componentUtils.exposeDeformation(
                twistSrtList[i], '%s_%s' % (self.name, str(i + 1).zfill(2)))

        # colorize
        coreUtils.colorize('green',
                           self.fkCtrls + [self.baseCtrl, self.settingsCtrl])
        coreUtils.colorize(
            'yellow',
            self.fkRevCtrls + [self.startCtrl, self.endCtrl, self.baseSubCtrl])
Beispiel #4
0
def buildBaseRig(name='eye', numTweaks=7, tweaks=1):
    '''
    Create the bezier setup with corner, top and bottom controls.
    Radius sets the distance from the spin pivots to the rig
    Spread sets the width of the corners (in degrees from the centre)
    '''
    # Base structure
    rootGrp = pmc.group(empty=1, name='%s_cmpnt' % name)
    pmc.addAttr(rootGrp, ln='rigParent', dt='string')
    rootGrp.rigParent.set('components_GRP')

    inputGrp = coreUtils.addChild(rootGrp, 'group', name='%s_input' % name)
    pmc.select(inputGrp)
    pmc.addAttr(ln='rigInputs', dt='string', multi=1)
    pmc.addAttr(inputGrp, at='matrix', ln='head_in_mtx')
    pmc.addAttr(inputGrp, at='matrix', ln='jaw_in_mtx')

    controlsGrp = coreUtils.addChild(rootGrp, 'group', name='%s_controls' % name)
    pmc.select(controlsGrp)
    pmc.addAttr(ln='rigInputs', dt='string', multi=1)
    controlsGrp.rigInputs[0].set('options_CTL.all_ctls_vis>>visibility')

    rigGrp = coreUtils.addChild(rootGrp, 'group', name='%s_rig' % name)
    rigGrp.visibility.set(0)

    outputGrp = coreUtils.addChild(rootGrp, 'group', name='%s_output' % name)
    addOutputAttrs(outputGrp)

    pmc.addAttr(outputGrp, ln='outputType', dt='string')
    # in case there is a discrepancy between the neck joint and the head control
    pmc.addAttr(outputGrp, ln='ctrl2Joint_offset_mtx', at='matrix')
    outputGrp.outputType.set('eye')

    # Config node
    config = coreUtils.addChild(controlsGrp, 'group', name='%s_config' % name)
    pmc.addAttr(config, ln='radius', at='double', k=0, h=0)
    config.radius.set(configDict['radius'])

    pmc.addAttr(config, ln='spread', at='doubleAngle', k=0, h=0)
    config.spread.set(configDict['spread'])

    pmc.addAttr(config, ln='height', at='double', k=0, h=0)
    config.height.set(configDict['height'])

    # Base srts
    rootSrt = coreUtils.addChild(controlsGrp, 'group', name='%s_root_srt' % name)
    headSrt = coreUtils.decomposeMatrix(inputGrp.head_in_mtx, name='%s_head_in_mtx2Srt_utl' % name)
    coreUtils.connectDecomposedMatrix(headSrt, rootSrt)

    centreSrt = coreUtils.addChild(rootSrt, 'group', name='%s_centre_srt' % name)
    negScaleSrt = coreUtils.addChild(centreSrt, 'group', name='%s_negScale_srt' % name)
    negScaleSrt.sx.set(-1)

    # Set up jaw blending stuff
    jawOffset = pmc.createNode('composeMatrix', name='%s_jawOffsetMtx_utl' % name)
    jawResultMtx = pmc.createNode('multMatrix', name='%s_jawResultMtx_utl' % name)
    jawOffset.outputMatrix.connect(jawResultMtx.matrixIn[0])
    inputGrp.jaw_in_mtx.connect(jawResultMtx.matrixIn[1])
    centreSrt.worldInverseMatrix[0].connect(jawResultMtx.matrixIn[2])
    jawSrt = coreUtils.decomposeMatrix(jawResultMtx.matrixSum, name='%s_jawResultMtx2Srt_utl' % name)
    jawRotConvert = coreUtils.convert(jawSrt.outputRotateX, 1.0, name='%s_jawRotAngle2Float_utl' % name)

    # Spin srt + Ctrl structure
    ctrls = []
    constGrps = []
    for i in ['R', 'T', 'L', 'B']:
        aimDict = {'T':'up', 'L':'left', 'B':'down', 'R':'left'}
        constSrt = coreUtils.addChild(centreSrt, 'group', name='%s_%s_const_srt' % (name, i))
        constGrps.append(constSrt)
        spinSrt = coreUtils.addChild(constSrt, 'group', name='%s_%s_spin_srt' % (name, i))

        bufferSrt = coreUtils.addChild(spinSrt, 'group', name='%s_%s_ctrlBufferSrt' % (name, i))
        negSrt = coreUtils.addChild(bufferSrt, 'group', name='%s_%s_xNegSrt' % (name, i))
        ctrl = controls.triCtrl(size=config.radius.get()*.2, aim=aimDict[i], name='%s_%s_ctrl' % (name, i))
        pmc.addAttr(ctrl, ln='follow_jaw', minValue=0.0, maxValue=1.0, k=1, h=0, at='double')
        ctrl.setParent(negSrt)
        config.radius.connect(bufferSrt.tz)
        if i == 'T':
            config.height.connect(bufferSrt.ty)
        elif i == 'B':
            heightInvert = coreUtils.convert(config.height, -1, name='%s_heightInvert_utl' % name)
            heightInvert.output.connect(bufferSrt.ty)

        # Negate x & y translate and connect to spin
        conv = coreUtils.convert(ctrl.tx, -1, name='%s_%s_invertTX_utl' % (name, i))
        conv.output.connect(negSrt.tx)
        spinFac = coreUtils.convert(config.radius, 6.283, name='%s_%s_spinFactor_utl' % (name, i))
        spinAmount = coreUtils.divide(ctrl.tx, spinFac.output, name='%s_%s_spinAmountX_utl' % (name, i))
        spinConv = coreUtils.convert(spinAmount.outputX, 6.283, name='%s_%s_spinX_utl' % (name, i))

        conv = coreUtils.convert(ctrl.ty, -1, name='%s_%s_invertTY_utl' % (name, i))
        conv.output.connect(negSrt.ty)
        spinAmountY = coreUtils.divide(ctrl.ty, spinFac.output, name='%s_%s_spinAmountY_utl' % (name, i))
        spinConvY = coreUtils.convert(spinAmountY.outputX, -6.283, name='%s_%s_spinY_utl' % (name, i))


        if i == 'R':
            negScaleSrt.setParent(constSrt)
            spinSrt.setParent(negScaleSrt)
            spinSrt.s.set(1,1,1)
            spinSrt.r.set(0,0,0)
        if i == 'L' or i == 'R':
            spinOffset = pmc.createNode('animBlendNodeAdditiveDA', name='%s_%s_spinOffset_utl' % (name, i))
            spinConv.output.connect(spinOffset.inputA)
            config.spread.connect(spinOffset.inputB)
            spinOffset.output.connect(spinSrt.ry)
        else:
            spinConv.output.connect(spinSrt.ry)
        spinConvY.output.connect(spinSrt.rx)
        spinSrt.ro.set(2)

        # set up jaw blending
        jawBlend = coreUtils.pairBlend((0,0,0), (0,0,0), jawSrt.outputTranslate, jawSrt.outputRotate, name='%s_%s_jawBlend_utl' % (name, i), blendAttr=ctrl.follow_jaw)
        jawBlend.outTranslate.connect(constSrt.t)
        jawBlend.outRotate.connect(constSrt.r)

        # set up corner push on jaw open
        if i == 'R' or i =='L':
            pmc.addAttr(bufferSrt, ln='jawOpenPush', at='double', k=0, h=0)
            rv = pmc.createNode('remapValue', name='%s_%s_jawPushRemap_utl' % (name, i))
            jawAdd = pmc.createNode('animBlendNodeAdditive', name='%s_%s_jawOpenAdd_utl' % (name, i))
            config.radius.connect(jawAdd.inputB)
            rv.outValue.connect(jawAdd.weightA)
            ctrl.follow_jaw.connect(rv.inputValue)
            jawPushMult = coreUtils.multiplyDouble(jawRotConvert.output, bufferSrt.jawOpenPush, name='%s_%s_jawPushMult' % (name, i))
            jawPushMult.output.connect(jawAdd.inputA)
            jawAdd.output.connect(bufferSrt.tz, f=1)
            rv.value[1].value_Position.set(.5)
            rv.value[2].value_FloatValue.set(0)
            rv.value[2].value_Position.set(1)
            rv.value[0].value_Interp.set(2)
            rv.value[1].value_Interp.set(2)


        ctrls.append(ctrl)

    # Distance nodes for auto scaling of tangents
    dist_R_T = coreUtils.distanceBetweenNodes(ctrls[0], ctrls[1], name='%s_dist_R_T_utl' % name)
    scaledDist_R_T = coreUtils.divide(dist_R_T.distance, headSrt.outputScaleX, name='%s_scaledDist_R_T_utl' % name)

    dist_L_T = coreUtils.distanceBetweenNodes(ctrls[2], ctrls[1], name='%s_dist_L_T_utl' % name)
    scaledDist_L_T = coreUtils.divide(dist_L_T.distance, headSrt.outputScaleX, name='%s_scaledDist_L_T_utl' % name)

    dist_R_B = coreUtils.distanceBetweenNodes(ctrls[0], ctrls[3], name='%s_dist_R_B_utl' % name)
    scaledDist_R_B = coreUtils.divide(dist_R_B.distance, headSrt.outputScaleX, name='%s_scaledDist_R_B_utl' % name)

    dist_L_B = coreUtils.distanceBetweenNodes(ctrls[2], ctrls[3], name='%s_dist_L_B_utl' % name)
    scaledDist_L_B = coreUtils.divide(dist_L_B.distance, headSrt.outputScaleX, name='%s_scaledDist_L_B_utl' % name)

    scaledHeight = coreUtils.divide(config.height, headSrt.outputScaleY, name='%s_scaledHeight_utl' % name)


    # Build curves
    points = [(0,0,0) for i in range(7)]
    knots = [0,0,0,1,1,1,2,2,2]
    topCrv = pmc.curve(d=3, p=points, k=knots, name='%s_T_macro_crv' % name)
    topCrv.setParent(rigGrp)
    btmCrv = pmc.curve(d=3, p=points, k=knots, name='%s_B_macro_crv' % name)
    btmCrv.setParent(rigGrp)

    p1 = coreUtils.pointMatrixMult((0,0,0), ctrls[0].worldMatrix[0], name='%s_R_pos_utl' % name)

    p2TanLen = coreUtils.multiplyDouble(headSrt.outputScaleY, scaledHeight.outputX, name='%s_R_outTan_len_utl' % name)
    p2 = coreUtils.pointMatrixMult((0,0,0), ctrls[0].worldMatrix[0], name='%s_R_outTan_pos_utl' % name)
    p2TanLen.output.connect(p2.input1Y)

    p3TanLen = coreUtils.multiply(scaledDist_R_T.outputX, -.5, name='%s_T_inTan_len_utl' % name)
    p3 = coreUtils.pointMatrixMult(p3TanLen.output, ctrls[1].worldMatrix[0], name='%s_T_inTan_pos_utl' % name)

    p4 = coreUtils.pointMatrixMult((0,0,0), ctrls[1].worldMatrix[0], name='%s_T_pos_utl' % name)

    p5TanLen = coreUtils.multiply(scaledDist_L_T.outputX, .5, name='%s_T_outTan_len_utl' % name)
    p5 = coreUtils.pointMatrixMult(p5TanLen.output, ctrls[1].worldMatrix[0], name='%s_T_outTan_pos_utl' % name)

    p6 = coreUtils.pointMatrixMult((0,0,0), ctrls[2].worldMatrix[0], name='%s_L_inTan_pos_utl' % name)
    p2TanLen.output.connect(p6.input1Y)

    p7 = coreUtils.pointMatrixMult((0,0,0), ctrls[2].worldMatrix[0], name='%s_L_pos_utl' % name)

    p8TanLen = coreUtils.convert(p2TanLen.output, -1, name='%s_L_outTan_len_utl' % name)
    p8 = coreUtils.pointMatrixMult((0,0,0), ctrls[2].worldMatrix[0], name='%s_L_outTan_pos_utl' % name)
    p8TanLen.output.connect(p8.input1Y)

    p9TanLen = coreUtils.multiply(scaledDist_L_B.outputX, .5, name='%s_B_inTan_len_utl' % name)
    p9 = coreUtils.pointMatrixMult(p9TanLen.output, ctrls[3].worldMatrix[0], name='%s_B_inTan_pos_utl' % name)

    p10 = coreUtils.pointMatrixMult((0,0,0), ctrls[3].worldMatrix[0], name='%s_B_pos_utl' % name)

    p11TanLen = coreUtils.multiply(scaledDist_R_B.outputX, -.5, name='%s_B_outTan_len_utl' % name)
    p11 = coreUtils.pointMatrixMult(p11TanLen.output, ctrls[3].worldMatrix[0], name='%s_B_outTan_pos_utl' % name)

    p12 = coreUtils.pointMatrixMult((0,0,0), ctrls[0].worldMatrix[0], name='%s_R_inTan_pos_utl' % name)
    p8TanLen.output.connect(p12.input1Y)

    p1.output.connect(topCrv.controlPoints[0])
    p2.output.connect(topCrv.controlPoints[1])
    p3.output.connect(topCrv.controlPoints[2])
    p4.output.connect(topCrv.controlPoints[3])
    p5.output.connect(topCrv.controlPoints[4])
    p6.output.connect(topCrv.controlPoints[5])
    p7.output.connect(topCrv.controlPoints[6])

    p1.output.connect(btmCrv.controlPoints[0])
    p12.output.connect(btmCrv.controlPoints[1])
    p11.output.connect(btmCrv.controlPoints[2])
    p10.output.connect(btmCrv.controlPoints[3])
    p9.output.connect(btmCrv.controlPoints[4])
    p8.output.connect(btmCrv.controlPoints[5])
    p7.output.connect(btmCrv.controlPoints[6])

    returnDict = {
        'root':rootSrt,
        'topCrv':topCrv,
        'btmCrv':btmCrv,
        'tangents':[p2, p8],
        'rigGrp':rigGrp
    }

    if not tweaks:
        return returnDict

    ##------------------------------TWEAKS-----------------------------------------##

    # Create motions path nodes
    tweakCtrls = []
    tweakGrp = coreUtils.addChild(centreSrt, 'group', name='%s_tweakControls_hrc' % name)
    for i in range(numTweaks):
        num = str(i+1).zfill(2)
        mp = pmc.createNode('motionPath', name='%s_T_%s_tweakMotionPath_utl' % (name, num))
        topCrv.worldSpace[0].connect(mp.geometryPath)
        mp.uValue.set(1.0 / (numTweaks-1) * i)
        bfr = pmc.group(empty=1, name='%s_tweak_%s_bufferSrt' % (name, num))
        aim = 'up'
        if i==numTweaks-1 or i == 0:
            aim='left'
        ctrl = controls.triCtrl(size = configDict['radius']*.075, aim=aim, name='%s_tweak_%s_ctrl' % (name, num))
        ctrl.setParent(bfr)
        bfrLocalPos = coreUtils.pointMatrixMult(mp.allCoordinates, centreSrt.worldInverseMatrix[0], name='%s_tweakLocalPos_%s_utl' % (name, num))
        bfrLocalPos.output.connect(bfr.t)
        bfrAngle = pmc.createNode('angleBetween', name='%s_tweakAngle_%s_utl' % (name, num))
        bfrLocalPos.output.connect(bfrAngle.vector2)
        bfrAngle.vector1.set((0,0,1))
        euler2Quat = pmc.createNode('eulerToQuat', name='%s_tweakAngleEuler2Quat_%s_utl' % (name, num))
        bfrAngle.euler.connect(euler2Quat.inputRotate)
        quatToEuler = pmc.createNode('quatToEuler', name='%s_tweakAngleQuat2Euler_%s_utl' % (name, num))
        euler2Quat.outputQuat.connect(quatToEuler.inputQuat)
        quatToEuler.inputRotateOrder.set(2)
        bfr.ro.set(2)
        quatToEuler.outputRotateX.connect(bfr.rx)
        quatToEuler.outputRotateY.connect(bfr.ry)
        mp.fractionMode.set(1)
        tweakCtrls.append(ctrl)
        d = coreUtils.decomposeMatrix(ctrl.worldMatrix[0], name='%s_tweak_%s_mtx2Srt_utl' % (name, num))
        if i==(numTweaks-1):
            tanMult = coreUtils.convert(p8.input1Y, -0.5, name='%s_T_tweakInTan_utl' % name)
            b = coreUtils.addChild(tweakCtrls[-1], 'group', name=bfr.name().replace('bufferSrt', 'inTan_bufferSrt'))
            tanMult.output.connect(b.ty)
            c = controls.triCtrl(size = configDict['radius']*.05, aim='up', name='%s_tweak_%s_inTan_ctrl' % (name, num))
            coreUtils.align(c, b, parent=1)
            tweakCtrls.append(c)
        if i==0:
            tanMult = coreUtils.convert(p2.input1Y, 0.5, name='%s_T_tweakOutTan_utl' % name)
            b = coreUtils.addChild(tweakCtrls[0], 'group', name=bfr.name().replace('bufferSrt', 'outTan_bufferSrt'))
            tanMult.output.connect(b.ty)
            c = controls.triCtrl(size = configDict['radius']*.05, aim='up', name='%s_tweak_%s_outTan_ctrl' % (name, num))
            coreUtils.align(c, b, parent=1)
            tweakCtrls.append(c)

        if d.outputTranslateX.get() < 0.0:
            bfr.sx.set(-1)

        bfr.setParent(tweakGrp)

    for i in range(numTweaks)[1:-1]:
        num = str(i+numTweaks).zfill(2)
        mp = pmc.createNode('motionPath', name='%s_B_%s_tweakMotionPath_utl' % (name, num))
        btmCrv.worldSpace[0].connect(mp.geometryPath)
        mp.uValue.set(1.0 / (numTweaks-1) * i)
        bfr = pmc.group(empty=1, name='%s_tweak_%s_bufferSrt' % (name, num))
        ctrl = controls.triCtrl(size = configDict['radius']*.075, aim='down', name='%s_tweak_%s_ctrl' % (name, num))
        ctrl.setParent(bfr)
        bfrLocalPos = coreUtils.pointMatrixMult(mp.allCoordinates, centreSrt.worldInverseMatrix[0], name='%s_tweakLocalPos_%s_utl' % (name, num))
        bfrLocalPos.output.connect(bfr.t)
        bfrAngle = pmc.createNode('angleBetween', name='%s_tweakAngle_%s_utl' % (name, num))
        bfrLocalPos.output.connect(bfrAngle.vector2)
        bfrAngle.vector1.set((0,0,1))
        euler2Quat = pmc.createNode('eulerToQuat', name='%s_tweakAngleEuler2Quat_%s_utl' % (name, num))
        bfrAngle.euler.connect(euler2Quat.inputRotate)
        quatToEuler = pmc.createNode('quatToEuler', name='%s_tweakAngleQuat2Euler_%s_utl' % (name, num))
        euler2Quat.outputQuat.connect(quatToEuler.inputQuat)
        quatToEuler.inputRotateOrder.set(2)
        bfr.ro.set(2)
        quatToEuler.outputRotateX.connect(bfr.rx)
        quatToEuler.outputRotateY.connect(bfr.ry)
        mp.fractionMode.set(1)
        d = coreUtils.decomposeMatrix(ctrl.worldMatrix[0], name='%s_tweak_%s_mtx2Srt_utl' % (name, num))
        if i==1:
            tanMult = coreUtils.convert(p2.input1Y, -0.5, name='%s_B_tweakOutTan_utl' % name)
            b = coreUtils.addChild(tweakCtrls[0], 'group', name=tweakCtrls[0].name().replace('ctrl', 'inTan_bufferSrt'))
            tanMult.output.connect(b.ty)
            c = controls.triCtrl(size = configDict['radius']*.05, aim='down', name=tweakCtrls[0].name().replace('ctrl', 'inTan_ctrl'))
            coreUtils.align(c, b, parent=1)
            tweakCtrls.append(c)
        tweakCtrls.append(ctrl)
        if i==(numTweaks-2):
            tanMult = coreUtils.convert(p8.input1Y, 0.5, name='%s_B_tweakInTan_utl' % name)
            b = coreUtils.addChild(tweakCtrls[numTweaks], 'group', name=tweakCtrls[numTweaks].name().replace('ctrl', 'outTan_bufferSrt'))
            tanMult.output.connect(b.ty)
            c = controls.triCtrl(size = configDict['radius']*.05, aim='down', name=tweakCtrls[numTweaks].name().replace('ctrl', 'outTan_ctrl'))
            coreUtils.align(c, b, parent=1)
            tweakCtrls.append(c)

        if d.outputTranslateX.get() < 0.0:
            bfr.sx.set(-1)

        bfr.setParent(tweakGrp)

    ctrlSet = pmc.sets(ctrls + tweakCtrls, name='%s_ctls_SEL' % name)


    # CLEAN UP
    coreUtils.attrCtrl(nodeList=[ctrls[0], ctrls[2]], attrList=['sx', 'sz', 'visibility'])
    coreUtils.attrCtrl(nodeList=[ctrls[1], ctrls[3]], attrList=['sy', 'sz', 'visibility'])
    coreUtils.attrCtrl(nodeList=tweakCtrls, attrList=['sx', 'sy', 'sz', 'visibility'])
    coreUtils.attrCtrl(nodeList=ctrls + tweakCtrls, attrList=['aiRenderCurve', 'aiCurveWidth', 'aiSampleRate', 'aiCurveShaderR', 'aiCurveShaderG', 'aiCurveShaderB'])

    addOutputAttrs(outputGrp)
    joints = []
    # top joints
    for i in range(len(tweakCtrls)):
        num = str(i+1).zfill(2)
        ctrl = tweakCtrls[i]
        t = pmc.xform(ctrl, ws=1, q=1, t=1)[0]
        unMirror=0
        if t < 0.0:
            unMirror=1
        faceRigging.exposeOutput(ctrl, outputGrp, 'eye', unMirror=unMirror, createJoint=0)

        pmc.select(None)
        j = pmc.joint(name='%s_T_%s_Out_Jnt' % (name, num))
        joints.append(j)

        j.segmentScaleCompensate.set(0)
        pmc.addAttr(j, ln='jointIndex', at='short', k=0)
        j.jointIndex.set(i)
        pmc.addAttr(j, ln='rigType', dt='string')
        j.rigType.set('eye')

        d = coreUtils.decomposeMatrix(outputGrp.outMatrix[i], name='%s_outMtx2Srt_%s_utl' % (name, num))
        coreUtils.connectDecomposedMatrix(d, j)
Beispiel #5
0
    def build(self, start, end, numFkCtrls, jointsPerCtrl, numIkCtrls, latticeDivisions, axis, upAxis):
        start, end = coreUtils.getStartAndEnd(start, end)
        ctrlSize = coreUtils.getDistance(start, end) * .1
        radius=1

        # main control
        baseCtrl = controls.circleBumpCtrl(radius=ctrlSize,
                                           name='%s_base_ctrl' % self.name, axis=axis)
        baseSrt = coreUtils.decomposeMatrix(baseCtrl.worldMatrix[0], name='%s_baseWorldMtxToSrt_utl' % baseCtrl)
        baseBuffer = coreUtils.addParent(baseCtrl, 'group', name='%s_base_buffer_srt' % self.name)
        baseBuffer.setParent(self.interfaceGrp)
        self.ctrls.append(baseCtrl)

        points = coreUtils.pointsAlongVector(start, end, divisions=numIkCtrls-1)

        # ik ctrls
        ikCtrls=[]
        refVecs = []
        ikSrtList = []
        for i in range(len(points)):
            num = str(i+1).zfill(2)

            c = controls.ballCtrl(radius=ctrlSize*.5, name='%s_ik_%s_ctrl' % (self.name, num))
            b = coreUtils.addParent(c, 'group', '%s_ik_%s_buffer_srt' % (self.name, num))
            b.setParent(self.interfaceGrp)
            b.t.set(points[i])
            ikCtrls.append(c)
            refVecs.append(coreUtils.matrixAxisToVector(c, name='%s_referenceVec_%s_utl' % (self.name, num), axis='x'))
            ikSrtList.append(coreUtils.decomposeMatrix(c.worldMatrix[0], name='%s_ikCtrlMtxToSrt_%s_utl' % (self.name, num)))

            # Add attributes for blending between soft and sharp points
            pmc.addAttr(c, ln='soften_outer', at='double', k=1, h=0, minValue=0.0, maxValue=1.0)
            pmc.addAttr(c, ln='soften_inner', at='double', k=1, h=0, minValue=0.0, maxValue=1.0)
            pmc.addAttr(c, ln='bend_pos_x', at='double', k=1, h=0)
            pmc.addAttr(c, ln='bend_neg_x', at='double', k=1, h=0)
            pmc.addAttr(c, ln='bend_pos_y', at='double', k=1, h=0)
            pmc.addAttr(c, ln='bend_neg_y', at='double', k=1, h=0)

        # tangent vectors
        tangentVecs = []
        tangentVecs.append(coreUtils.matrixAxisToVector(ikCtrls[0], name='%s_tangentVec_00_utl' % self.name, axis='z'))
        for i in range(len(ikCtrls)-1):
            num = str(i+2).zfill(2)
            vec = coreUtils.vectorBetweenNodes(ikCtrls[i], ikCtrls[i+1], name='%s_tangentVec_%s_utl' % (self.name, num))
            vecNorm = coreUtils.normalizeVector(vec.output3D, name='%s_tangentVecNorm_%s_utl' % (self.name, num))
            tangentVecs.append(vecNorm)

        tangentVecs.append(coreUtils.matrixAxisToVector(ikCtrls[-1], name='%s_tangentVec_%s_utl' % (self.name, str(len(points)).zfill(2)), axis='z'))

        blendedTangentVecs=[]
        # create blended tangent vector
        for i in range(len(ikCtrls)):
            num = str(i+1).zfill(2)
            bc = coreUtils.blend(tangentVecs[i].output, tangentVecs[i+1].output, name='%s_blendedTangentVec_%s_utl' % (self.name, num))
            bc.blender.set(0.5)
            blendedTangentVecNorm = coreUtils.normalizeVector(bc.output, name='%s_blendedTangentVecNorm_%s_utl' % (self.name, num))
            blendedTangentVecs.append(blendedTangentVecNorm)
        blendedTangentVecs.append(tangentVecs[-1])


        # create matrix and pole vector for each joint
        segMtxList = []
        segPoleVecList = []
        segDots = []
        for i in range(len(ikCtrls)):
            num = str(i+1).zfill(2)
            segMtx = pmc.createNode('fourByFourMatrix', name='%s_segMtx_%s_utl' % (self.name, num))
            frontVec = blendedTangentVecs[i]
            if i == 0:
                frontVec = tangentVecs[1]
            elif i == len(ikCtrls)-1:
                frontVec = tangentVecs[i]
            upVec = coreUtils.cross(frontVec.output, refVecs[i].output, name='%s_upVec_%s_utl' % (self.name, num))
            sideVec = coreUtils.cross(upVec.output, frontVec.output, name='%s_sideVec_%s_utl' % (self.name, num))

            if i < len(ikCtrls):
                segDot = coreUtils.dot(frontVec.output, tangentVecs[i+1].output, name='%s_segDot_%s_utl' % (self.name, num))
                segDots.append(segDot)

            if i != 0 and i < len(ikCtrls)-1:
                segMidPoint = coreUtils.blend(coreUtils.isDecomposed(ikCtrls[i-1]).outputTranslate, coreUtils.isDecomposed(ikCtrls[i+1]).outputTranslate, name='%s_segMidPoint_%s_utl' % (self.name, num))
                segMidPoint.blender.set(0.5)
                segPoleVec = coreUtils.minus([segMidPoint.output, coreUtils.isDecomposed(ikCtrls[i]).outputTranslate], name='%s_segPoleVec_%s_utl' % (self.name, num))
                segPoleVecCond = pmc.createNode('condition', name='%s_segPoleVecIsZero_%s_utl' % (self.name, num))
                segDot.outputX.connect(segPoleVecCond.firstTerm)
                segPoleVecCond.secondTerm.set(1.0)
                refVecs[i].output.connect(segPoleVecCond.colorIfTrue)
                segPoleVec.output3D.connect(segPoleVecCond.colorIfFalse)
                segPoleVecNorm = coreUtils.normalizeVector(segPoleVecCond.outColor, name='%s_segPoleVecNorm_%s_utl' % (self.name, num))
                segPoleVecList.append(segPoleVecNorm)
            else:
                segPoleVecList.append(upVec)

            # construct segment matrix
            sideVec.outputX.connect(segMtx.in00)
            sideVec.outputY.connect(segMtx.in01)
            sideVec.outputZ.connect(segMtx.in02)

            upVec.outputX.connect(segMtx.in10)
            upVec.outputY.connect(segMtx.in11)
            upVec.outputZ.connect(segMtx.in12)

            frontVec.outputX.connect(segMtx.in20)
            frontVec.outputY.connect(segMtx.in21)
            frontVec.outputZ.connect(segMtx.in22)

            d = coreUtils.isDecomposed(ikCtrls[i])
            d.outputTranslateX.connect(segMtx.in30)
            d.outputTranslateY.connect(segMtx.in31)
            d.outputTranslateZ.connect(segMtx.in32)

            segMtxList.append(segMtx)

        posYPoints = []
        negYPoints = []
        posXPoints = []
        negXPoints = []

        for i in range(len(ikCtrls)):
            num = str(i+1).zfill(2)

            isStraightCond = None
            if i < (len(ikCtrls)-2):
                isStraightCond = pmc.createNode('condition', name='%s_isStraight_%s_utl' % (self.name, num))
                segDot.outputX.connect(isStraightCond.firstTerm)
                isStraightCond.secondTerm.set(1.0)
                segPoleVecList[i+1].output.connect(isStraightCond.colorIfTrue)
                segPoleVecList[i].output.connect(isStraightCond.colorIfFalse)

            if i == 0 or i == len(ikCtrls)-1:
                posYPoint = coreUtils.pointMatrixMult((0, 1, 0), segMtxList[i].output, name='%s_seg_%s_posYPoint_utl' % (self.name, num))
                posYPoints.append(posYPoint)

                negYPoint = coreUtils.pointMatrixMult((0, -1, 0), segMtxList[i].output, name='%s_seg_%s_negYPoint_utl' % (self.name, num))
                negYPoints.append(negYPoint)

                posXPoint = coreUtils.pointMatrixMult((1, 0, 0), segMtxList[i].output, name='%s_seg_%s_posXPoint_utl' % (self.name, num))
                posXPoints.append(posXPoint)

                negXPoint = coreUtils.pointMatrixMult((-1, 0, 0), segMtxList[i].output, name='%s_seg_%s_negXPoint_utl' % (self.name, num))
                negXPoints.append(negXPoint)
            else:
                # Calculate X and Y scaling.
                scaleMult = coreUtils.divide(1.0, segDots[i].outputX, name='%s_segScaleMult_%s_utl' % (self.name, num))

                # Measure tangent vec relative to first mtx of segment so we know direction of bend
                worldTangentVec = coreUtils.add([tangentVecs[i+1].output, ikSrtList[i].outputTranslate], name='%s_seg_%s_worldTangentVec_utl' % (self.name, num))
                segMtxInverse = coreUtils.inverseMatrix(segMtxList[i].output, name='%s_seg_%s_inverseMtx_utl' % (self.name, num))
                localTangentVec = coreUtils.pointMatrixMult(worldTangentVec.output3D, segMtxInverse.outputMatrix, name='%s_seg_%s_localTangentVec_utl' % (self.name, num))
                localProjectVec = pmc.createNode('vectorProduct', name='%s_seg_%s_localProjectVec_utl' % (self.name, num))
                localProjectVec.input1Z.set(.0001)
                localProjectVec.operation.set(0)
                localProjectVec.normalizeOutput.set(1)
                localYVecAbs = coreUtils.forceAbsolute(localProjectVec.outputY, name='%s_seg_%s_localYVecAbs' % (self.name, num))[1]
                localXVecAbs = coreUtils.forceAbsolute(localProjectVec.outputX, name='%s_seg_%s_localXVecAbs' % (self.name, num))[1]
                localTangentVec.outputX.connect(localProjectVec.input1X)
                localTangentVec.outputY.connect(localProjectVec.input1Y)

                posYRemap = pmc.createNode('remapValue', name='%s_seg_%s_posYRemap_utl' % (self.name, num))
                localProjectVec.outputY.connect(posYRemap.inputValue)

                negYRemap = pmc.createNode('remapValue', name='%s_seg_%s_negYRemap_utl' % (self.name, num))
                negYInvert = coreUtils.convert(localProjectVec.outputY, -1, name='%s_seg_%s_negYInvert_utl' % (self.name, num))
                negYInvert.output.connect(negYRemap.inputValue)

                posXRemap = pmc.createNode('remapValue', name='%s_seg_%s_posXRemap_utl' % (self.name, num))
                localProjectVec.outputX.connect(posXRemap.inputValue)

                negXRemap = pmc.createNode('remapValue', name='%s_seg_%s_negXRemap_utl' % (self.name, num))
                negXInvert = coreUtils.convert(localProjectVec.outputX, -1, name='%s_seg_%s_negXInvert_utl' % (self.name, num))
                negXInvert.output.connect(negXRemap.inputValue)

                posYOuterMult = coreUtils.multiply(posYRemap.outValue, ikCtrls[i].soften_outer, name='%s_seg_%s_posYOuterMult_utl' % (self.name, num))
                posYInnerMult = coreUtils.multiply(negYRemap.outValue, ikCtrls[i].soften_inner, name='%s_seg_%s_posYInnerMult_utl' % (self.name, num))
                posYTotal = coreUtils.add([posYOuterMult.outputX, posYInnerMult.outputX], name='%s_seg_%s_posYBlendAmount_utl' % (self.name, num))
                posYTotal.output1D.connect(ikCtrls[i].bend_pos_y)

                negYOuterMult = coreUtils.multiply(posYRemap.outValue, ikCtrls[i].soften_inner, name='%s_seg_%s_negYOuterMult_utl' % (self.name, num))
                negYInnerMult = coreUtils.multiply(negYRemap.outValue, ikCtrls[i].soften_outer, name='%s_seg_%s_negYInnerMult_utl' % (self.name, num))
                negYTotal = coreUtils.add([negYOuterMult.outputX, negYInnerMult.outputX], name='%s_seg_%s_negYBlendAmount_utl' % (self.name, num))
                negYTotal.output1D.connect(ikCtrls[i].bend_neg_y)

                posXOuterMult = coreUtils.multiply(posXRemap.outValue, ikCtrls[i].soften_outer, name='%s_seg_%s_posXOuterMult_utl' % (self.name, num))
                posXInnerMult = coreUtils.multiply(negXRemap.outValue, ikCtrls[i].soften_inner, name='%s_seg_%s_posXInnerMult_utl' % (self.name, num))
                posXTotal = coreUtils.add([posXOuterMult.outputX, posXInnerMult.outputX], name='%s_seg_%s_posXBlendAmount_utl' % (self.name, num))
                posXTotal.output1D.connect(ikCtrls[i].bend_pos_x)

                negXOuterMult = coreUtils.multiply(posXRemap.outValue, ikCtrls[i].soften_inner, name='%s_seg_%s_negXOuterMult_utl' % (self.name, num))
                negXInnerMult = coreUtils.multiply(negXRemap.outValue, ikCtrls[i].soften_outer, name='%s_seg_%s_negXInnerMult_utl' % (self.name, num))
                negXTotal = coreUtils.add([negXOuterMult.outputX, negXInnerMult.outputX], name='%s_seg_%s_negXBlendAmount_utl' % (self.name, num))
                negXTotal.output1D.connect(ikCtrls[i].bend_neg_x)

                posYBlend = coreUtils.blend(scaleMult.outputX, 1.0, name='%s_seg_%s_posYBlend_utl' % (self.name, num), blendAttr=localYVecAbs.outputX)
                negYInvert = coreUtils.convert(posYBlend.outputR, -1.0, name='%s_seg_%s_negYLength_utl' % (self.name, num))

                posXBlend = coreUtils.blend(scaleMult.outputX, 1.0, name='%s_seg_%s_posXBlend_utl' % (self.name, num), blendAttr=localXVecAbs.outputX)
                negXInvert = coreUtils.convert(posXBlend.outputR, -1.0, name='%s_seg_%s_negXLength_utl' % (self.name, num))

                posYPoint = coreUtils.pointMatrixMult((0, 0, 0), segMtxList[i].output, name='%s_seg_%s_posYPoint_utl' % (self.name, num))
                posYBlend.outputR.connect(posYPoint.input1Y)
                posYPoints.append(posYPoint)

                negYPoint = coreUtils.pointMatrixMult((0, 0, 0), segMtxList[i].output, name='%s_seg_%s_negYPoint_utl' % (self.name, num))
                negYInvert.output.connect(negYPoint.input1Y)
                negYPoints.append(negYPoint)

                posXPoint = coreUtils.pointMatrixMult((0, 0, 0), segMtxList[i].output, name='%s_seg_%s_posXPoint_utl' % (self.name, num))
                posXBlend.outputR.connect(posXPoint.input1X)
                posXPoints.append(posXPoint)

                negXPoint = coreUtils.pointMatrixMult((0, 0, 0), segMtxList[i].output, name='%s_seg_%s_negXPoint_utl' % (self.name, num))
                negXInvert.output.connect(negXPoint.input1X)
                negXPoints.append(negXPoint)

        # Add intermediate points
        posYMidPoints = []
        negYMidPoints = []
        posXMidPoints = []
        negXMidPoints = []
        for i in range(len(posYPoints)-1):
            num = (str(i+1).zfill(2))
            posYPoint = coreUtils.blend(posYPoints[i].output, posYPoints[i+1].output, name='%s_seg_%s_posYMidPoint_utl' % (self.name, num))
            posYPoint.blender.set(0.5)
            posYMidPoints.append(posYPoint)
            #posYPoints.insert((i*2)+1, posYPoint)

            negYPoint = coreUtils.blend(negYPoints[i].output, negYPoints[i+1].output, name='%s_seg_%s_negYMidPoint_utl' % (self.name, num))
            negYPoint.blender.set(0.5)
            #negYPoints.insert((i*2)+1, negYPoint)
            negYMidPoints.append(negYPoint)

            posXPoint = coreUtils.blend(posXPoints[i].output, posXPoints[i+1].output, name='%s_seg_%s_posXMidPoint_utl' % (self.name, num))
            posXPoint.blender.set(0.5)
            #posXPoints.insert((i*2)+1, posXPoint)
            posXMidPoints.append(posXPoint)

            negXPoint = coreUtils.blend(negXPoints[i].output, negXPoints[i+1].output, name='%s_seg_%s_negXMidPoint_utl' % (self.name, num))
            negXPoint.blender.set(0.5)
            #negXPoints.insert((i*2)+1, negXPoint)
            negXMidPoints.append(negXPoint)

        for i in range(len(posYMidPoints)):
            posYPoints.insert((i*2)+1, posYMidPoints[i])
            negYPoints.insert((i*2)+1, negYMidPoints[i])
            posXPoints.insert((i*2)+1, posXMidPoints[i])
            negXPoints.insert((i*2)+1, negXMidPoints[i])



        # create lattices
        latticeScale = math.sqrt(1*2)
        pmc.select([])
        sharpLattice = pmc.lattice(dv=(2, 2, len(posYPoints)), scale=(1, 1, 1))
        sharpLattice[0].rename('%s_sharpLattice_def' % self.name)
        sharpLattice[1].rename('%s_sharpLattice_cage' % self.name)
        sharpLattice[2].rename('%s_sharpLattice_base' % self.name)
        sharpLattice[2].rz.set(45)
        sharpLattice[2].s.set((latticeScale, latticeScale, coreUtils.getDistance(start, end)))

        for i in range(len(posYPoints)):
            posYPoints[i].output.connect(sharpLattice[1].controlPoints[(i*4)+3])
            negYPoints[i].output.connect(sharpLattice[1].controlPoints[i*4])
            posXPoints[i].output.connect(sharpLattice[1].controlPoints[(i*4)+1])
            negXPoints[i].output.connect(sharpLattice[1].controlPoints[(i*4)+2])

        pmc.select([])
        softLattice = pmc.lattice(dv=(2, 2, len(posYPoints)), scale=(1, 1, 1))
        softLattice[0].rename('%s_softLattice_def' % self.name)
        softLattice[1].rename('%s_softLattice_cage' % self.name)
        softLattice[2].rename('%s_softLattice_base' % self.name)
        softLattice[2].rz.set(45)
        softLattice[2].s.set((latticeScale, latticeScale, coreUtils.getDistance(start, end)))
        softLattice[0].

        for i in range(len(posYPoints)):
            posYPoints[i].output.connect(softLattice[1].controlPoints[(i*4)+3])
            negYPoints[i].output.connect(softLattice[1].controlPoints[i*4])
            posXPoints[i].output.connect(softLattice[1].controlPoints[(i*4)+1])
            negXPoints[i].output.connect(softLattice[1].controlPoints[(i*4)+2])