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