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")) for shp in self.line_ref.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): """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")) for shp in self.line_ref.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.connectAttr(self.mid_ctl.scaleX, self.tws1_loc.scaleX) pm.connectAttr(self.mid_ctl.scaleX, self.tws1B_loc.scaleX) applyop.oriCns(self.mid_ctl, self.tws1_rot, maintainOffset=False) applyop.oriCns(self.mid_ctl, self.tws1B_rot, maintainOffset=False) if self.negate: axis = "xz" axisb = "-xz" else: axis = "-xz" axisb = "xz" applyop.aimCns(self.tws1_loc, self.root_ctl, axis=axis, wupType=4, wupVector=[0, 0, 1], wupObject=self.mid_ctl, maintainOffset=False) applyop.aimCns(self.tws1B_loc, self.eff_loc, axis=axisb, wupType=4, wupVector=[0, 0, 1], wupObject=self.mid_ctl, maintainOffset=False) pm.pointConstraint(self.thick_ctl, self.tws1B_loc, 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")) pm.connectAttr(add_node + ".output", self.tws1B_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" 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 b_twist = False for i, div_cns in enumerate(self.div_cns): subdiv = False if self.settings["supportJoints"]: 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): b_twist = True perc = .51 subdiv = 45 else: perc = (.5 + (i - self.settings["div0"] - 3.0) * .5 / (self.settings["div1"] + 1.0)) else: subdiv = 40 if i < (self.settings["div0"] + 1): perc = i * .5 / (self.settings["div0"] + 1.0) elif i < (self.settings["div0"] + 2): b_twist = True perc = .501 else: perc = .5 + \ (i - self.settings["div0"] - 1.0) * .5 / \ (self.settings["div1"] + 1.0) perc = max(.001, min(.990, perc)) # mid twist distribution if b_twist: mid_twist = self.tws1B_rot else: mid_twist = self.tws1_rot # Roll if self.negate: o_node = applyop.gear_rollsplinekine_op( div_cns, [self.tws2_rot, mid_twist, self.tws0_rot], 1.0 - perc, subdiv) else: o_node = applyop.gear_rollsplinekine_op( div_cns, [self.tws0_rot, mid_twist, 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) # connect_reader pm.parentConstraint(self.bone0, self.readerA, mo=True) pm.parentConstraint(self.bone1, self.readerB, mo=True) # connect auto thickness if self.negate and not self.settings["mirrorMid"]: d_val = -180 / self.length1 else: d_val = 180 / self.length1 div_thick_node = node.createDivNode(self.knee_thickness_att, d_val) node.createMulNode(div_thick_node.outputX, self.readerB.rx, self.thick_lvl.tx) 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) try: 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")) for shp in self.line_ref.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) except RuntimeError: pm.displayInfo("Visibility already connecte") # 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.connectAttr(self.mid_ctl.scaleX, self.tws1_loc.scaleX) 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) if self.settings["div0"]: ori_ref = self.rollRef[0] else: ori_ref = self.bone0 applyop.oriCns(ori_ref, self.tws0_loc, maintainOffset=True) self.tws0_loc.setAttr("sx", .001) self.tws2_loc.setAttr("sx", .001) add_node = node.createAddNode(self.roundness_att, .0) 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 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): subdiv = 40 if i < (self.settings["div0"] + 1): perc = i * .5 / (self.settings["div0"] + 1.0) elif i < (self.settings["div0"] + 2): perc = .501 else: perc = .5 + \ (i - self.settings["div0"] - 1.0) * .5 / \ (self.settings["div1"] + 1.0) perc = max(.0001, 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.0 - 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) # 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. """ # 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")) for shp in self.line_ref.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")) for shp in self.roll_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) # NOTE: Ideally we should not change hierarchy or move object after # object generation method. But is much easier this way since every # part is in the final and correct position # after the ctrn_loc is in the correct position with the ikfk2bone op # point constrain tip reference pm.pointConstraint(self.ik_ctl, self.tip_ref, mo=False) # interpolate transform mid point locator int_matrix = applyop.gear_intmatrix_op( self.armChainUpvRef[0].attr("worldMatrix"), self.tip_ref.attr("worldMatrix"), .5) applyop.gear_mulmatrix_op( int_matrix.attr("output"), self.interpolate_lvl.attr("parentInverseMatrix[0]"), self.interpolate_lvl) # match roll ctl npo to ctrn_loc current transform (so correct orient) transform.matchWorldTransform(self.ctrn_loc, self.roll_ctl_npo) # match roll ctl npo to interpolate transform current position pos = self.interpolate_lvl.getTranslation(space="world") self.roll_ctl_npo.setTranslation(pos, space="world") # parent constraint roll control npo to interpolate trans pm.parentConstraint(self.interpolate_lvl, self.roll_ctl_npo, mo=True) 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 rollMulVal = 1 else: mulVal = 1 rollMulVal = -1 roll_m_node = node.createMulNode(self.roll_att, mulVal) roll_m_node2 = node.createMulNode(self.roll_ctl.attr("rx"), rollMulVal) node.createPlusMinusAverage1D( [roll_m_node.outputX, roll_m_node2.outputX], operation=1, output=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.connectAttr(self.mid_ctl.scaleX, self.tws1B_loc.scaleX) pm.orientConstraint(self.mid_ctl_twst_ref, self.tws1_npo, maintainOffset=False) applyop.oriCns(self.mid_ctl, self.tws1_rot, maintainOffset=False) applyop.oriCns(self.mid_ctl, self.tws1B_rot, maintainOffset=False) if self.negate: axis = "xz" axisb = "-xz" else: axis = "-xz" axisb = "xz" applyop.aimCns(self.tws1_loc, self.root, axis=axis, wupType=4, wupVector=[0, 0, 1], wupObject=self.mid_ctl, maintainOffset=False) applyop.aimCns(self.tws1B_loc, self.eff_loc, axis=axisb, wupType=4, wupVector=[0, 0, 1], wupObject=self.mid_ctl, maintainOffset=False) pm.pointConstraint(self.thick_ctl, self.tws1B_loc, 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(add_node + ".output", self.tws1B_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 b_twist = False for i, div_cns in enumerate(self.div_cns): if self.settings["supportJoints"]: 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): b_twist = True perc = .51 else: perc = .5 + \ (i - self.settings["div0"] - 3.0) * .5 / \ (self.settings["div1"] + 1.0) else: if i < (self.settings["div0"] + 1): perc = i * .5 / (self.settings["div0"] + 1.0) elif i < (self.settings["div0"] + 2): b_twist = True perc = .501 else: perc = .5 + \ (i - self.settings["div0"] - 1.0) * .5 / \ (self.settings["div1"] + 1.0) perc = max(.001, min(.990, perc)) # mid twist distribution if b_twist: mid_twist = self.tws1B_rot else: mid_twist = self.tws1_rot # Roll if self.negate: o_node = applyop.gear_rollsplinekine_op( div_cns, [self.tws2_rot, mid_twist, self.tws0_rot], 1.0 - perc, 40) else: o_node = applyop.gear_rollsplinekine_op( div_cns, [self.tws0_rot, mid_twist, 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) # connect_reader pm.parentConstraint(self.bone0, self.readerA, mo=True) pm.parentConstraint(self.bone1, self.readerB, mo=True) # connect auto thickness if self.negate and not self.settings["mirrorMid"]: d_val = 180 / self.length1 else: d_val = -180 / self.length1 div_thick_node = node.createDivNode(self.elbow_thickness_att, d_val) node.createMulNode(div_thick_node.outputX, self.readerB.ry, self.thick_lvl.tx) 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")) for shp in self.line_ref.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.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") # Twist references --------------------------------- 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")) # spline IK for twist jnts self.ikhUpLegTwist, self.uplegTwistCrv = applyop.splineIK( self.getName("uplegTwist"), self.uplegTwistChain, parent=self.root, cParent=self.bone0) self.ikhLowLegTwist, self.lowlegTwistCrv = applyop.splineIK( self.getName("lowlegTwist"), self.lowlegTwistChain, parent=self.root, cParent=self.bone1) # references self.ikhUpLegRef, self.tmpCrv = applyop.splineIK( self.getName("uplegRollRef"), self.uplegRollRef, parent=self.root, cParent=self.bone0) self.ikhLowLegRef, self.tmpCrv = applyop.splineIK( self.getName("lowlegRollRef"), self.lowlegRollRef, parent=self.root, cParent=self.eff_loc) self.ikhAuxTwist, self.tmpCrv = applyop.splineIK( self.getName("auxTwist"), self.auxTwistChain, parent=self.root, cParent=self.eff_loc) # setting connexions for ikhUpLegTwist self.ikhUpLegTwist.attr("dTwistControlEnable").set(True) self.ikhUpLegTwist.attr("dWorldUpType").set(4) self.ikhUpLegTwist.attr("dWorldUpAxis").set(3) self.ikhUpLegTwist.attr("dWorldUpVectorZ").set(1.0) self.ikhUpLegTwist.attr("dWorldUpVectorY").set(0.0) self.ikhUpLegTwist.attr("dWorldUpVectorEndZ").set(1.0) self.ikhUpLegTwist.attr("dWorldUpVectorEndY").set(0.0) pm.connectAttr(self.uplegRollRef[0].attr("worldMatrix[0]"), self.ikhUpLegTwist.attr("dWorldUpMatrix")) pm.connectAttr(self.bone0.attr("worldMatrix[0]"), self.ikhUpLegTwist.attr("dWorldUpMatrixEnd")) # setting connexions for ikhAuxTwist self.ikhAuxTwist.attr("dTwistControlEnable").set(True) self.ikhAuxTwist.attr("dWorldUpType").set(4) self.ikhAuxTwist.attr("dWorldUpAxis").set(3) self.ikhAuxTwist.attr("dWorldUpVectorZ").set(1.0) self.ikhAuxTwist.attr("dWorldUpVectorY").set(0.0) self.ikhAuxTwist.attr("dWorldUpVectorEndZ").set(1.0) self.ikhAuxTwist.attr("dWorldUpVectorEndY").set(0.0) pm.connectAttr(self.lowlegRollRef[0].attr("worldMatrix[0]"), self.ikhAuxTwist.attr("dWorldUpMatrix")) pm.connectAttr(self.tws_ref.attr("worldMatrix[0]"), self.ikhAuxTwist.attr("dWorldUpMatrixEnd")) pm.connectAttr(self.auxTwistChain[1].attr("rx"), self.ikhLowLegTwist.attr("twist")) pm.parentConstraint(self.bone1, self.aux_npo, maintainOffset=True) # scale arm length for twist chain (not the squash and stretch) arclen_node = pm.arclen(self.uplegTwistCrv, ch=True) alAttrUpLeg = arclen_node.attr("arcLength") muldiv_nodeArm = pm.createNode("multiplyDivide") pm.connectAttr(arclen_node.attr("arcLength"), muldiv_nodeArm.attr("input1X")) muldiv_nodeArm.attr("input2X").set(alAttrUpLeg.get()) muldiv_nodeArm.attr("operation").set(2) for jnt in self.uplegTwistChain: pm.connectAttr(muldiv_nodeArm.attr("outputX"), jnt.attr("sx")) # scale forearm length for twist chain (not the squash and stretch) arclen_node = pm.arclen(self.lowlegTwistCrv, ch=True) alAttrLowLeg = arclen_node.attr("arcLength") muldiv_nodeLowLeg = pm.createNode("multiplyDivide") pm.connectAttr(arclen_node.attr("arcLength"), muldiv_nodeLowLeg.attr("input1X")) muldiv_nodeLowLeg.attr("input2X").set(alAttrLowLeg.get()) muldiv_nodeLowLeg.attr("operation").set(2) for jnt in self.lowlegTwistChain: pm.connectAttr(muldiv_nodeLowLeg.attr("outputX"), jnt.attr("sx")) # scale compensation for the first twist join dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(self.root.attr("worldMatrix[0]"), dm_node.attr("inputMatrix")) pm.connectAttr(dm_node.attr("outputScale"), self.uplegTwistChain[0].attr("inverseScale")) pm.connectAttr(dm_node.attr("outputScale"), self.lowlegTwistChain[0].attr("inverseScale")) # tangent controls muldiv_node = pm.createNode("multiplyDivide") muldiv_node.attr("input2X").set(-1) pm.connectAttr(self.tws1A_npo.attr("rz"), muldiv_node.attr("input1X")) muldiv_nodeBias = pm.createNode("multiplyDivide") pm.connectAttr(muldiv_node.attr("outputX"), muldiv_nodeBias.attr("input1X")) pm.connectAttr(self.roundness_att, muldiv_nodeBias.attr("input2X")) pm.connectAttr(muldiv_nodeBias.attr("outputX"), self.tws1A_loc.attr("rz")) if self.negate: axis = "xz" else: axis = "-xz" applyop.aimCns(self.tws1A_npo, self.tws0_loc, axis=axis, wupType=2, wupVector=[0, 0, 1], wupObject=self.mid_ctl, maintainOffset=False) applyop.aimCns(self.lowlegTangentB_loc, self.lowlegTangentA_npo, axis=axis, wupType=2, wupVector=[0, 0, 1], wupObject=self.mid_ctl, maintainOffset=False) pm.pointConstraint(self.eff_loc, self.lowlegTangentB_loc) muldiv_node = pm.createNode("multiplyDivide") muldiv_node.attr("input2X").set(-1) pm.connectAttr(self.tws1B_npo.attr("rz"), muldiv_node.attr("input1X")) muldiv_nodeBias = pm.createNode("multiplyDivide") pm.connectAttr(muldiv_node.attr("outputX"), muldiv_nodeBias.attr("input1X")) pm.connectAttr(self.roundness_att, muldiv_nodeBias.attr("input2X")) pm.connectAttr(muldiv_nodeBias.attr("outputX"), self.tws1B_loc.attr("rz")) if self.negate: axis = "-xz" else: axis = "xz" applyop.aimCns(self.tws1B_npo, self.tws2_loc, axis=axis, wupType=2, wupVector=[0, 0, 1], wupObject=self.mid_ctl, maintainOffset=False) applyop.aimCns(self.uplegTangentA_loc, self.uplegTangentB_npo, axis=axis, wupType=2, wupVector=[0, 0, 1], wupObject=self.mid_ctl, maintainOffset=False) # 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" # connecting tangent scaele compensation after volume to # avoid duplicate some nodes distA_node = node.createDistNode(self.tws0_loc, self.mid_ctl) distB_node = node.createDistNode(self.mid_ctl, self.tws2_loc) div_nodeUpLeg = node.createDivNode(distA_node + ".distance", dm_node.attr("outputScaleX")) div_node2 = node.createDivNode(div_nodeUpLeg + ".outputX", distA_node.attr("distance").get()) pm.connectAttr(div_node2.attr("outputX"), self.tws1A_loc.attr("sx")) pm.connectAttr(div_node2.attr("outputX"), self.uplegTangentA_loc.attr("sx")) div_nodeLowLeg = node.createDivNode(distB_node + ".distance", dm_node.attr("outputScaleX")) div_node2 = node.createDivNode(div_nodeLowLeg + ".outputX", distB_node.attr("distance").get()) pm.connectAttr(div_node2.attr("outputX"), self.tws1B_loc.attr("sx")) pm.connectAttr(div_node2.attr("outputX"), self.lowlegTangentB_loc.attr("sx")) # conection curve cnts = [ self.uplegTangentA_loc, self.uplegTangentA_ctl, self.uplegTangentB_ctl, self.kneeTangent_ctl ] applyop.gear_curvecns_op(self.uplegTwistCrv, cnts) cnts = [ self.kneeTangent_ctl, self.lowlegTangentA_ctl, self.lowlegTangentB_ctl, self.lowlegTangentB_loc ] applyop.gear_curvecns_op(self.lowlegTwistCrv, cnts) # Tangent controls vis for shp in self.uplegTangentA_ctl.getShapes(): pm.connectAttr(self.tangentVis_att, shp.attr("visibility")) for shp in self.uplegTangentB_ctl.getShapes(): pm.connectAttr(self.tangentVis_att, shp.attr("visibility")) for shp in self.lowlegTangentA_ctl.getShapes(): pm.connectAttr(self.tangentVis_att, shp.attr("visibility")) for shp in self.lowlegTangentB_ctl.getShapes(): pm.connectAttr(self.tangentVis_att, shp.attr("visibility")) for shp in self.kneeTangent_ctl.getShapes(): pm.connectAttr(self.tangentVis_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"] + 2): mulmat_node = applyop.gear_mulmatrix_op( self.uplegTwistChain[i] + ".worldMatrix", div_cns + ".parentInverseMatrix") lastUpLegDiv = div_cns else: o_node = self.lowlegTwistChain[i - (self.settings["div0"] + 2)] mulmat_node = applyop.gear_mulmatrix_op( o_node + ".worldMatrix", div_cns + ".parentInverseMatrix") lastLowLegDiv = div_cns dm_node = node.createDecomposeMatrixNode(mulmat_node + ".output") pm.connectAttr(dm_node + ".outputTranslate", div_cns + ".t") pm.connectAttr(dm_node + ".outputRotate", div_cns + ".r") # 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") # force translation for last loc arm and foreamr applyop.gear_mulmatrix_op(self.kneeTangent_ctl.worldMatrix, lastUpLegDiv.parentInverseMatrix, lastUpLegDiv, "t") applyop.gear_mulmatrix_op(self.tws2_loc.worldMatrix, lastLowLegDiv.parentInverseMatrix, lastLowLegDiv, "t") # 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. """ # 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")) for shp in self.line_ref.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 self.settings["supportJoints"]: 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) else: if i < (self.settings["div0"] + 1): perc = i * .5 / (self.settings["div0"] + 1.0) elif i < (self.settings["div0"] + 2): perc = .501 else: perc = .5 + \ (i - self.settings["div0"] - 1.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.0 - 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