示例#1
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])
示例#2
0
    def build(self, start, end, numFkCtrls, jointsPerCtrl, numIkCtrls,
              numSegments, axis, upAxis, bias):
        start, end = coreUtils.getStartAndEnd(start, end)
        ctrlSize = coreUtils.getDistance(start, end) * .3 / numSegments
        # Build ik curves
        ikCrv = curveUtils.curveBetweenNodes(start,
                                             end,
                                             numCVs=numIkCtrls,
                                             name='%s_ik_crv' % self.name)
        ikCrv.setParent(self.rigGrp)

        # main control
        baseCtrl = controls.circleBumpCtrl(radius=ctrlSize * 1.25,
                                           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)

        pmc.addAttr(baseCtrl,
                    ln='stretch',
                    at='double',
                    k=1,
                    h=0,
                    minValue=0.0,
                    maxValue=1.0)

        self.ctrls.append(baseCtrl)

        aimMtx = coreUtils.getAimMatrix(start=start,
                                        end=end,
                                        axis=axis,
                                        upAxis=upAxis,
                                        worldUpAxis=upAxis)
        startSrt = coreUtils.matrixToSrt(aimMtx)
        baseBuffer.t.set(startSrt['translate'])
        baseBuffer.r.set(startSrt['rotate'])

        # ik ctrls
        cvs = ikCrv.getCVs(space='world')
        self.ikCtrls = []

        for i in range(numIkCtrls):
            num = str(i).zfill(2)
            if i > 0:
                c = controls.ballCtrl(radius=ctrlSize - (i * .25),
                                      name='%s_ik_%s_ctrl' % (self.name, num))
                b = coreUtils.addParent(
                    c, 'group', '%s_ik_buffer_%s_srt' % (self.name, num))
                b.t.set(cvs[i])
                b.setParent(self.interfaceGrp)
                d = coreUtils.decomposeMatrix(
                    c.worldMatrix[0],
                    name='%s_ikWorldMtxToSrt_%s_utl' % (self.name, num))
                d.outputTranslate.connect(ikCrv.controlPoints[i])
                componentUtils.addSpaceSwitch(node=b,
                                              name='ik_%s' % num,
                                              spaces=['base'],
                                              type='parent',
                                              ctrlNode=c,
                                              targetNodes=[baseCtrl])
                self.ctrls.append(c)
                self.ikCtrls.append(c)
            else:
                baseSrt.outputTranslate.connect(ikCrv.controlPoints[0])

        # Arclen stuff for stretching vs maintaining length
        stretch = curveUtils.getCurveStretch(ikCrv, name='%s_A' % self.name)
        blendCond = pmc.createNode('condition',
                                   name='%s_stretchIsNegative_utl' % self.name)
        stretch['stretchFactor'].outputX.connect(blendCond.firstTerm)
        self.mainGrp.globalScale.connect(stretch['globalScaleFactor'].input1X)
        # self.mainGrp.globalScale.connect(blendCond.secondTerm)
        blendCond.operation.set(2)
        blendCond.secondTerm.set(1.0)
        blendCond.colorIfTrueR.set(1)
        baseCtrl.stretch.connect(blendCond.colorIfFalseR)

        mpList = []
        settingsCtrls = []
        allBuffers = []
        upNode = baseCtrl
        # Motion Path nodes
        for x in range(numSegments):
            segNum = str(x + 1).zfill(2)

            settingsCtrl = controls.squareChamferCtrl(
                size=ctrlSize - (x * .1),
                axis=upAxis,
                name='%s_seg_%s_settings_ctrl' % (self.name, segNum))
            pmc.addAttr(settingsCtrl,
                        ln='extend',
                        at='double',
                        k=1,
                        h=0,
                        minValue=0.0,
                        maxValue=1.0)
            pmc.addAttr(settingsCtrl, ln='twist', at='double', k=1, h=0)
            pmc.addAttr(settingsCtrl, ln='width', at='double', k=1, h=0)
            pmc.addAttr(settingsCtrl, ln='taper', at='double', k=1, h=0)
            settingsCtrls.append(settingsCtrl)
            settingsCtrl.extend.set(1)

            if x != 0:
                upNode = buffers[-1]
            minRange = (1.0 / numSegments) * x
            maxRange = (1.0 / numSegments) * (x + 1)
            mpList.append(
                curveUtils.nodesAlongCurve(ikCrv,
                                           numNodes=numFkCtrls * jointsPerCtrl,
                                           name='%s_%s' % (self.name, segNum),
                                           followAxis=axis,
                                           upAxis=upAxis,
                                           upNode=upNode,
                                           follow=1,
                                           groups=0,
                                           progressive=1,
                                           sampleRange=(minRange, maxRange)))

            # Parameter values
            paramVals = [mp.uValue.get() for mp in mpList[-1]['mpNodes']]
            if bias:
                for x in range(len(paramVals)):
                    paramVals[x] += paramVals[x] - pow(paramVals[x], 1 + bias)

            pairBlends = {'pb': [], 'pbMtx': [], 'pbInverseMtx': []}

            for i in range(numFkCtrls * jointsPerCtrl):
                num = str(i + 1).zfill(2)
                mp = mpList[-1]['mpNodes'][i]
                uc = coreUtils.convert(
                    settingsCtrl.twist,
                    ((.0174533 / numFkCtrls * jointsPerCtrl) * i),
                    name='%s_seg_%s_twistMult_%s_utl' %
                    (self.name, segNum, num))
                uc.output.connect(mp.frontTwist)

                if i != 0:
                    paramExtendMult = pmc.createNode(
                        'multDoubleLinear',
                        name='%s_seg_%s_paramExtendMult_%s_utl' %
                        (self.name, segNum, num))
                    paramMult = pmc.createNode(
                        'multDoubleLinear',
                        name='%s_seg_%s_paramMult_%s_utl' %
                        (self.name, segNum, num))
                    if x != 0:
                        paramExtendMult.input1.set(paramVals[i] - minRange)
                    else:
                        paramExtendMult.input1.set(paramVals[i])
                    settingsCtrl.extend.connect(paramExtendMult.input2)

                    paramExtendMult.output.connect(paramMult.input1)
                    stretch['stretchFactor'].outputX.connect(paramMult.input2)
                    #paramMult.input2.set(1)

                    blend = pmc.createNode(
                        'blendTwoAttr',
                        name='%s_seg_%s_stretchBlend_%s_utl' %
                        (self.name, segNum, num))
                    if x != 0:
                        paramExtendOffset = coreUtils.add(
                            [
                                paramMult.output,
                                mpList[-1]['mpNodes'][0].uValue
                            ],
                            name='%s_seg_%s_paramExtendOffset_%s_utl' %
                            (self.name, segNum, num))
                        paramExtendOffset.output1D.connect(blend.input[0])

                        paramMultOffset = coreUtils.add(
                            [
                                paramMult.input1,
                                mpList[-1]['mpNodes'][0].uValue
                            ],
                            name='%s_seg_%s_paramMultOffset_%s_utl' %
                            (self.name, segNum, num))
                        paramMultOffset.output1D.connect(blend.input[1])
                    else:
                        paramMult.output.connect(blend.input[0])
                        paramMult.input1.connect(blend.input[1])

                    blendCond.outColorR.connect(blend.attributesBlender)
                    blend.output.connect(mp.uValue)
                else:
                    if x != 0:
                        mpList[-2]['mpNodes'][-1].uValue.connect(mp.uValue)

                mtx = pmc.createNode('composeMatrix',
                                     name='%s_seg_%s_worldMtx_%s_utl' %
                                     (self.name, segNum, num))
                mp.allCoordinates.connect(mtx.inputTranslate)
                mp.rotate.connect(mtx.inputRotate)
                baseSrt.outputScale.connect(mtx.inputScale)
                inverseMtx = pmc.createNode(
                    'inverseMatrix',
                    name='%s_seg_%s_worldInverseMtx_%s_utl' %
                    (self.name, segNum, num))
                mtx.outputMatrix.connect(inverseMtx.inputMatrix)

                pairBlends['pbMtx'].append(mtx)
                pairBlends['pbInverseMtx'].append(inverseMtx)

            # Build matrix chain and fk controls
            self.fkCtrls = []
            buffers = []
            d = None
            srtList = []

            for i in range(numFkCtrls * jointsPerCtrl):
                num = str(i + 1).zfill(2)
                ctrlNum = str((i / jointsPerCtrl) + 1).zfill(2)
                b = coreUtils.addChild(
                    self.interfaceGrp, 'group',
                    '%s_seg_%s_fk_buffer_%s_srt' % (self.name, segNum, num))
                buffers.append(b)
                allBuffers.append(b)
                if i % jointsPerCtrl == 0:
                    c = controls.circleBumpCtrl(name='%s_seg_%s_fk_%s_ctrl' %
                                                (self.name, segNum, ctrlNum),
                                                radius=ctrlSize * .5 -
                                                (i * .02) - (x * .1),
                                                axis=axis)

                    c.setParent(b)
                    self.fkCtrls.append(c)
                    self.ctrls.append(c)
                else:
                    b.setParent(self.rigGrp)

                if i != 0:
                    multMtx = None
                    ctrl = self.fkCtrls[-1]
                    if i % jointsPerCtrl == 0:
                        ctrl = self.fkCtrls[-2]
                    multMtx = coreUtils.multiplyMatrices(
                        [
                            pairBlends['pbMtx'][i].outputMatrix,
                            pairBlends['pbInverseMtx'][i - 1].outputMatrix,
                            ctrl.matrix, buffers[-2].worldMatrix[0]
                        ],
                        name='%s_localIkToFkMtx_%s_utl' % (self.name, num))

                    d = coreUtils.decomposeMatrix(
                        multMtx.matrixSum,
                        name='%s_seg_%s_ikToFkMtxToSrt_%s_utl' %
                        (self.name, segNum, num))
                else:
                    if x == 0:
                        d = coreUtils.decomposeMatrix(
                            pairBlends['pbMtx'][0].outputMatrix,
                            name='%s_seg_%s_ikToFkMtxToSrt_%s_utl' %
                            (self.name, segNum, num))
                    else:
                        d = coreUtils.decomposeMatrix(
                            allBuffers[-2].worldMatrix[0],
                            name='%s_seg_%s_ikToFkMtxToSrt_%s_utl' %
                            (self.name, segNum, num))
                    settingsCtrl.setParent(b)
                d.outputTranslate.connect(b.t)
                d.outputRotate.connect(b.r)
                d.outputScale.connect(b.s)
                srtList.append(d)

            widthOffset = coreUtils.add(
                [settingsCtrl.width, settingsCtrl.taper, 1],
                name='%s_%s_widthOffset_utl' % (self.name, segNum))
            widthMult = pmc.createNode('multDoubleLinear',
                                       name='%s_%s_widthMult_utl' %
                                       (self.name, segNum))
            widthOffset.output1D.connect(widthMult.input1)
            baseSrt.outputScaleX.connect(widthMult.input2)

            # Create joints
            for i in range(numFkCtrls * jointsPerCtrl):
                num = str(i + 1).zfill(2)
                j = coreUtils.addChild(
                    self.deformGrp, 'joint',
                    '%s_seg_%s_%s_dfm' % (self.name, segNum, num))
                srtList[i].outputTranslate.connect(j.t)
                srtList[i].outputRotate.connect(j.r)
                taperMult = coreUtils.convert(settingsCtrl.taper,
                                              i * .1,
                                              name='%s_%s_taperMult_%s_utl' %
                                              (self.name, segNum, num))
                taperAmount = coreUtils.add(
                    [widthOffset.output1D, taperMult.output],
                    name='%s_%s_taperAmount_%s_utl' % (self.name, segNum, num))
                taperAmount.output1D.connect(j.sx)
                taperAmount.output1D.connect(j.sy)
                taperAmount.output1D.connect(j.sz)
                scaleAttr = pmc.Attribute('%s.s%s' % (j.name(), axis[-1]))
                srtList[i].outputScaleX.connect(scaleAttr, f=1)
示例#3
0
def connectIO(dest, source, connectionName):
    '''
    checks for an output from source. If it finds one, creates a corresponding input on dest's component input group
    If an input already exists it will be used instead. Also creates an offset group under the input which
    is the node to decompose and connect things to within the component
    :param dest: node to drive from the new input (usually a ctrl's buffer_srt
    :param source: node to connect the input to
    :param connectionName: name for the new input connection
    :return: offset group under new input node
    '''
    if dest.getParent() == getComponentGroup(dest, 'input'):
        # check whether source is in worldspace. If so apply a direct connection
        offset = coreUtils.addChild(
            getComponentGroup(dest, 'input'), 'group',
            '%s_%s_in_srt' % (getComponentFromName(dest), connectionName))
        if source.worldMatrix.get() == source.matrix.get():
            source.t.connect(offset.t)
            source.r.connect(offset.r)
            source.s.connect(offset.s)
        else:
            d = coreUtils.isDecomposed(source)
            coreUtils.connectDecomposedMatrix(d, offset)
        dest.setParent(offset)
    elif getComponentFromName(dest) == getComponentFromName(source):
        if dest.getParent() == getComponentGroup(
                dest, 'interface') or dest.getParent() == getComponentGroup(
                    dest, 'rig'):

            print 'creating rig input'
            # This means source and dest are in the same component and a target can be added to the rig group
            offset = coreUtils.createAlignedNode(
                dest, 'group', '%s_%s_%sOffset_srt' %
                (getComponentFromName(dest), connectionName,
                 dest.name().split('_')[2]))
            rels = pmc.listRelatives(getComponentGroup(dest, 'rig'), ad=1, c=1)
            if source in rels:
                offset.setParent(source)
            else:
                input = coreUtils.addChild(
                    getComponentGroup(dest, 'rig'), 'group', '%s_%s_%s_srt' %
                    (getComponentFromName(dest), connectionName,
                     dest.name().split('_')[2]))
                if source.worldMatrix.get() == source.matrix.get():
                    source.t.connect(input.t)
                    source.r.connect(input.r)
                    source.s.connect(input.s)
                else:
                    d = coreUtils.isDecomposed(source)
                    coreUtils.connectDecomposedMatrix(d, input)
                offset.setParent(input)
            d = coreUtils.isDecomposed(offset)
            coreUtils.connectDecomposedMatrix(d, dest)
    else:
        output = getOutput(source)
        if not output:
            output = exposeOutput(source)
        input = getInput(dest, output)
        print 'creating new input'
        input = exposeInput(dest, output, connectionName)
        conns = pmc.listConnections(dest.t, d=0, type='decomposeMatrix')
        offset = None
        if conns:
            offset = pmc.listConnections(conns[0].inputMatrix, d=0)[0]
            if offset.getParent() != input:
                offset.setParent(input)
                offset.rename(offset.getParent().name().replace(
                    '_srt', '_%sOffset_srt' % dest.name().split('_')[2]))
        else:
            offset = coreUtils.createAlignedNode(
                dest, 'group', '%s_%s_in_%sOffset_srt' %
                (getComponentFromName(dest), connectionName,
                 dest.name().split('_')[2]))
            offset.setParent(input)

            # Check whether dest is in worldspace. If so, use a direct connection. Otherwise, multiply by parent mtx
            if dest.worldMatrix.get() != dest.matrix.get():
                m = coreUtils.multiplyMatrices(
                    [
                        offset.worldMatrix[0],
                        dest.getParent().worldInverseMatrix
                    ], '%s_%s_localMtx_utl' %
                    (getComponentFromName(dest), connectionName))
                d = coreUtils.decomposeMatrix(
                    m.matrixSum, '%s_%s_localMtxToSrt_utl' %
                    (getComponentFromName(dest), connectionName))
                coreUtils.connectDecomposedMatrix(d, dest)
            else:
                d = coreUtils.isDecomposed(offset)
                coreUtils.connectDecomposedMatrix(d, dest)
        return offset
示例#4
0
    def build(self, numDivisions, start, end, addMidControls, addEndControls):
        axisDict = {0:'x', 1:'y', 2:'z'}
        ctrlSize = coreUtils.getDistance(start, end) * .25

        # create inputs - these should be connected to the nodes you wish to drive the twistSegment
        self.startIn = coreUtils.addChild(self.inputGrp, 'group', '%s_start_in_srt' % self.name)
        coreUtils.align(self.startIn, start)
        self.endIn = coreUtils.addChild(self.startIn, 'group', '%s_end_in_srt' % self.name)
        coreUtils.align(self.endIn, end)
        endTranslateList = [abs(attr.get()) for attr in [self.endIn.tx, self.endIn.ty, self.endIn.tz]]
        axis = axisDict[endTranslateList.index(max(endTranslateList))]
        upAxis = 'x'
        if axis in upAxis:
            upAxis = 'y'
        if pmc.getAttr('%s.t%s' % (self.endIn.name(), axis)) < 0.0:
            axis = '-%s' % axis
        self.endIn.setParent(self.inputGrp)

        print 'Axis = %s' % axis


        # build curve
        crv = curveUtils.curveBetweenNodes(start=self.startIn, end=self.endIn, name='%s_crv' % self.name)
        crv.setParent(self.rigGrp)

        # create attributes on main grp
        pmc.addAttr(self.mainGrp, ln='startAuto', at='double', minValue=0, maxValue=1, k=1, h=0)
        pmc.addAttr(self.mainGrp, ln='endAuto', at='double', minValue=0, maxValue=1, k=1, h=0)
        pmc.addAttr(self.mainGrp, ln='twist', at='double')
        pmc.addAttr(self.mainGrp, ln='invertTwist', at=bool, k=0, h=0)

        # world space srt of start and end
        startToSrt = coreUtils.decomposeWorldMatrix(self.startIn)
        endToSrt = coreUtils.decomposeWorldMatrix(self.endIn)

        # Vector representing direction from start to end
        cmpntVec = None
        if '-' in axis:
            cmpntVec = coreUtils.minus([startToSrt.outputTranslate, endToSrt.outputTranslate],'%s_cmpntVector_utl' % self.name)
        else:
            cmpntVec = coreUtils.minus([endToSrt.outputTranslate, startToSrt.outputTranslate], '%s_cmpntVector_utl' % self.name)


        # matrix representing cmpntVec using start as upnode
        cmpntVecNorm = coreUtils.normalizeVector(cmpntVec.output3D, name='%s_cmpntVectorNormalized_utl' % self.name)
        cmpntUpVec = coreUtils.matrixAxisToVector(self.startIn, axis=upAxis, name='%s_cmpntUpVec_utl' % self.name)
        normVec = coreUtils.cross(cmpntVecNorm.output, cmpntUpVec.output, name='%s_localNormalVec_utl' % self.name)

        orderDict = {'x': 0, 'y': 1, 'z': 2, '-x': 0, '-y': 1, '-z': 2}
        matrixList = ['', '', '']
        matrixList[orderDict[axis]] = 'X'
        matrixList[orderDict[upAxis]] = 'Y'

        localOrientMtx = pmc.createNode('fourByFourMatrix', name='%s_localOrientMatrix_utl' % self.name)
        cmpntVecNorm.outputX.connect(pmc.Attribute('%s.in%s0' % (localOrientMtx.name(), matrixList.index('X'))))
        cmpntVecNorm.outputY.connect(pmc.Attribute('%s.in%s1' % (localOrientMtx.name(), matrixList.index('X'))))
        cmpntVecNorm.outputZ.connect(pmc.Attribute('%s.in%s2' % (localOrientMtx.name(), matrixList.index('X'))))

        cmpntUpVec.outputX.connect(pmc.Attribute('%s.in%s0' % (localOrientMtx.name(), matrixList.index('Y'))))
        cmpntUpVec.outputY.connect(pmc.Attribute('%s.in%s1' % (localOrientMtx.name(), matrixList.index('Y'))))
        cmpntUpVec.outputZ.connect(pmc.Attribute('%s.in%s2' % (localOrientMtx.name(), matrixList.index('Y'))))

        normVec.outputX.connect(pmc.Attribute('%s.in%s0' % (localOrientMtx.name(), matrixList.index(''))))
        normVec.outputY.connect(pmc.Attribute('%s.in%s1' % (localOrientMtx.name(), matrixList.index(''))))
        normVec.outputZ.connect(pmc.Attribute('%s.in%s2' % (localOrientMtx.name(), matrixList.index(''))))

        startToSrt.outputTranslateX.connect(localOrientMtx.in30)
        startToSrt.outputTranslateY.connect(localOrientMtx.in31)
        startToSrt.outputTranslateZ.connect(localOrientMtx.in32)


        # matrix representing positional offset of first control
        startEndDist = coreUtils.distanceBetweenNodes(self.startIn, self.endIn, name='%s_startEndDist_utl' % self.name)
        mult = .333
        if '-' in axis:
            mult = -.333
        startLocalOffsetMult = coreUtils.multiply(startEndDist.distance, mult, name='%s_startLocalOffsetMult_utl' % self.name)
        startLocalOffsetMtx = pmc.createNode('fourByFourMatrix', name='%s_startLocalOffsetMtx_utl' % self.name)
        startLocalOffsetMult.outputX.connect('%s.in3%s' % (startLocalOffsetMtx.name(), orderDict[axis[-1]]))

        # Matrices that convert local positional offset into either local orient space or start space
        startLocalMtx = coreUtils.multiplyMatrices([startLocalOffsetMtx.output, localOrientMtx.output],
                                                    name='%s_startLocalMtx_utl' % self.name)
        startLocalMtxToSrt = coreUtils.decomposeMatrix(startLocalMtx.matrixSum, name='%s_startLocalMtxToSrt_utl' % self.name)

        startAutoMtx = coreUtils.multiplyMatrices([startLocalOffsetMtx.output, self.startIn.worldMatrix[0]],
                                                   name='%s_startAutoMtx_utl' % self.name)
        startAutoMtxToSrt = coreUtils.decomposeMatrix(startAutoMtx.matrixSum, name='%s_startAutoMtxToSrt_utl' % self.name)

        startBlend = coreUtils.pairBlend(startLocalMtxToSrt.outputTranslate,
                                         startLocalMtxToSrt.outputRotate,
                                         startAutoMtxToSrt.outputTranslate,
                                         startAutoMtxToSrt.outputRotate,
                                         name = '%s_startAutoBlend_utl' % self.name,
                                         blendAttr=self.mainGrp.startAuto)

        # matrix representing positional offset of second control
        mult = mult *-1
        endLocalOffsetMult = coreUtils.multiply(startEndDist.distance, mult,
                                                  name='%s_endLocalOffsetMult_utl' % self.name)
        endLocalOffsetMtx = pmc.createNode('fourByFourMatrix', name='%s_endLocalOffsetMtx_utl' % self.name)
        endLocalOffsetMult.outputX.connect('%s.in3%s' % (endLocalOffsetMtx.name(), orderDict[axis[-1]]))

        # Matrices that convert local positional offset into either local orient space or start space
        endLocalMtx = coreUtils.multiplyMatrices([endLocalOffsetMtx.output, localOrientMtx.output],
                                                   name='%s_endLocalMtx_utl' % self.name)
        endLocalMtxToSrt = coreUtils.decomposeMatrix(endLocalMtx.matrixSum,
                                                       name='%s_endLocalMtxToSrt_utl' % self.name)

        endLocalPos = pmc.createNode('plusMinusAverage', name='%s_endLocalPos_utl' % self.name)
        if '-' in axis:
            endLocalPos.operation.set(2)
        endLocalMtxToSrt.outputTranslate.connect(endLocalPos.input3D[0])
        cmpntVec.output3D.connect(endLocalPos.input3D[1])

        endAutoMtx = coreUtils.multiplyMatrices([endLocalOffsetMtx.output, self.endIn.worldMatrix[0]],
                                                  name='%s_endAutoMtx_utl' % self.name)
        endAutoMtxToSrt = coreUtils.decomposeMatrix(endAutoMtx.matrixSum,
                                                      name='%s_endAutoMtxToSrt_utl' % self.name)

        endBlend = coreUtils.pairBlend(endLocalPos.output3D,
                                       endLocalMtxToSrt.outputRotate,
                                       endAutoMtxToSrt.outputTranslate,
                                       endAutoMtxToSrt.outputRotate,
                                       name='%s_endAutoBlend_utl' % self.name,
                                       blendAttr=self.mainGrp.endAuto)



        # Motion path
        mps = curveUtils.nodesAlongCurve(crv=crv,
                                         numNodes=numDivisions,
                                         name=self.name,
                                         followAxis=axis,
                                         upAxis=upAxis,
                                         upNode=self.startIn,
                                         upVec=upAxis,
                                         follow=1,
                                         groups=0)

        # twist inversion
        cond = pmc.createNode('condition', name='%s_twistIsInverted_utl' % self.name)
        self.mainGrp.twist.connect(cond.colorIfFalseR)
        uc = coreUtils.convert(self.mainGrp.twist, -1, name='%s_twistInvert_utl' % self.name)
        uc.output.connect(cond.colorIfTrueR)
        self.mainGrp.invertTwist.connect(cond.firstTerm)
        cond.secondTerm.set(1)

        # joints
        for i in range(numDivisions):
            num = str(i + 1).zfill(2)
            mp = mps['mpNodes'][i]
            j = pmc.joint(name='%s_%s_dfm' % (self.name, num))
            j.setParent(self.deformGrp)
            mp.allCoordinates.connect(j.t)
            mp.rotate.connect(j.jointOrient)
            twistBlend = pmc.createNode('animBlendNodeAdditiveRotation', name='%s_%s_twistBlend_utl' % (self.name, num))
            attr = pmc.Attribute('%s.inputA%s' % (twistBlend.name(), axis[-1].upper()))
            cond.outColorR.connect(attr)
            if not '-' in axis:
                twistBlend.weightA.set(mp.uValue.get() * -1)
            else:
                twistBlend.weightA.set(mp.uValue.get())
            twistBlend.output.connect(j.r)

        #twisting
        orientInverseMtx = pmc.createNode('inverseMatrix', name='%s_localOrientInverseMatrix_utl' % self.name)
        localOrientMtx.output.connect(orientInverseMtx.inputMatrix)
        twist = coreUtils.isolateTwist(self.endIn.worldMatrix[0], orientInverseMtx.outputMatrix, name=self.name, axis=axis)
        twistAttr = pmc.Attribute('%s.outputRotate%s' % (twist[2].name(), axis[-1].upper()))
        twistAttr.connect(self.mainGrp.twist)

        crvShape = pmc.listRelatives(crv, c=1, s=1)[0]
        startToSrt.outputTranslate.connect(crvShape.controlPoints[0])
        endToSrt.outputTranslate.connect(crvShape.controlPoints[3])

        # bend controls
        if addMidControls:
            startCtrl = controls.squareCtrl(name='%s_start_ctrl' % self.name, axis=axis[-1], size=ctrlSize)
            startBuffer = coreUtils.addParent(startCtrl, 'group', '%s_startCtrl_buffer_srt' % self.name)
            startBuffer.setParent(self.interfaceGrp)
            startCtrlToSrt = coreUtils.decomposeMatrix(startCtrl.worldMatrix[0], name='%s_startCtrlWorldMtxToSrt_utl' % self.name)
            startBlend.outTranslate.connect(startBuffer.t)
            startBlend.outRotate.connect(startBuffer.r)
            self.ctrls.append(startCtrl)

            endCtrl = controls.squareCtrl(name='%s_end_ctrl' % self.name, axis=axis[-1], size=ctrlSize)
            endBuffer = coreUtils.addParent(endCtrl, 'group', '%s_endCtrl_buffer_srt' % self.name)
            endBuffer.setParent(self.interfaceGrp)
            endCtrlToSrt = coreUtils.decomposeMatrix(endCtrl.worldMatrix[0], name='%s_startendCtrlWorldMtxToSrt_utl' % self.name)
            endBlend.outTranslate.connect(endBuffer.t)
            endBlend.outRotate.connect(endBuffer.r)
            self.ctrls.append(endCtrl)

            startCtrlToSrt.outputTranslate.connect(crvShape.controlPoints[1])
            endCtrlToSrt.outputTranslate.connect(crvShape.controlPoints[2])
        else:
            startBlend.outTranslate.connect(crvShape.controlPoints[1])
            endBlend.outTranslate.connect(crvShape.controlPoints[2])

        if addEndControls:
            self.btmCtrl = controls.circleBumpCtrl(name='%s_btm_ctrl' % self.name, axis=axis, radius=ctrlSize)
            coreUtils.align(self.btmCtrl, self.startIn)
            btmBuffer = coreUtils.addParent(self.btmCtrl, 'group', '%s_btm_buffer_srt' % self.name)
            btmBuffer.setParent(self.interfaceGrp)
            d = coreUtils.isDecomposed(self.btmCtrl)
            coreUtils.connectDecomposedMatrix(d, self.startIn)
            self.ctrls.append(self.btmCtrl)

            self.topCtrl = controls.circleBumpCtrl(name='%s_top_ctrl' % self.name, axis=axis, radius=ctrlSize)
            coreUtils.align(self.topCtrl, self.endIn)
            topBuffer = coreUtils.addParent(self.topCtrl, 'group', '%s_top_buffer_srt' % self.name)
            topBuffer.setParent(self.interfaceGrp)
            d = coreUtils.isDecomposed(self.topCtrl)
            coreUtils.connectDecomposedMatrix(d, self.endIn)
            self.ctrls.append(self.topCtrl)
示例#5
0
    def build(self, start, end, numFkCtrls, jointsPerCtrl, numIkCtrls, axis,
              upAxis, bias, doubleIkChain):
        start, end = coreUtils.getStartAndEnd(start, end)
        ctrlSize = coreUtils.getDistance(start, end) * .2
        # Build ik curves
        ikCrvA = curveUtils.curveBetweenNodes(start,
                                              end,
                                              numCVs=numIkCtrls,
                                              name='%s_ik_A_crv' % self.name)
        ikCrvA.setParent(self.rigGrp)
        if doubleIkChain:
            ikCrvB = curveUtils.curveBetweenNodes(start,
                                                  end,
                                                  numCVs=numIkCtrls,
                                                  name='%s_ik_B_crv' %
                                                  self.name)
            ikCrvB.setParent(self.rigGrp)

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

        aimMtx = coreUtils.getAimMatrix(start=start,
                                        end=end,
                                        axis=axis,
                                        upAxis=upAxis,
                                        worldUpAxis=upAxis)
        startSrt = coreUtils.matrixToSrt(aimMtx)
        baseBuffer.t.set(startSrt['translate'])
        baseBuffer.r.set(startSrt['rotate'])

        if doubleIkChain:
            pmc.addAttr(baseCtrl,
                        ln='A_B_blend',
                        at='double',
                        k=1,
                        h=0,
                        minValue=0.0,
                        maxValue=1.0)
        pmc.addAttr(baseCtrl,
                    ln='stretch',
                    at='double',
                    k=1,
                    h=0,
                    minValue=0.0,
                    maxValue=1.0)
        pmc.addAttr(baseCtrl,
                    ln='pin',
                    at='enum',
                    enumName='head:tail',
                    k=1,
                    h=0)
        pmc.addAttr(baseCtrl,
                    ln='extend',
                    at='double',
                    k=1,
                    h=0,
                    minValue=0.0,
                    maxValue=1.0)
        pmc.addAttr(baseCtrl, ln='twist', at='double', k=1, h=0)
        pmc.addAttr(baseCtrl,
                    ln='upVector',
                    at='enum',
                    enumName='x:y:z',
                    k=1,
                    h=0)
        baseCtrl.extend.set(1)

        # ik ctrls
        cvsA = ikCrvA.getCVs(space='world')
        self.ikACtrls = []
        if doubleIkChain:
            cvsB = ikCrvB.getCVs(space='world')
            self.ikBCtrls = []
        for i in range(numIkCtrls):
            num = str(i).zfill(2)
            if i > 0:
                c = controls.squareCtrl(size=ctrlSize * 1.5,
                                        name='%s_ik_%s_A_ctrl' %
                                        (self.name, num),
                                        axis=axis)
                b = coreUtils.addParent(
                    c, 'group', '%s_ik_buffer_A_%s_srt' % (self.name, num))
                b.t.set(cvsA[i])
                b.setParent(self.interfaceGrp)
                d = coreUtils.decomposeMatrix(
                    c.worldMatrix[0],
                    name='%s_ikWorldMtxToSrt_A_%s_utl' % (self.name, num))
                d.outputTranslate.connect(ikCrvA.controlPoints[i])
                componentUtils.addSpaceSwitch(node=b,
                                              name='ik_%s' % num,
                                              spaces=['base'],
                                              type='parent',
                                              ctrlNode=c,
                                              targetNodes=[baseCtrl])
                self.ctrls.append(c)
                self.ikACtrls.append(c)

                if doubleIkChain:
                    c = controls.squareCtrl(size=ctrlSize * 1.25,
                                            name='%s_ik_%s_B_ctrl' %
                                            (self.name, num),
                                            axis=axis)
                    b = coreUtils.addParent(
                        c, 'group', '%s_ik_buffer_B_%s_srt' % (self.name, num))
                    b.t.set(cvsB[i])
                    b.setParent(self.interfaceGrp)
                    d = coreUtils.decomposeMatrix(
                        c.worldMatrix[0],
                        name='%s_ikWorldMtxToSrt_B_%s_utl' % (self.name, num))
                    d.outputTranslate.connect(ikCrvB.controlPoints[i])
                    componentUtils.addSpaceSwitch(node=b,
                                                  name='ik_%s' % num,
                                                  spaces=['base'],
                                                  type='parent',
                                                  ctrlNode=c,
                                                  targetNodes=[baseCtrl])

                    self.ikBCtrls.append(c)
                    self.ctrls.append(c)
            else:
                baseSrt.outputTranslate.connect(ikCrvA.controlPoints[0])
                if doubleIkChain:
                    baseSrt.outputTranslate.connect(ikCrvB.controlPoints[0])

        # Arclen stuff for stretching vs maintaining length
        stretchA = curveUtils.getCurveStretch(ikCrvA, name='%s_A' % self.name)
        blendACond = pmc.createNode('condition',
                                    name='%s_stretchIsNegativeA_utl' %
                                    self.name)
        stretchA['stretchFactor'].outputX.connect(blendACond.firstTerm)
        self.mainGrp.globalScale.connect(stretchA['globalScaleFactor'].input1X)
        #self.mainGrp.globalScale.connect(blendACond.secondTerm)
        blendACond.operation.set(2)
        blendACond.secondTerm.set(1.0)
        blendACond.colorIfTrueR.set(1)
        baseCtrl.stretch.connect(blendACond.colorIfFalseR)
        if doubleIkChain:
            stretchB = curveUtils.getCurveStretch(ikCrvB,
                                                  name='%s_B' % self.name)
            blendBCond = pmc.createNode('condition',
                                        name='%s_stretchIsNegativeB_utl' %
                                        self.name)
            stretchB['stretchFactor'].outputX.connect(blendBCond.firstTerm)
            self.mainGrp.globalScale.connect(
                stretchB['globalScaleFactor'].input1X)
            #self.mainGrp.globalScale.connect(blendBCond.secondTerm)
            blendBCond.secondTerm.set(1.0)
            blendBCond.operation.set(2)
            blendBCond.colorIfTrueR.set(1)
            baseCtrl.stretch.connect(blendBCond.colorIfFalseR)

        # Motion Path nodes
        upVecX = pmc.createNode('colorConstant',
                                name='%s_upVecX_utl' % self.name)
        upVecX.inColor.set((1, 0, 0))
        upVecY = pmc.createNode('colorConstant',
                                name='%s_upVecY_utl' % self.name)
        upVecY.inColor.set((0, 1, 0))
        upVecZ = pmc.createNode('colorConstant',
                                name='%s_upVecZ_utl' % self.name)
        upVecZ.inColor.set((0, 0, 1))
        upVecChoice = pmc.createNode('choice',
                                     name='%s_upVecChoice_utl' % self.name)
        upVecX.outColor.connect(upVecChoice.input[0])
        upVecY.outColor.connect(upVecChoice.input[1])
        upVecZ.outColor.connect(upVecChoice.input[2])

        baseCtrl.upVector.connect(upVecChoice.selector)
        mpsA = curveUtils.nodesAlongCurve(ikCrvA,
                                          numNodes=numFkCtrls * jointsPerCtrl,
                                          name='%s_A' % self.name,
                                          followAxis=axis,
                                          upAxis=upAxis,
                                          upNode=baseCtrl,
                                          follow=1,
                                          groups=0)

        if doubleIkChain:
            mpsB = curveUtils.nodesAlongCurve(ikCrvB,
                                              numNodes=numFkCtrls *
                                              jointsPerCtrl,
                                              name='%s_B' % self.name,
                                              followAxis=axis,
                                              upAxis=upAxis,
                                              upNode=baseCtrl,
                                              follow=1,
                                              groups=0)
        # Parameter values
        paramVals = [mp.uValue.get() for mp in mpsA['mpNodes']]
        if bias:
            for i in range(len(paramVals)):
                paramVals[i] += paramVals[i] - pow(paramVals[i], 1 + bias)

        pairBlends = {'pb': [], 'pbMtx': [], 'pbInverseMtx': []}

        for i in range(numFkCtrls * jointsPerCtrl):
            num = str(i + 1).zfill(2)
            mpA = mpsA['mpNodes'][i]
            baseCtrl.upVector.connect(mpA.upAxis)
            upVecChoice.output.connect(mpA.worldUpVector)
            uc = coreUtils.convert(
                baseCtrl.twist, ((.0174533 / numFkCtrls * jointsPerCtrl) * i),
                name='%s_twistMult_%s_utl' % (self.name, num))
            uc.output.connect(mpA.frontTwist)
            paramExtendMult = pmc.createNode(
                'multDoubleLinear',
                name='%s_paramExtendMult_%s_A_utl' % (self.name, num))
            paramMult = pmc.createNode('multDoubleLinear',
                                       name='%s_paramMult_%s_A_utl' %
                                       (self.name, num))
            paramExtendMult.input1.set(paramVals[i])
            baseCtrl.extend.connect(paramExtendMult.input2)
            paramExtendMult.output.connect(paramMult.input1)
            stretchA['stretchFactor'].outputX.connect(paramMult.input2)
            blendA = pmc.createNode('blendTwoAttr',
                                    name='%s_stretchBlend_%s_A_utl' %
                                    (self.name, num))
            paramMult.output.connect(blendA.input[0])
            paramMult.input1.connect(blendA.input[1])

            blendACond.outColorR.connect(blendA.attributesBlender)
            blendA.output.connect(mpA.uValue)

            if doubleIkChain:
                mpB = mpsB['mpNodes'][i]
                baseCtrl.upVector.connect(mpB.upAxis)
                upVecChoice.output.connect(mpB.worldUpVector)
                uc.output.connect(mpB.frontTwist)
                paramMult = pmc.createNode('multDoubleLinear',
                                           name='%s_paramMult_%s_B_utl' %
                                           (self.name, num))
                paramExtendMult.output.connect(paramMult.input1)
                stretchB['stretchFactor'].outputX.connect(paramMult.input2)
                blendB = pmc.createNode('blendTwoAttr',
                                        name='%s_stretchBlend_%s_B_utl' %
                                        (self.name, num))
                paramMult.output.connect(blendB.input[0])
                paramMult.input1.connect(blendB.input[1])
                blendBCond.outColorR.connect(blendB.attributesBlender)
                blendB.output.connect(mpB.uValue)

                rv = pmc.createNode('remapValue',
                                    name='%s_blendRemap_%s_utl' %
                                    (self.name, num))
                baseCtrl.A_B_blend.connect(rv.inputValue)
                rv.value[0].value_Interp.set(2)
                startPos = (1.0 / (numFkCtrls * jointsPerCtrl - 1)) * i * .67
                endPos = startPos + .33
                rv.value[0].value_Position.set(startPos)
                rv.value[1].value_Position.set(endPos)

                pb = coreUtils.pairBlend(mpA.allCoordinates,
                                         mpA.rotate,
                                         mpB.allCoordinates,
                                         mpB.rotate,
                                         '%s_curveBlend_%s_utl' %
                                         (self.name, num),
                                         blendAttr=rv.outValue)
                pbMtx = pmc.createNode('composeMatrix',
                                       name='%s_worldMtx_%s_utl' %
                                       (self.name, num))
                pb.outTranslate.connect(pbMtx.inputTranslate)
                pb.outRotate.connect(pbMtx.inputRotate)
                baseSrt.outputScale.connect(pbMtx.inputScale)
                pbInverseMtx = pmc.createNode(
                    'inverseMatrix',
                    name='%s_worldInverseMtx_%s_utl' % (self.name, num))
                pbMtx.outputMatrix.connect(pbInverseMtx.inputMatrix)

                pairBlends['pb'].append(pb)
                pairBlends['pbMtx'].append(pbMtx)
                pairBlends['pbInverseMtx'].append(pbInverseMtx)
            else:
                mtx = pmc.createNode('composeMatrix',
                                     name='%s_worldMtx_%s_utl' %
                                     (self.name, num))
                mpA.allCoordinates.connect(mtx.inputTranslate)
                mpA.rotate.connect(mtx.inputRotate)
                baseSrt.outputScale.connect(mtx.inputScale)
                inverseMtx = pmc.createNode('inverseMatrix',
                                            name='%s_worldInverseMtx_%s_utl' %
                                            (self.name, num))
                mtx.outputMatrix.connect(inverseMtx.inputMatrix)

                pairBlends['pbMtx'].append(mtx)
                pairBlends['pbInverseMtx'].append(inverseMtx)

        # Build matrix chain and fk controls
        self.fkCtrls = []
        buffers = []
        d = None
        srtList = []

        for i in range(numFkCtrls * jointsPerCtrl):
            num = str(i + 1).zfill(2)
            ctrlNum = str((i / jointsPerCtrl) + 1).zfill(2)
            b = coreUtils.addChild(self.interfaceGrp, 'group',
                                   '%s_fk_buffer_%s_srt' % (self.name, num))
            buffers.append(b)
            if i % jointsPerCtrl == 0:
                c = controls.circleBumpCtrl(name='%s_fk_%s_ctrl' %
                                            (self.name, ctrlNum),
                                            radius=ctrlSize * .5,
                                            axis=axis)

                c.setParent(b)
                self.fkCtrls.append(c)
                self.ctrls.append(c)
            else:
                b.setParent(self.rigGrp)

            if i != 0:
                multMtx = None
                ctrl = self.fkCtrls[-1]
                if i % jointsPerCtrl == 0:
                    ctrl = self.fkCtrls[-2]
                multMtx = coreUtils.multiplyMatrices(
                    [
                        pairBlends['pbMtx'][i].outputMatrix,
                        pairBlends['pbInverseMtx'][i - 1].outputMatrix,
                        ctrl.matrix, buffers[-2].worldMatrix[0]
                    ],
                    name='%s_localIkToFkMtx_%s_utl' % (self.name, num))

                d = coreUtils.decomposeMatrix(multMtx.matrixSum,
                                              name='%s_ikToFkMtxToSrt_%s_utl' %
                                              (self.name, num))
            else:
                d = coreUtils.decomposeMatrix(
                    pairBlends['pbMtx'][0].outputMatrix,
                    name='%s_ikToFkMtxToSrt_%s_utl' % (self.name, num))
            d.outputTranslate.connect(b.t)
            d.outputRotate.connect(b.r)
            d.outputScale.connect(b.s)
            srtList.append(d)

        # Create joints
        for i in range(numFkCtrls * jointsPerCtrl):
            num = str(i + 1).zfill(2)
            j = coreUtils.addChild(self.deformGrp, 'joint',
                                   '%s_%s_dfm' % (self.name, num))
            srtList[i].outputTranslate.connect(j.t)
            srtList[i].outputRotate.connect(j.r)
            srtList[i].outputScale.connect(j.s)