def addOperators(self): """Create operators and set the relations for the component rig Apply operators, constraints, expressions to the hierarchy. In order to keep the code clean and easier to debug, we shouldn't create any new object in this method. """ # 1 bone chain Upv ref ============================================== self.ikHandleUpvRef = primitive.addIkHandle( self.root, self.getName("ikHandleArmChainUpvRef"), self.armChainUpvRef, "ikSCsolver") pm.pointConstraint(self.ik_ctl, self.ikHandleUpvRef) pm.parentConstraint(self.armChainUpvRef[0], self.upv_cns, mo=True) # Visibilities ------------------------------------- # fk fkvis_node = node.createReverseNode(self.blend_att) for shp in self.fk0_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) for shp in self.fk1_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) for shp in self.fk2_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) # ik for shp in self.upv_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ikcns_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ik_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) if self.settings["ikTR"]: for shp in self.ikRot_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) # Controls ROT order ----------------------------------- attribute.setRotOrder(self.fk0_ctl, "XZY") attribute.setRotOrder(self.fk1_ctl, "XYZ") attribute.setRotOrder(self.fk2_ctl, "YZX") attribute.setRotOrder(self.ik_ctl, "XYZ") # IK Solver ----------------------------------------- out = [self.bone0, self.bone1, self.ctrn_loc, self.eff_loc] o_node = applyop.gear_ikfk2bone_op(out, self.root, self.ik_ref, self.upv_ctl, self.fk_ctl[0], self.fk_ctl[1], self.fk_ref, self.length0, self.length1, self.negate) if self.settings["ikTR"]: # connect the control inputs outEff_dm = o_node.listConnections(c=True)[-1][1] inAttr = self.ikRot_npo.attr("translate") outEff_dm.attr("outputTranslate") >> inAttr outEff_dm.attr("outputScale") >> self.ikRot_npo.attr("scale") dm_node = node.createDecomposeMatrixNode(o_node.attr("outB")) dm_node.attr("outputRotate") >> self.ikRot_npo.attr("rotate") # rotation mulM_node = applyop.gear_mulmatrix_op( self.ikRot_ctl.attr("worldMatrix"), self.eff_loc.attr("parentInverseMatrix")) intM_node = applyop.gear_intmatrix_op(o_node.attr("outEff"), mulM_node.attr("output"), o_node.attr("blend")) dm_node = node.createDecomposeMatrixNode(intM_node.attr("output")) dm_node.attr("outputRotate") >> self.eff_loc.attr("rotate") transform.matchWorldTransform(self.fk2_ctl, self.ikRot_cns) # scale: this fix the scalin popping issue intM_node = applyop.gear_intmatrix_op( self.fk2_ctl.attr("worldMatrix"), self.ik_ctl_ref.attr("worldMatrix"), o_node.attr("blend")) mulM_node = applyop.gear_mulmatrix_op( intM_node.attr("output"), self.eff_loc.attr("parentInverseMatrix")) dm_node = node.createDecomposeMatrixNode(mulM_node.attr("output")) dm_node.attr("outputScale") >> self.eff_loc.attr("scale") pm.connectAttr(self.blend_att, o_node + ".blend") if self.negate: mulVal = -1 else: mulVal = 1 node.createMulNode(self.roll_att, mulVal, o_node + ".roll") pm.connectAttr(self.scale_att, o_node + ".scaleA") pm.connectAttr(self.scale_att, o_node + ".scaleB") pm.connectAttr(self.maxstretch_att, o_node + ".maxstretch") pm.connectAttr(self.slide_att, o_node + ".slide") pm.connectAttr(self.softness_att, o_node + ".softness") pm.connectAttr(self.reverse_att, o_node + ".reverse") # Twist references --------------------------------- pm.pointConstraint(self.mid_ctl_twst_ref, self.tws1_npo, maintainOffset=False) pm.connectAttr(self.mid_ctl.scaleX, self.tws1_loc.scaleX) pm.orientConstraint(self.mid_ctl_twst_ref, self.tws1_npo, maintainOffset=False) o_node = applyop.gear_mulmatrix_op(self.eff_loc.attr( "worldMatrix"), self.root.attr("worldInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputTranslate", self.tws2_npo.attr("translate")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputRotate", self.tws2_npo.attr("rotate")) o_node = applyop.gear_mulmatrix_op( self.eff_loc.attr("worldMatrix"), self.tws2_rot.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") attribute.setRotOrder(self.tws2_rot, "XYZ") pm.connectAttr(dm_node + ".outputRotate", self.tws2_rot + ".rotate") self.tws0_rot.setAttr("sx", .001) self.tws2_rot.setAttr("sx", .001) add_node = node.createAddNode(self.roundness_att, .001) pm.connectAttr(add_node + ".output", self.tws1_rot.attr("sx")) pm.connectAttr(self.armpit_roll_att, self.tws0_rot + ".rotateX") # Roll Shoulder applyop.splineIK(self.getName("rollRef"), self.rollRef, parent=self.root, cParent=self.bone0) # Volume ------------------------------------------- distA_node = node.createDistNode(self.tws0_loc, self.tws1_loc) distB_node = node.createDistNode(self.tws1_loc, self.tws2_loc) add_node = node.createAddNode(distA_node + ".distance", distB_node + ".distance") div_node = node.createDivNode(add_node + ".output", self.root.attr("sx")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(self.root.attr("worldMatrix"), dm_node + ".inputMatrix") div_node2 = node.createDivNode(div_node + ".outputX", dm_node + ".outputScaleX") self.volDriver_att = div_node2 + ".outputX" if self.settings["extraTweak"]: for tweak_ctl in self.tweak_ctl: for shp in tweak_ctl.getShapes(): pm.connectAttr(self.tweakVis_att, shp.attr("visibility")) # Divisions ---------------------------------------- # at 0 or 1 the division will follow exactly the rotation of the # controler.. and we wont have this nice tangent + roll for i, div_cns in enumerate(self.div_cns): if i < (self.settings["div0"] + 1): perc = i * .5 / (self.settings["div0"] + 1.0) elif i < (self.settings["div0"] + 2): perc = .49 elif i < (self.settings["div0"] + 3): perc = .50 elif i < (self.settings["div0"] + 4): perc = .51 else: perc = .5 + \ (i - self.settings["div0"] - 3.0) * .5 / \ (self.settings["div1"] + 1.0) perc = max(.001, min(.990, perc)) # Roll if self.negate: o_node = applyop.gear_rollsplinekine_op( div_cns, [self.tws2_rot, self.tws1_rot, self.tws0_rot], 1 - perc, 40) else: o_node = applyop.gear_rollsplinekine_op( div_cns, [self.tws0_rot, self.tws1_rot, self.tws2_rot], perc, 40) pm.connectAttr(self.resample_att, o_node + ".resample") pm.connectAttr(self.absolute_att, o_node + ".absolute") # Squash n Stretch o_node = applyop.gear_squashstretch2_op( div_cns, None, pm.getAttr(self.volDriver_att), "x") pm.connectAttr(self.volume_att, o_node + ".blend") pm.connectAttr(self.volDriver_att, o_node + ".driver") pm.connectAttr(self.st_att[i], o_node + ".stretch") pm.connectAttr(self.sq_att[i], o_node + ".squash") # match IK/FK ref pm.parentConstraint(self.bone0, self.match_fk0_off, mo=True) pm.parentConstraint(self.bone1, self.match_fk1_off, mo=True) if self.settings["ikTR"]: transform.matchWorldTransform(self.ikRot_ctl, self.match_ikRot) transform.matchWorldTransform(self.fk_ctl[2], self.match_fk2) return
def addOperators(self): # Visibilities ------------------------------------- # fk fkvis_node = nod.createReverseNode(self.blend_att) for shp in self.fk0_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) for shp in self.fk0_roll_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) for shp in self.fk1_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) fkvis2_node = nod.createReverseNode(self.blend2_att) for shp in self.fk2_ctl.getShapes(): pm.connectAttr(fkvis2_node + ".outputX", shp.attr("visibility")) # ik for shp in self.upv_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ikcns_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ik_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) # Controls ROT order ----------------------------------- att.setRotOrder(self.fk0_ctl, "YZX") att.setRotOrder(self.fk0_roll_ctl, "YZX") att.setRotOrder(self.fk1_ctl, "XYZ") att.setRotOrder(self.fk2_ctl, "YZX") # att.setRotOrder(self.ik_ctl, "ZYX") att.setRotOrder(self.ik_ctl, "XYZ") # IK Solver ----------------------------------------- out = [self.bone0, self.bone1, self.ctrn_loc, self.eff_npo] #self.fk_ctl = [self.fk0_roll_ctl, self.fk1_ctl, self.fk2_mtx] node = aop.gear_ikfk2bone_op(out, self.root, self.ik_ref, self.upv_ctl, self.fk_ctl[0], self.fk_ctl[1], self.fk2_mtx, self.length0, self.length1, self.negate) pm.connectAttr(self.blend_att, node + ".blend") pm.connectAttr(self.roll_att, node + ".roll") pm.connectAttr(self.scale_att, node + ".scaleA") pm.connectAttr(self.scale_att, node + ".scaleB") pm.connectAttr(self.maxstretch_att, node + ".maxstretch") pm.connectAttr(self.slide_att, node + ".slide") pm.connectAttr(self.softness_att, node + ".softness") pm.connectAttr(self.reverse_att, node + ".reverse") # auto upvector ------------------------------------- if self.negate: node = aop.aimCns(self.upv_auv, self.ik_ctl, axis="-xy", wupType=4, wupVector=[0, 1, 0], wupObject=self.upv_auv, maintainOffset=False) else: node = aop.aimCns(self.upv_auv, self.ik_ctl, axis="xy", wupType=4, wupVector=[0, 1, 0], wupObject=self.upv_auv, maintainOffset=False) pb_node = pm.createNode("pairBlend") pb_node.attr("rotInterpolation").set(1) pm.connectAttr(self.upv_auv.attr("rotate"), pb_node + ".inRotate2") pm.connectAttr(pb_node + ".outRotate", self.upv_mtx.attr("rotate")) pm.connectAttr(self.auv_att, pb_node + ".weight") # fk2_npo position constraint to effector------------------------ node = aop.gear_mulmatrix_op(self.eff_npo.attr("worldMatrix"), self.fk2_npo.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputTranslate", self.fk2_npo.attr("translate")) # fk2_npo rotation constraint to bone1 (bugfixed) ------------------------ node = aop.gear_mulmatrix_op(self.bone1.attr("worldMatrix"), self.fk2_npo.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputRotate", self.fk2_npo.attr("rotate")) # hand ikfk blending from fk ref to ik ref (serious bugfix)-------------------------------- node = aop.gear_mulmatrix_op(self.fk_ref.attr("worldMatrix"), self.eff_loc.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pb_node = pm.createNode("pairBlend") pb_node.attr("rotInterpolation").set(1) pm.connectAttr(node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputRotate", pb_node + ".inRotate1") pm.connectAttr(self.blend2_att, pb_node + ".weight") pm.connectAttr(pb_node + ".outRotate", self.eff_loc.attr("rotate")) node = aop.gear_mulmatrix_op(self.ik_ref.attr("worldMatrix"), self.eff_loc.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputRotate", pb_node + ".inRotate2") # Twist references --------------------------------- node = aop.gear_mulmatrix_op(self.mid_ctl.attr("worldMatrix"), self.tws1_npo.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputTranslate", self.tws1_npo.attr("translate")) pm.connectAttr(dm_node + ".outputRotate", self.tws1_npo.attr("rotate")) pm.connectAttr(dm_node + ".outputScale", self.tws1_npo.attr("scale")) node = aop.gear_mulmatrix_op(self.eff_loc.attr("worldMatrix"), self.tws2_npo.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputTranslate", self.tws2_npo.attr("translate")) pm.connectAttr(dm_node + ".outputRotate", self.tws2_npo.attr("rotate")) # orientConstraint(self.eff_loc, self.tws2_rot, maintainOffset=False) node = aop.gear_mulmatrix_op(self.eff_loc.attr("worldMatrix"), self.tws2_rot.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(node + ".output", dm_node + ".inputMatrix") att.setRotOrder(self.tws2_rot, "XYZ") pm.connectAttr(dm_node + ".outputRotate", self.tws2_rot + ".rotate") self.tws0_rot.setAttr("sx", .001) self.tws2_rot.setAttr("sx", .001) add_node = nod.createAddNode(self.roundness_att, .001) pm.connectAttr(add_node + ".output", self.tws1_rot.attr("sx")) pm.connectAttr(self.armpit_roll_att, self.tws0_rot + ".rotateX") #Roll Shoulder--use aimconstraint withour uovwctor to solve the stable twist if self.negate: node = aop.aimCns(self.tws0_loc, self.mid_ctl, axis="-xy", wupType=4, wupVector=[0, 1, 0], wupObject=self.tws0_npo, maintainOffset=False) else: node = aop.aimCns(self.tws0_loc, self.mid_ctl, axis="xy", wupType=4, wupVector=[0, 1, 0], wupObject=self.tws0_npo, maintainOffset=False) # Volume ------------------------------------------- distA_node = nod.createDistNode(self.tws0_loc, self.tws1_loc) distB_node = nod.createDistNode(self.tws1_loc, self.tws2_loc) add_node = nod.createAddNode(distA_node + ".distance", distB_node + ".distance") div_node = nod.createDivNode(add_node + ".output", self.root.attr("sx")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(self.root.attr("worldMatrix"), dm_node + ".inputMatrix") div_node2 = nod.createDivNode(div_node + ".outputX", dm_node + ".outputScaleX") self.volDriver_att = div_node2 + ".outputX" # Divisions ---------------------------------------- # at 0 or 1 the division will follow exactly the rotation of the controler.. and we wont have this nice tangent + roll for i, div_cns in enumerate(self.div_cns): if i < (self.settings["div0"] + 1): perc = i * .5 / (self.settings["div0"] + 1.0) elif i < (self.settings["div0"] + 2): perc = .49 elif i < (self.settings["div0"] + 3): perc = .50 elif i < (self.settings["div0"] + 4): perc = .51 else: perc = .5 + (i - self.settings["div0"] - 3.0) * .5 / (self.settings["div1"] + 1.0) perc = max(.001, min(.990, perc)) # Roll if self.negate: node = aop.gear_rollsplinekine_op( div_cns, [self.tws2_rot, self.tws1_rot, self.tws0_rot], 1 - perc, 40) else: node = aop.gear_rollsplinekine_op( div_cns, [self.tws0_rot, self.tws1_rot, self.tws2_rot], perc, 40) pm.connectAttr(self.resample_att, node + ".resample") pm.connectAttr(self.absolute_att, node + ".absolute") # Squash n Stretch node = aop.gear_squashstretch2_op(div_cns, None, pm.getAttr(self.volDriver_att), "x") pm.connectAttr(self.volume_att, node + ".blend") pm.connectAttr(self.volDriver_att, node + ".driver") pm.connectAttr(self.st_att[i], node + ".stretch") pm.connectAttr(self.sq_att[i], node + ".squash") # match IK/FK ref pm.parentConstraint(self.bone0, self.match_fk0_off, mo=True) pm.parentConstraint(self.bone1, self.match_fk1_off, mo=True) return
def addOperators(self): """Create operators and set the relations for the component rig Apply operators, constraints, expressions to the hierarchy. In order to keep the code clean and easier to debug, we shouldn't create any new object in this method. """ # Soft condition soft_cond_node = node.createConditionNode(self.soft_attr, 0.0001, 4, 0.0001, self.soft_attr) self.soft_attr_cond = soft_cond_node.outColorR if self.settings["ikSolver"]: self.ikSolver = "ikRPsolver" else: pm.mel.eval("ikSpringSolver;") self.ikSolver = "ikSpringSolver" # 1 bone chain Upv ref =============================== self.ikHandleUpvRef = primitive.addIkHandle( self.root, self.getName("ikHandleLegChainUpvRef"), self.legChainUpvRef, "ikSCsolver") pm.pointConstraint(self.ik_ctl, self.ikHandleUpvRef) pm.parentConstraint(self.legChainUpvRef[0], self.upv_cns, mo=True) # mid joints ================================================ for xjnt, midJ in zip(self.legBones[1:3], [self.mid1_jnt, self.mid2_jnt]): node.createPairBlend(None, xjnt, .5, 1, midJ) pm.connectAttr(xjnt + ".translate", midJ + ".translate", f=True) pm.parentConstraint(self.mid1_jnt, self.knee_lvl) pm.parentConstraint(self.mid2_jnt, self.ankle_lvl) # joint length multiply multJnt1_node = node.createMulNode(self.boneALenght_attr, self.boneALenghtMult_attr) multJnt2_node = node.createMulNode(self.boneBLenght_attr, self.boneBLenghtMult_attr) multJnt3_node = node.createMulNode(self.boneCLenght_attr, self.boneCLenghtMult_attr) # # IK 3 bones =============================================== self.ikHandle = primitive.addIkHandle(self.softblendLoc, self.getName("ik3BonesHandle"), self.chain3bones, self.ikSolver, self.upv_ctl) # TwistTest if [round(elem, 4) for elem in transform.getTranslation(self.chain3bones[1])] \ != [round(elem, 4) for elem in self.guide.apos[1]]: add_nodeTwist = node.createAddNode(180.0, self.roll_att) else: add_nodeTwist = node.createAddNode(0, self.roll_att) if self.negate: mulVal = 1 else: mulVal = -1 node.createMulNode(add_nodeTwist + ".output", mulVal, self.ikHandle.attr("twist")) # stable spring solver doble rotation pm.pointConstraint(self.root_ctl, self.chain3bones[0]) # softIK 3 bones operators applyop.aimCns(self.aim_tra, self.ik_ref, axis="zx", wupType=4, wupVector=[1, 0, 0], wupObject=self.root_ctl, maintainOffset=False) plusTotalLength_node = node.createPlusMinusAverage1D([ multJnt1_node.attr("outputX"), multJnt2_node.attr("outputX"), multJnt3_node.attr("outputX") ]) subtract1_node = node.createPlusMinusAverage1D( [plusTotalLength_node.attr("output1D"), self.soft_attr_cond], 2) distance1_node = node.createDistNode(self.ik_ref, self.aim_tra) div1_node = node.createDivNode(1.0, self.rig.global_ctl + ".sx") mult1_node = node.createMulNode(distance1_node + ".distance", div1_node + ".outputX") subtract2_node = node.createPlusMinusAverage1D( [mult1_node.attr("outputX"), subtract1_node.attr("output1D")], 2) div2_node = node.createDivNode(subtract2_node + ".output1D", self.soft_attr_cond) mult2_node = node.createMulNode(-1, div2_node + ".outputX") power_node = node.createPowNode(self.softSpeed_attr, mult2_node + ".outputX") mult3_node = node.createMulNode(self.soft_attr_cond, power_node + ".outputX") subtract3_node = node.createPlusMinusAverage1D([ plusTotalLength_node.attr("output1D"), mult3_node.attr("outputX") ], 2) cond1_node = node.createConditionNode( self.soft_attr_cond, 0, 2, subtract3_node + ".output1D", plusTotalLength_node + ".output1D") cond2_node = node.createConditionNode(mult1_node + ".outputX", subtract1_node + ".output1D", 2, cond1_node + ".outColorR", mult1_node + ".outputX") pm.connectAttr(cond2_node + ".outColorR", self.wristSoftIK + ".tz") # soft blend pc_node = pm.pointConstraint(self.wristSoftIK, self.ik_ref, self.softblendLoc) node.createReverseNode(self.stretch_attr, pc_node + ".target[0].targetWeight") pm.connectAttr(self.stretch_attr, pc_node + ".target[1].targetWeight", f=True) # Stretch distance2_node = node.createDistNode(self.softblendLoc, self.wristSoftIK) mult4_node = node.createMulNode(distance2_node + ".distance", div1_node + ".outputX") # bones for i, mulNode in enumerate( [multJnt1_node, multJnt2_node, multJnt3_node]): div3_node = node.createDivNode(mulNode + ".outputX", plusTotalLength_node + ".output1D") mult5_node = node.createMulNode(mult4_node + ".outputX", div3_node + ".outputX") mult6_node = node.createMulNode(self.stretch_attr, mult5_node + ".outputX") node.createPlusMinusAverage1D( [mulNode.attr("outputX"), mult6_node.attr("outputX")], 1, self.chain3bones[i + 1] + ".tx") # IK 2 bones =============================================== self.ikHandle2 = primitive.addIkHandle(self.softblendLoc2, self.getName("ik2BonesHandle"), self.chain2bones, self.ikSolver, self.upv_ctl) node.createMulNode(self.roll_att, mulVal, self.ikHandle2.attr("twist")) # stable spring solver doble rotation pm.pointConstraint(self.root_ctl, self.chain2bones[0]) parentc_node = pm.parentConstraint(self.ik2b_ikCtl_ref, self.ik2b_bone_ref, self.ik2b_blend) node.createReverseNode(self.fullIK_attr, parentc_node + ".target[0].targetWeight") pm.connectAttr(self.fullIK_attr, parentc_node + ".target[1].targetWeight", f=True) # softIK 2 bones operators applyop.aimCns(self.aim_tra2, self.ik2b_ik_ref, axis="zx", wupType=4, wupVector=[1, 0, 0], wupObject=self.root_ctl, maintainOffset=False) plusTotalLength_node = node.createPlusMinusAverage1D( [multJnt1_node.attr("outputX"), multJnt2_node.attr("outputX")]) subtract1_node = node.createPlusMinusAverage1D( [plusTotalLength_node.attr("output1D"), self.soft_attr_cond], 2) distance1_node = node.createDistNode(self.ik2b_ik_ref, self.aim_tra2) div1_node = node.createDivNode(1, self.rig.global_ctl + ".sx") mult1_node = node.createMulNode(distance1_node + ".distance", div1_node + ".outputX") subtract2_node = node.createPlusMinusAverage1D( [mult1_node.attr("outputX"), subtract1_node.attr("output1D")], 2) div2_node = node.createDivNode(subtract2_node + ".output1D", self.soft_attr_cond) mult2_node = node.createMulNode(-1, div2_node + ".outputX") power_node = node.createPowNode(self.softSpeed_attr, mult2_node + ".outputX") mult3_node = node.createMulNode(self.soft_attr_cond, power_node + ".outputX") subtract3_node = node.createPlusMinusAverage1D([ plusTotalLength_node.attr("output1D"), mult3_node.attr("outputX") ], 2) cond1_node = node.createConditionNode( self.soft_attr_cond, 0, 2, subtract3_node + ".output1D", plusTotalLength_node + ".output1D") cond2_node = node.createConditionNode(mult1_node + ".outputX", subtract1_node + ".output1D", 2, cond1_node + ".outColorR", mult1_node + ".outputX") pm.connectAttr(cond2_node + ".outColorR", self.ankleSoftIK + ".tz") # soft blend pc_node = pm.pointConstraint(self.ankleSoftIK, self.ik2b_ik_ref, self.softblendLoc2) node.createReverseNode(self.stretch_attr, pc_node + ".target[0].targetWeight") pm.connectAttr(self.stretch_attr, pc_node + ".target[1].targetWeight", f=True) # Stretch distance2_node = node.createDistNode(self.softblendLoc2, self.ankleSoftIK) mult4_node = node.createMulNode(distance2_node + ".distance", div1_node + ".outputX") for i, mulNode in enumerate([multJnt1_node, multJnt2_node]): div3_node = node.createDivNode(mulNode + ".outputX", plusTotalLength_node + ".output1D") mult5_node = node.createMulNode(mult4_node + ".outputX", div3_node + ".outputX") mult6_node = node.createMulNode(self.stretch_attr, mult5_node + ".outputX") node.createPlusMinusAverage1D( [mulNode.attr("outputX"), mult6_node.attr("outputX")], 1, self.chain2bones[i + 1] + ".tx") # IK/FK connections for i, x in enumerate(self.fk_ctl): pm.parentConstraint(x, self.legBonesFK[i], mo=True) for i, x in enumerate([self.chain2bones[0], self.chain2bones[1]]): pm.parentConstraint(x, self.legBonesIK[i], mo=True) pm.pointConstraint(self.ik2b_ik_ref, self.legBonesIK[2]) applyop.aimCns(self.legBonesIK[2], self.roll_ctl, axis="xy", wupType=4, wupVector=[0, 1, 0], wupObject=self.legBonesIK[1], maintainOffset=False) pm.connectAttr(self.chain3bones[-1].attr("tx"), self.legBonesIK[-1].attr("tx")) # foot twist roll pm.orientConstraint(self.ik_ref, self.legBonesIK[-1], mo=True) node.createMulNode(-1, self.chain3bones[-1].attr("tx"), self.ik2b_ik_ref.attr("tx")) for i, x in enumerate(self.legBones): node.createPairBlend(self.legBonesFK[i], self.legBonesIK[i], self.blend_att, 1, x) # Twist references ---------------------------------------- self.ikhArmRef, self.tmpCrv = applyop.splineIK( self.getName("legRollRef"), self.rollRef, parent=self.root, cParent=self.legBones[0]) initRound = .001 multVal = 1 multTangent_node = node.createMulNode(self.roundnessKnee_att, multVal) add_node = node.createAddNode(multTangent_node + ".outputX", initRound) pm.connectAttr(add_node + ".output", self.tws1_rot.attr("sx")) for x in ["translate"]: pm.connectAttr(self.knee_ctl.attr(x), self.tws1_loc.attr(x)) for x in "xy": pm.connectAttr(self.knee_ctl.attr("r" + x), self.tws1_loc.attr("r" + x)) multTangent_node = node.createMulNode(self.roundnessAnkle_att, multVal) add_node = node.createAddNode(multTangent_node + ".outputX", initRound) pm.connectAttr(add_node + ".output", self.tws2_rot.attr("sx")) for x in ["translate"]: pm.connectAttr(self.ankle_ctl.attr(x), self.tws2_loc.attr(x)) for x in "xy": pm.connectAttr(self.ankle_ctl.attr("r" + x), self.tws2_loc.attr("r" + x)) # Volume ------------------------------------------- distA_node = node.createDistNode(self.tws0_loc, self.tws1_loc) distB_node = node.createDistNode(self.tws1_loc, self.tws2_loc) distC_node = node.createDistNode(self.tws2_loc, self.tws3_loc) add_node = node.createAddNode(distA_node + ".distance", distB_node + ".distance") add_node2 = node.createAddNode(distC_node + ".distance", add_node + ".output") div_node = node.createDivNode(add_node2 + ".output", self.root_ctl.attr("sx")) # comp scaling dm_node = node.createDecomposeMatrixNode(self.root.attr("worldMatrix")) div_node2 = node.createDivNode(div_node + ".outputX", dm_node + ".outputScaleX") self.volDriver_att = div_node2 + ".outputX" # Flip Offset ---------------------------------------- pm.connectAttr(self.ankleFlipOffset_att, self.tws2_loc.attr("rz")) pm.connectAttr(self.kneeFlipOffset_att, self.tws1_loc.attr("rz")) # Divisions ---------------------------------------- # at 0 or 1 the division will follow exactly the rotation of the # controler.. and we wont have this nice tangent + roll for i, div_cns in enumerate(self.div_cns): subdiv = False if i == len(self.div_cns) - 1 or i == 0: subdiv = 45 else: subdiv = 45 if i < (self.settings["div0"] + 1): perc = i * .333 / (self.settings["div0"] + 1.0) elif i < (self.settings["div0"] + self.settings["div1"] + 2): perc = i * .333 / (self.settings["div0"] + 1.0) else: perc = (.5 + (i - self.settings["div0"] - 3.0) * .5 / (self.settings["div1"] + 1.0)) if i < (self.settings["div0"] + 2): perc = i * .333 / (self.settings["div0"] + 1.0) elif i < (self.settings["div0"] + self.settings["div1"] + 3): perc = (.333 + (i - self.settings["div0"] - 1) * .333 / (self.settings["div1"] + 1.0)) else: perc = ( .666 + (i - self.settings["div1"] - self.settings["div0"] - 2.0) * .333 / (self.settings["div2"] + 1.0)) # we neet to offset the ankle and knee point to force the bone # orientation to the nex bone span if perc == .333: perc = .3338 elif perc == .666: perc = .6669 perc = max(.001, min(.999, perc)) # Roll cts = [self.tws0_rot, self.tws1_rot, self.tws2_rot, self.tws3_rot] o_node = applyop.gear_rollsplinekine_op(div_cns, cts, perc, subdiv) pm.connectAttr(self.resample_att, o_node + ".resample") pm.connectAttr(self.absolute_att, o_node + ".absolute") # Squash n Stretch o_node = applyop.gear_squashstretch2_op( div_cns, None, pm.getAttr(self.volDriver_att), "x") pm.connectAttr(self.volume_att, o_node + ".blend") pm.connectAttr(self.volDriver_att, o_node + ".driver") pm.connectAttr(self.st_att[i], o_node + ".stretch") pm.connectAttr(self.sq_att[i], o_node + ".squash") # Visibilities ------------------------------------- # fk fkvis_node = node.createReverseNode(self.blend_att) for ctrl in self.fk_ctl: for shp in ctrl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) # ik for ctrl in [self.ik_ctl, self.roll_ctl]: for shp in ctrl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) # setup leg o_node scale compensate pm.connectAttr(self.rig.global_ctl + ".scale", self.setup + ".scale") return
def addOperators(self): """Create operators and set the relations for the component rig Apply operators, constraints, expressions to the hierarchy. In order to keep the code clean and easier to debug, we shouldn't create any new object in this method. """ # 1 bone chain Upv ref =========================== self.ikHandleUpvRef = primitive.addIkHandle( self.root, self.getName("ikHandleLegChainUpvRef"), self.legChainUpvRef, "ikSCsolver") pm.pointConstraint(self.ik_ctl, self.ikHandleUpvRef) pm.parentConstraint(self.legChainUpvRef[0], self.ik_ctl, self.upv_cns, mo=True) # Visibilities ------------------------------------- # shape.dispGeometry # fk fkvis_node = node.createReverseNode(self.blend_att) for shp in self.fk0_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) for shp in self.fk1_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) for shp in self.fk2_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) # ik for shp in self.upv_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ikcns_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ik_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) # IK Solver ----------------------------------------- out = [self.bone0, self.bone1, self.ctrn_loc, self.eff_loc] o_node = applyop.gear_ikfk2bone_op(out, self.root_ctl, self.ik_ref, self.upv_ctl, self.fk_ctl[0], self.fk_ctl[1], self.fk_ref, self.length0, self.length1, self.negate) pm.connectAttr(self.blend_att, o_node + ".blend") if self.negate: mulVal = -1 else: mulVal = 1 node.createMulNode(self.roll_att, mulVal, o_node + ".roll") pm.connectAttr(self.scale_att, o_node + ".scaleA") pm.connectAttr(self.scale_att, o_node + ".scaleB") pm.connectAttr(self.maxstretch_att, o_node + ".maxstretch") pm.connectAttr(self.slide_att, o_node + ".slide") pm.connectAttr(self.softness_att, o_node + ".softness") pm.connectAttr(self.reverse_att, o_node + ".reverse") # Twist references --------------------------------- self.ikhArmRef, self.tmpCrv = applyop.splineIK( self.getName("legRollRef"), self.rollRef, parent=self.root, cParent=self.bone0) pm.pointConstraint(self.mid_ctl, self.tws1_loc, maintainOffset=False) pm.scaleConstraint(self.mid_ctl, self.tws1_loc, maintainOffset=False) applyop.oriCns(self.mid_ctl, self.tws1_rot, maintainOffset=False) pm.pointConstraint(self.eff_loc, self.tws2_loc, maintainOffset=False) pm.scaleConstraint(self.eff_loc, self.tws2_loc, maintainOffset=False) applyop.oriCns(self.bone1, self.tws2_loc, maintainOffset=False) applyop.oriCns(self.tws_ref, self.tws2_rot) self.tws0_loc.setAttr("sx", .001) self.tws2_loc.setAttr("sx", .001) add_node = node.createAddNode(self.roundness_att, .001) pm.connectAttr(add_node + ".output", self.tws1_rot.attr("sx")) # Volume ------------------------------------------- distA_node = node.createDistNode(self.tws0_loc, self.tws1_loc) distB_node = node.createDistNode(self.tws1_loc, self.tws2_loc) add_node = node.createAddNode(distA_node + ".distance", distB_node + ".distance") div_node = node.createDivNode(add_node + ".output", self.root_ctl.attr("sx")) # comp scaling issue dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(self.root.attr("worldMatrix"), dm_node + ".inputMatrix") div_node2 = node.createDivNode(div_node + ".outputX", dm_node + ".outputScaleX") self.volDriver_att = div_node2 + ".outputX" # Divisions ---------------------------------------- # at 0 or 1 the division will follow exactly the rotation of the # controler.. and we wont have this nice tangent + roll for i, div_cns in enumerate(self.div_cns): subdiv = False if i == len(self.div_cns) - 1 or i == 0: subdiv = 45 else: subdiv = 10 if i < (self.settings["div0"] + 1): perc = i * .5 / (self.settings["div0"] + 1.0) elif i < (self.settings["div0"] + 2): perc = .49 subdiv = 45 elif i < (self.settings["div0"] + 3): perc = .50 subdiv = 45 elif i < (self.settings["div0"] + 4): perc = .51 subdiv = 45 else: perc = (.5 + (i - self.settings["div0"] - 3.0) * .5 / (self.settings["div1"] + 1.0)) perc = max(.001, min(.999, perc)) # Roll if self.negate: o_node = applyop.gear_rollsplinekine_op( div_cns, [self.tws2_rot, self.tws1_rot, self.tws0_rot], 1 - perc, subdiv) else: o_node = applyop.gear_rollsplinekine_op( div_cns, [self.tws0_rot, self.tws1_rot, self.tws2_rot], perc, subdiv) pm.connectAttr(self.resample_att, o_node + ".resample") pm.connectAttr(self.absolute_att, o_node + ".absolute") # Squash n Stretch o_node = applyop.gear_squashstretch2_op( div_cns, None, pm.getAttr(self.volDriver_att), "x") pm.connectAttr(self.volume_att, o_node + ".blend") pm.connectAttr(self.volDriver_att, o_node + ".driver") pm.connectAttr(self.st_att[i], o_node + ".stretch") pm.connectAttr(self.sq_att[i], o_node + ".squash") # NOTE: next line fix the issue on meters. # This is special case becasuse the IK solver from mGear use # the scale as lenght and we have shear # TODO: check for a more clean and elegant solution instead of # re-match the world matrix again # transform.matchWorldTransform(self.fk_ctl[0], self.match_fk0_off) # transform.matchWorldTransform(self.fk_ctl[1], self.match_fk1_off) # transform.matchWorldTransform(self.fk_ctl[0], self.match_fk0) # transform.matchWorldTransform(self.fk_ctl[1], self.match_fk1) # match IK/FK ref pm.parentConstraint(self.bone0, self.match_fk0_off, mo=True) pm.parentConstraint(self.bone1, self.match_fk1_off, mo=True) return
def addOperators(self): """Create operators and set the relations for the component rig Apply operators, constraints, expressions to the hierarchy. In order to keep the code clean and easier to debug, we shouldn't create any new object in this method. """ # Visibilities ------------------------------------- # fk fkvis_node = node.createReverseNode(self.blend_att) for shp in self.fk0_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) for shp in self.fk0_roll_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) for shp in self.fk1_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) for shp in self.fk1_roll_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) fkvis2_node = node.createReverseNode(self.blend2_att) for shp in self.fk2_ctl.getShapes(): pm.connectAttr(fkvis2_node + ".outputX", shp.attr("visibility")) # ik for shp in self.upv_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ikcns_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ik_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) # jnt ctl for ctl in (self.div_ctls): for shp in ctl.getShapes(): pm.connectAttr(self.jntctl_vis_att, shp.attr("visibility")) # Controls ROT order ----------------------------------- attribute.setRotOrder(self.fk0_ctl, "YZX") attribute.setRotOrder(self.fk1_ctl, "XYZ") attribute.setRotOrder(self.fk2_ctl, "YZX") attribute.setRotOrder(self.ik_ctl, "XYZ") # IK Solver ----------------------------------------- out = [self.bone0, self.bone1, self.ctrn_loc, self.eff_npo] o_node = applyop.gear_ikfk2bone_op(out, self.root, self.ik_ref, self.upv_ctl, self.fk0_mtx, self.fk1_mtx, self.fk2_mtx, self.length0, self.length1, self.negate) pm.connectAttr(self.blend_att, o_node + ".blend") pm.connectAttr(self.roll_att, o_node + ".roll") pm.connectAttr(self.scale_att, o_node + ".scaleA") pm.connectAttr(self.scale_att, o_node + ".scaleB") pm.connectAttr(self.maxstretch_att, o_node + ".maxstretch") pm.connectAttr(self.slide_att, o_node + ".slide") pm.connectAttr(self.softness_att, o_node + ".softness") pm.connectAttr(self.reverse_att, o_node + ".reverse") # update issue on effector scale interpol, disconnect for stability pm.disconnectAttr(self.eff_npo.scale) # auto upvector ------------------------------------- if self.negate: o_node = applyop.aimCns(self.upv_auv, self.ik_ctl, axis="-xy", wupType=4, wupVector=[0, 1, 0], wupObject=self.upv_auv, maintainOffset=False) else: o_node = applyop.aimCns(self.upv_auv, self.ik_ctl, axis="xy", wupType=4, wupVector=[0, 1, 0], wupObject=self.upv_auv, maintainOffset=False) o_node = applyop.gear_mulmatrix_op( self.upv_auv.attr("worldMatrix"), self.upv_mtx.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") pb_node = pm.createNode("pairBlend") pb_node.attr("rotInterpolation").set(1) pm.connectAttr(dm_node + ".outputTranslate", pb_node + ".inTranslate2") pm.connectAttr(dm_node + ".outputRotate", pb_node + ".inRotate2") pm.connectAttr(pb_node + ".outRotate", self.upv_mtx.attr("rotate")) pm.connectAttr(pb_node + ".outTranslate", self.upv_mtx.attr("translate")) pm.connectAttr(self.auv_att, pb_node + ".weight") # fk0 mtx connection o_node = applyop.gear_mulmatrix_op( self.fk0_roll_ctl.attr("worldMatrix"), self.fk0_mtx.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputTranslate", self.fk0_mtx.attr("translate")) pm.connectAttr(dm_node + ".outputRotate", self.fk0_mtx.attr("rotate")) # fk1 loc connect to fk1 ref @ pos and rot, not scl to avoid shearing o_node = applyop.gear_mulmatrix_op( self.fk1_ref.attr("worldMatrix"), self.fk1_loc.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputTranslate", self.fk1_loc.attr("translate")) pm.connectAttr(dm_node + ".outputRotate", self.fk1_loc.attr("rotate")) # fk1 mtx orient cns to fk1 roll pm.connectAttr(self.fk1_roll_ctl.attr("rotate"), self.fk1_mtx.attr("rotate")) # fk2_loc position constraint to effector------------------------ o_node = applyop.gear_mulmatrix_op( self.eff_npo.attr("worldMatrix"), self.fk2_loc.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputTranslate", self.fk2_loc.attr("translate")) # fk2_loc rotation constraint to bone1 (bugfixed) -------------- o_node = applyop.gear_mulmatrix_op( self.bone1.attr("worldMatrix"), self.fk2_loc.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputRotate", self.fk2_loc.attr("rotate")) # hand ikfk blending from fk ref to ik ref (serious bugfix)-------- o_node = applyop.gear_mulmatrix_op( self.fk_ref.attr("worldMatrix"), self.eff_loc.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pb_node = pm.createNode("pairBlend") pb_node.attr("rotInterpolation").set(1) pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputRotate", pb_node + ".inRotate1") pm.connectAttr(self.blend2_att, pb_node + ".weight") pm.connectAttr(pb_node + ".outRotate", self.eff_loc.attr("rotate")) o_node = applyop.gear_mulmatrix_op( self.ik_ref.attr("worldMatrix"), self.eff_loc.attr("parentInverseMatrix")) dm_node1 = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node1 + ".inputMatrix") pm.connectAttr(dm_node1 + ".outputRotate", pb_node + ".inRotate2") # use blendcolors to blend scale bc_node = pm.createNode("blendColors") pm.connectAttr(self.blend_att, bc_node + ".blender") pm.connectAttr(dm_node + ".outputScale", bc_node + ".color2") pm.connectAttr(dm_node1 + ".outputScale", bc_node + ".color1") pm.connectAttr(bc_node + ".output", self.eff_loc.attr("scale")) # Twist references --------------------------------- pm.connectAttr(self.mid_ctl.attr("translate"), self.tws1_npo.attr("translate")) pm.connectAttr(self.mid_ctl.attr("rotate"), self.tws1_npo.attr("rotate")) pm.connectAttr(self.mid_ctl.attr("scale"), self.tws1_npo.attr("scale")) o_node = applyop.gear_mulmatrix_op( self.eff_loc.attr("worldMatrix"), self.tws3_npo.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputTranslate", self.tws3_npo.attr("translate")) pm.connectAttr(dm_node + ".outputRotate", self.tws3_npo.attr("rotate")) attribute.setRotOrder(self.tws3_rot, "XYZ") # elbow thickness connection if self.negate: o_node = node.createMulNode( [self.elbow_thickness_att, self.elbow_thickness_att], [0.5, -0.5, 0], [self.tws1_loc + ".translateX", self.tws2_loc + ".translateX"]) else: o_node = node.createMulNode( [self.elbow_thickness_att, self.elbow_thickness_att], [-0.5, 0.5, 0], [self.tws1_loc + ".translateX", self.tws2_loc + ".translateX"]) # connect both tws1 and tws2 (mid tws) self.tws0_rot.setAttr("sx", .001) self.tws3_rot.setAttr("sx", .001) add_node = node.createAddNode(self.roundness0_att, .001) pm.connectAttr(add_node + ".output", self.tws1_rot.attr("sx")) add_node = node.createAddNode(self.roundness1_att, .001) pm.connectAttr(add_node + ".output", self.tws2_rot.attr("sx")) pm.connectAttr(self.armpit_roll_att, self.tws0_rot + ".rotateX") # Roll Shoulder--use aimconstraint withour uovwctor to solve # the stable twist if self.negate: o_node = applyop.aimCns(self.tws0_loc, self.mid_ctl, axis="-xy", wupType=4, wupVector=[0, 1, 0], wupObject=self.tws0_npo, maintainOffset=False) else: o_node = applyop.aimCns(self.tws0_loc, self.mid_ctl, axis="xy", wupType=4, wupVector=[0, 1, 0], wupObject=self.tws0_npo, maintainOffset=False) # Volume ------------------------------------------- distA_node = node.createDistNode(self.tws0_loc, self.tws1_npo) distB_node = node.createDistNode(self.tws1_npo, self.tws3_loc) add_node = node.createAddNode(distA_node + ".distance", distB_node + ".distance") div_node = node.createDivNode(add_node + ".output", self.root.attr("sx")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(self.root.attr("worldMatrix"), dm_node + ".inputMatrix") div_node2 = node.createDivNode(div_node + ".outputX", dm_node + ".outputScaleX") self.volDriver_att = div_node2 + ".outputX" # Divisions ---------------------------------------- # div mid constraint to mid ctl o_node = applyop.gear_mulmatrix_op( self.mid_ctl.attr("worldMatrix"), self.div_mid.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputTranslate", self.div_mid.attr("translate")) pm.connectAttr(dm_node + ".outputRotate", self.div_mid.attr("rotate")) # at 0 or 1 the division will follow exactly the rotation of the # controler.. and we wont have this nice tangent + roll # linear scaling percentage (1) to effector (2) to elbow scl_1_perc = [] scl_2_perc = [] for i, div_cnsUp in enumerate(self.div_cnsUp): if i < (self.settings["div0"] + 1): perc = i / (self.settings["div0"] + 1.0) elif i < (self.settings["div0"] + 2): perc = .95 perc = max(.001, min(.99, perc)) # Roll if self.negate: o_node = applyop.gear_rollsplinekine_op( div_cnsUp, [self.tws1_rot, self.tws0_rot], 1 - perc, 20) else: o_node = applyop.gear_rollsplinekine_op( div_cnsUp, [self.tws0_rot, self.tws1_rot], perc, 20) pm.connectAttr(self.resample_att, o_node + ".resample") pm.connectAttr(self.absolute_att, o_node + ".absolute") scl_1_perc.append(perc / 2) scl_2_perc.append(perc) scl_1_perc.append(0.5) scl_2_perc.append(1) for i, div_cnsDn in enumerate(self.div_cnsDn): if i == (0): perc = .05 elif i < (self.settings["div1"] + 1): perc = i / (self.settings["div1"] + 1.0) elif i < (self.settings["div1"] + 2): perc = .95 perc = max(.001, min(.990, perc)) # Roll if self.negate: o_node = applyop.gear_rollsplinekine_op( div_cnsDn, [self.tws3_rot, self.tws2_rot], 1 - perc, 20) else: o_node = applyop.gear_rollsplinekine_op( div_cnsDn, [self.tws2_rot, self.tws3_rot], perc, 20) pm.connectAttr(self.resample_att, o_node + ".resample") pm.connectAttr(self.absolute_att, o_node + ".absolute") scl_1_perc.append(perc / 2 + 0.5) scl_2_perc.append(1 - perc) # Squash n Stretch for i, div_cns in enumerate(self.div_cns): o_node = applyop.gear_squashstretch2_op( div_cns, None, pm.getAttr(self.volDriver_att), "x") pm.connectAttr(self.volume_att, o_node + ".blend") pm.connectAttr(self.volDriver_att, o_node + ".driver") pm.connectAttr(self.st_att[i], o_node + ".stretch") pm.connectAttr(self.sq_att[i], o_node + ".squash") # get the first mult_node after sq op mult_node = pm.listHistory(o_node, future=True)[1] # linear blend effector scale bc_node = pm.createNode("blendColors") bc_node.setAttr("color2R", 1) bc_node.setAttr("color2G", 1) bc_node.setAttr("blender", scl_1_perc[i]) pm.connectAttr(self.eff_loc.attr("scale"), bc_node + ".color1") # linear blend mid scale bc_node2 = pm.createNode("blendColors") bc_node2.setAttr("color2R", 1) bc_node2.setAttr("color2G", 1) bc_node2.setAttr("blender", scl_2_perc[i]) pm.connectAttr(self.mid_ctl.attr("scale"), bc_node2 + ".color1") # mid_ctl scale * effector scale mult_node2 = pm.createNode("multiplyDivide") pm.connectAttr(bc_node2 + ".output", mult_node2 + ".input1") pm.connectAttr(bc_node + ".output", mult_node2 + ".input2") # plug to sq scale pm.connectAttr(mult_node2 + ".output", mult_node + ".input2") # match IK/FK ref pm.connectAttr(self.bone0.attr("rotate"), self.match_fk0.attr("rotate")) pm.connectAttr(self.bone0.attr("translate"), self.match_fk0.attr("translate")) pm.connectAttr(self.bone1.attr("rotate"), self.match_fk1.attr("rotate")) pm.connectAttr(self.bone1.attr("translate"), self.match_fk1.attr("translate")) return
def addOperators(self): # 1 bone chain Upv ref ===================================================================================== self.ikHandleUpvRef = pri.addIkHandle( self.root, self.getName("ikHandleLegChainUpvRef"), self.armChainUpvRef, "ikSCsolver") pm.pointConstraint(self.ik_ctl, self.ikHandleUpvRef) pm.parentConstraint(self.armChainUpvRef[0], self.upv_cns, mo=True) # Visibilities ------------------------------------- # fk fkvis_node = nod.createReverseNode(self.blend_att) for shp in self.fk0_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) for shp in self.fk1_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) for shp in self.fk2_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) # ik for shp in self.upv_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ikcns_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ik_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) if self.settings["ikTR"]: for shp in self.ikRot_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) # Controls ROT order ----------------------------------- att.setRotOrder(self.fk0_ctl, "XZY") att.setRotOrder(self.fk1_ctl, "XYZ") att.setRotOrder(self.fk2_ctl, "YZX") # att.setRotOrder(self.ik_ctl, "ZYX") att.setRotOrder(self.ik_ctl, "XYZ") # IK Solver ----------------------------------------- out = [self.bone0, self.bone1, self.ctrn_loc, self.eff_loc] node = aop.gear_ikfk2bone_op(out, self.root, self.ik_ref, self.upv_ctl, self.fk_ctl[0], self.fk_ctl[1], self.fk_ref, self.length0, self.length1, self.negate) if self.settings["ikTR"]: #connect the control inputs outEff_dm = node.listConnections(c=True)[-1][1] outEff_dm.attr("outputTranslate") >> self.ikRot_npo.attr( "translate") outEff_dm.attr("outputScale") >> self.ikRot_npo.attr("scale") dm_node = nod.createDecomposeMatrixNode(node.attr("outB")) dm_node.attr("outputRotate") >> self.ikRot_npo.attr("rotate") #rotation # intM_node = aop.gear_intmatrix_op(node.attr("outEff"), self.ikRot_ctl.attr("worldMatrix"), node.attr("blend")) # mulM_node = aop.gear_mulmatrix_op(intM_node.attr("output"), self.eff_loc.attr("parentInverseMatrix")) # dm_node = nod.createDecomposeMatrixNode(mulM_node.attr("output")) mulM_node = aop.gear_mulmatrix_op( self.ikRot_ctl.attr("worldMatrix"), self.eff_loc.attr("parentInverseMatrix")) intM_node = aop.gear_intmatrix_op(node.attr("outEff"), mulM_node.attr("output"), node.attr("blend")) dm_node = nod.createDecomposeMatrixNode(intM_node.attr("output")) dm_node.attr("outputRotate") >> self.eff_loc.attr("rotate") #scale: this fix the scalin popping issue intM_node = aop.gear_intmatrix_op(self.fk2_ctl.attr("worldMatrix"), self.ik_ctl.attr("worldMatrix"), node.attr("blend")) mulM_node = aop.gear_mulmatrix_op( intM_node.attr("output"), self.eff_loc.attr("parentInverseMatrix")) dm_node = nod.createDecomposeMatrixNode(mulM_node.attr("output")) dm_node.attr("outputScale") >> self.eff_loc.attr("scale") pm.connectAttr(self.blend_att, node + ".blend") pm.connectAttr(self.roll_att, node + ".roll") pm.connectAttr(self.scale_att, node + ".scaleA") pm.connectAttr(self.scale_att, node + ".scaleB") pm.connectAttr(self.maxstretch_att, node + ".maxstretch") pm.connectAttr(self.slide_att, node + ".slide") pm.connectAttr(self.softness_att, node + ".softness") pm.connectAttr(self.reverse_att, node + ".reverse") # Twist references --------------------------------- pm.pointConstraint(self.mid_ctl, self.tws1_npo, maintainOffset=False) pm.scaleConstraint(self.mid_ctl, self.tws1_npo, maintainOffset=False) pm.orientConstraint(self.mid_ctl, self.tws1_npo, maintainOffset=False) node = aop.gear_mulmatrix_op(self.eff_loc.attr("worldMatrix"), self.root.attr("worldInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputTranslate", self.tws2_npo.attr("translate")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputRotate", self.tws2_npo.attr("rotate")) node = aop.gear_mulmatrix_op(self.eff_loc.attr("worldMatrix"), self.tws2_rot.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(node + ".output", dm_node + ".inputMatrix") att.setRotOrder(self.tws2_rot, "XYZ") pm.connectAttr(dm_node + ".outputRotate", self.tws2_rot + ".rotate") self.tws0_rot.setAttr("sx", .001) self.tws2_rot.setAttr("sx", .001) add_node = nod.createAddNode(self.roundness_att, .001) pm.connectAttr(add_node + ".output", self.tws1_rot.attr("sx")) pm.connectAttr(self.armpit_roll_att, self.tws0_rot + ".rotateX") #Roll Shoulder aop.splineIK(self.getName("rollRef"), self.rollRef, parent=self.root, cParent=self.bone0) # Volume ------------------------------------------- distA_node = nod.createDistNode(self.tws0_loc, self.tws1_loc) distB_node = nod.createDistNode(self.tws1_loc, self.tws2_loc) add_node = nod.createAddNode(distA_node + ".distance", distB_node + ".distance") div_node = nod.createDivNode(add_node + ".output", self.root.attr("sx")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(self.root.attr("worldMatrix"), dm_node + ".inputMatrix") div_node2 = nod.createDivNode(div_node + ".outputX", dm_node + ".outputScaleX") self.volDriver_att = div_node2 + ".outputX" # Divisions ---------------------------------------- # at 0 or 1 the division will follow exactly the rotation of the controler.. and we wont have this nice tangent + roll for i, div_cns in enumerate(self.div_cns): if i < (self.settings["div0"] + 1): perc = i * .5 / (self.settings["div0"] + 1.0) elif i < (self.settings["div0"] + 2): perc = .49 elif i < (self.settings["div0"] + 3): perc = .50 elif i < (self.settings["div0"] + 4): perc = .51 else: perc = .5 + (i - self.settings["div0"] - 3.0) * .5 / (self.settings["div1"] + 1.0) perc = max(.001, min(.990, perc)) # Roll if self.negate: node = aop.gear_rollsplinekine_op( div_cns, [self.tws2_rot, self.tws1_rot, self.tws0_rot], 1 - perc, 40) else: node = aop.gear_rollsplinekine_op( div_cns, [self.tws0_rot, self.tws1_rot, self.tws2_rot], perc, 40) pm.connectAttr(self.resample_att, node + ".resample") pm.connectAttr(self.absolute_att, node + ".absolute") # Squash n Stretch node = aop.gear_squashstretch2_op(div_cns, None, pm.getAttr(self.volDriver_att), "x") pm.connectAttr(self.volume_att, node + ".blend") pm.connectAttr(self.volDriver_att, node + ".driver") pm.connectAttr(self.st_att[i], node + ".stretch") pm.connectAttr(self.sq_att[i], node + ".squash") # match IK/FK ref pm.parentConstraint(self.bone0, self.match_fk0_off, mo=True) pm.parentConstraint(self.bone1, self.match_fk1_off, mo=True) return
def addOperators(self): # Visibilities ------------------------------------- # fk fkvis_node = nod.createReverseNode(self.blend_att) for shp in self.fk0_ctl.getShapes(): connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) for shp in self.fk1_ctl.getShapes(): connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) for shp in self.fk2_ctl.getShapes(): connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) # ik for shp in self.upv_ctl.getShapes(): connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ikcns_ctl.getShapes(): connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ik_ctl.getShapes(): connectAttr(self.blend_att, shp.attr("visibility")) # IK Solver ----------------------------------------- out = [self.bone0, self.bone1, self.ctrn_loc, self.eff_loc] node = aop.gear_ikfk2bone_op(out, self.root, self.ik_ref, self.upv_ctl, self.fk_ctl[0], self.fk_ctl[1], self.fk_ref, self.length0, self.length1, self.negate) connectAttr(self.blend_att, node + ".blend") connectAttr(self.roll_att, node + ".roll") connectAttr(self.scale_att, node + ".scaleA") connectAttr(self.scale_att, node + ".scaleB") connectAttr(self.maxstretch_att, node + ".maxstretch") connectAttr(self.slide_att, node + ".slide") connectAttr(self.softness_att, node + ".softness") connectAttr(self.reverse_att, node + ".reverse") # Twist references --------------------------------- pointConstraint(self.root, self.tws0_loc, maintainOffset=True) aop.aimCns(self.tws0_loc, self.mid_ctl, self.n_sign + "xz", 2, [0, 1, 0], self.root, False) pointConstraint(self.mid_ctl, self.tws1_loc, maintainOffset=False) scaleConstraint(self.mid_ctl, self.tws1_loc, maintainOffset=False) orientConstraint(self.mid_ctl, self.tws1_rot, maintainOffset=False) pointConstraint(self.eff_loc, self.tws2_loc, maintainOffset=False) scaleConstraint(self.eff_loc, self.tws2_loc, maintainOffset=False) orientConstraint(self.bone1, self.tws2_loc, maintainOffset=False) # orientConstraint(self.eff_loc, self.tws2_rot, maintainOffset=False) node = aop.gear_mulmatrix_op(self.eff_loc.attr("worldMatrix"), self.tws2_rot.attr("parentInverseMatrix")) dm_node = createNode("decomposeMatrix") connectAttr(node + ".output", dm_node + ".inputMatrix") connectAttr(dm_node + ".outputRotate", self.tws2_rot + ".rotate") # att.setRotOrder(self.tws2_rot, "YZX") self.tws0_loc.setAttr("sx", .001) self.tws2_loc.setAttr("sx", .001) add_node = nod.createAddNode(self.roundness_att, .001) connectAttr(add_node + ".output", self.tws1_rot.attr("sx")) # Volume ------------------------------------------- distA_node = nod.createDistNode(self.tws0_loc, self.tws1_loc) distB_node = nod.createDistNode(self.tws1_loc, self.tws2_loc) add_node = nod.createAddNode(distA_node + ".distance", distB_node + ".distance") div_node = nod.createDivNode(add_node + ".output", self.root.attr("sx")) self.volDriver_att = div_node + ".outputX" # Divisions ---------------------------------------- # at 0 or 1 the division will follow exactly the rotation of the controler.. and we wont have this nice tangent + roll for i, div_cns in enumerate(self.div_cns): if i < (self.settings["div0"] + 1): perc = i * .5 / (self.settings["div0"] + 1.0) else: perc = .5 + (i - self.settings["div0"] - 1.0) * .5 / (self.settings["div1"] + 1.0) perc = max(.001, min(.999, perc)) # Roll if self.negate: node = aop.gear_rollsplinekine_op( div_cns, [self.tws2_rot, self.tws1_rot, self.tws0_rot], 1 - perc) else: node = aop.gear_rollsplinekine_op( div_cns, [self.tws0_rot, self.tws1_rot, self.tws2_rot], perc) connectAttr(self.resample_att, node + ".resample") connectAttr(self.absolute_att, node + ".absolute") # Squash n Stretch node = aop.gear_squashstretch2_op(div_cns, None, getAttr(self.volDriver_att), "x") connectAttr(self.volume_att, node + ".blend") connectAttr(self.volDriver_att, node + ".driver") connectAttr(self.st_att[i], node + ".stretch") connectAttr(self.sq_att[i], node + ".squash") return
def addOperators(self): # Visibilities ------------------------------------- # fk fkvis_node = nod.createReverseNode(self.blend_att) for shp in self.fk0_ctl.getShapes(): connectAttr(fkvis_node+".outputX", shp.attr("visibility")) for shp in self.fk1_ctl.getShapes(): connectAttr(fkvis_node+".outputX", shp.attr("visibility")) for shp in self.fk2_ctl.getShapes(): connectAttr(fkvis_node+".outputX", shp.attr("visibility")) # ik for shp in self.upv_ctl.getShapes(): connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ikcns_ctl.getShapes(): connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ik_ctl.getShapes(): connectAttr(self.blend_att, shp.attr("visibility")) # IK Solver ----------------------------------------- out = [self.bone0, self.bone1, self.ctrn_loc, self.eff_loc] node = aop.gear_ikfk2bone_op(out, self.root, self.ik_ref, self.upv_ctl, self.fk_ctl[0], self.fk_ctl[1], self.fk_ref, self.length0, self.length1, self.negate) connectAttr(self.blend_att, node+".blend") connectAttr(self.roll_att, node+".roll") connectAttr(self.scale_att, node+".scaleA") connectAttr(self.scale_att, node+".scaleB") connectAttr(self.maxstretch_att, node+".maxstretch") connectAttr(self.slide_att, node+".slide") connectAttr(self.softness_att, node+".softness") connectAttr(self.reverse_att, node+".reverse") # Twist references --------------------------------- pointConstraint(self.root, self.tws0_loc, maintainOffset=True) aop.aimCns(self.tws0_loc, self.mid_ctl, self.n_sign+"xz", 2, [0,1,0], self.root, False) pointConstraint(self.mid_ctl, self.tws1_loc, maintainOffset=False) scaleConstraint(self.mid_ctl, self.tws1_loc, maintainOffset=False) orientConstraint(self.mid_ctl, self.tws1_rot, maintainOffset=False) pointConstraint(self.eff_loc, self.tws2_loc, maintainOffset=False) scaleConstraint(self.eff_loc, self.tws2_loc, maintainOffset=False) orientConstraint(self.bone1, self.tws2_loc, maintainOffset=False) # orientConstraint(self.eff_loc, self.tws2_rot, maintainOffset=False) node = aop.gear_mulmatrix_op(self.eff_loc.attr("worldMatrix"), self.tws2_rot.attr("parentInverseMatrix")) dm_node = createNode("decomposeMatrix") connectAttr(node+".output", dm_node+".inputMatrix") connectAttr(dm_node+".outputRotate", self.tws2_rot+".rotate") # att.setRotOrder(self.tws2_rot, "YZX") self.tws0_loc.setAttr("sx", .001) self.tws2_loc.setAttr("sx", .001) add_node = nod.createAddNode(self.roundness_att, .001) connectAttr(add_node+".output", self.tws1_rot.attr("sx")) # Volume ------------------------------------------- distA_node = nod.createDistNode(self.tws0_loc, self.tws1_loc) distB_node = nod.createDistNode(self.tws1_loc, self.tws2_loc) add_node = nod.createAddNode(distA_node+".distance", distB_node+".distance") div_node = nod.createDivNode(add_node+".output", self.root.attr("sx")) self.volDriver_att = div_node+".outputX" # Divisions ---------------------------------------- # at 0 or 1 the division will follow exactly the rotation of the controler.. and we wont have this nice tangent + roll for i, div_cns in enumerate(self.div_cns): if i < (self.settings["div0"]+1): perc = i*.5 / (self.settings["div0"]+1.0) else: perc = .5 + (i-self.settings["div0"]-1.0)*.5 / (self.settings["div1"]+1.0) perc = max(.001, min(.999, perc)) # Roll if self.negate: node = aop.gear_rollsplinekine_op(div_cns, [self.tws2_rot, self.tws1_rot, self.tws0_rot], 1-perc) else: node = aop.gear_rollsplinekine_op(div_cns, [self.tws0_rot, self.tws1_rot, self.tws2_rot], perc) connectAttr(self.resample_att, node+".resample") connectAttr(self.absolute_att, node+".absolute") # Squash n Stretch node = aop.gear_squashstretch2_op(div_cns, None, getAttr(self.volDriver_att), "x") connectAttr(self.volume_att, node+".blend") connectAttr(self.volDriver_att, node+".driver") connectAttr(self.st_att[i], node+".stretch") connectAttr(self.sq_att[i], node+".squash") return