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.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) self.tws0_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" 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 = 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): # Tangent position --------------------------------- # common part d = vec.getDistance(self.guide.pos["root"], self.guide.pos["neck"]) dist_node = nod.createDistNode(self.root, self.ik_ctl) rootWorld_node = nod.createDecomposeMatrixNode( self.root.attr("worldMatrix")) div_node = nod.createDivNode(dist_node + ".distance", rootWorld_node + ".outputScaleX") div_node = nod.createDivNode(div_node + ".outputX", d) # tan0 mul_node = nod.createMulNode(self.tan0_att, self.tan0_loc.getAttr("ty")) res_node = nod.createMulNode(mul_node + ".outputX", div_node + ".outputX") connectAttr(res_node + ".outputX", self.tan0_loc + ".ty") # tan1 mul_node = nod.createMulNode(self.tan1_att, self.tan1_loc.getAttr("ty")) res_node = nod.createMulNode(mul_node + ".outputX", div_node + ".outputX") connectAttr(res_node + ".outputX", self.tan1_loc.attr("ty")) # Curves ------------------------------------------- op = aop.gear_curveslide2_op(self.slv_crv, self.mst_crv, 0, 1.5, .5, .5) connectAttr(self.maxstretch_att, op + ".maxstretch") connectAttr(self.maxsquash_att, op + ".maxsquash") connectAttr(self.softness_att, op + ".softness") # Volume driver ------------------------------------ crv_node = nod.createCurveInfoNode(self.slv_crv) # Division ----------------------------------------- for i in range(self.settings["division"]): # References u = i / (self.settings["division"] - 1.0) cns = aop.pathCns(self.div_cns[i], self.slv_crv, False, u, True) cns.setAttr("frontAxis", 1) # front axis is 'Y' cns.setAttr("upAxis", 2) # front axis is 'Z' # Roll aop.gear_spinePointAtOp(cns, self.root, self.ik_ctl, u, "Z") # Squash n Stretch op = aop.gear_squashstretch2_op(self.fk_npo[i], self.root, arclen(self.slv_crv), "y") connectAttr(self.volume_att, op + ".blend") connectAttr(crv_node + ".arcLength", op + ".driver") connectAttr(self.st_att[i], op + ".stretch") connectAttr(self.sq_att[i], op + ".squash") # scl compas if i != 0: div_node = nod.createDivNode([1, 1, 1], [ self.fk_npo[i - 1] + ".sx", self.fk_npo[i - 1] + ".sy", self.fk_npo[i - 1] + ".sz" ]) connectAttr(div_node + ".output", self.scl_npo[i] + ".scale") # Controlers if i == 0: mulmat_node = aop.gear_mulmatrix_op( self.div_cns[i].attr("worldMatrix"), self.root.attr("worldInverseMatrix")) else: mulmat_node = aop.gear_mulmatrix_op( self.div_cns[i].attr("worldMatrix"), self.div_cns[i - 1].attr("worldInverseMatrix")) dm_node = nod.createDecomposeMatrixNode(mulmat_node + ".output") connectAttr(dm_node + ".outputTranslate", self.fk_npo[i].attr("t")) connectAttr(dm_node + ".outputRotate", self.fk_npo[i].attr("r")) #connectAttr(dm_node+".outputScale", self.fk_npo[i].attr("s")) # Orientation Lock if i == self.settings["division"] - 1: dm_node = nod.createDecomposeMatrixNode(self.ik_ctl + ".worldMatrix") blend_node = nod.createBlendNode( [dm_node + ".outputRotate%s" % s for s in "XYZ"], [cns + ".rotate%s" % s for s in "XYZ"], self.lock_ori_att) self.div_cns[i].attr("rotate").disconnect() connectAttr(blend_node + ".output", self.div_cns[i] + ".rotate") # Head --------------------------------------------- self.fk_ctl[-1].addChild(self.head_cns)
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.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): # 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 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") tra.matchWorldTransform(self.fk2_ctl, self.ikRot_cns) #scale: this fix the scalin popping issue intM_node = aop.gear_intmatrix_op(self.fk2_ctl.attr("worldMatrix"), self.ik_ctl_ref.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") if self.negate: mulVal = -1 else: mulVal = 1 nod.createMulNode(self.roll_att, mulVal, 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_twst_ref, self.tws1_npo, maintainOffset=False) pm.scaleConstraint(self.mid_ctl_twst_ref, self.tws1_npo, maintainOffset=False) pm.orientConstraint(self.mid_ctl_twst_ref, 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) if self.settings["ikTR"]: tra.matchWorldTransform(self.ikRot_ctl,self.match_ikRot ) tra.matchWorldTransform(self.fk_ctl[2], self.match_fk2 ) 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. """ # Auto bend ---------------------------- if self.settings["autoBend"]: mul_node = node.createMulNode( [self.autoBendChain[0].ry, self.autoBendChain[0].rz], [self.sideBend_att, self.frontBend_att]) mul_node.outputX >> self.ik1autoRot_lvl.rz mul_node.outputY >> self.ik1autoRot_lvl.rx self.ikHandleAutoBend = primitive.addIkHandle( self.autoBend_ctl, self.getName("ikHandleAutoBend"), self.autoBendChain, "ikSCsolver") # Tangent position --------------------------------- # common part d = vector.getDistance(self.guide.apos[0], self.guide.apos[1]) dist_node = node.createDistNode(self.ik0_ctl, self.ik1_ctl) rootWorld_node = node.createDecomposeMatrixNode( self.root.attr("worldMatrix")) div_node = node.createDivNode(dist_node + ".distance", rootWorld_node + ".outputScaleX") div_node = node.createDivNode(div_node + ".outputX", d) # tan0 mul_node = node.createMulNode(self.tan0_att, self.tan0_npo.getAttr("ty")) res_node = node.createMulNode(mul_node + ".outputX", div_node + ".outputX") pm.connectAttr(res_node + ".outputX", self.tan0_npo.attr("ty")) # tan1 mul_node = node.createMulNode(self.tan1_att, self.tan1_npo.getAttr("ty")) res_node = node.createMulNode(mul_node + ".outputX", div_node + ".outputX") pm.connectAttr(res_node + ".outputX", self.tan1_npo.attr("ty")) # Tangent Mid -------------------------------------- if self.settings["centralTangent"]: tanIntMat = applyop.gear_intmatrix_op( self.tan0_npo.attr("worldMatrix"), self.tan1_npo.attr("worldMatrix"), .5) applyop.gear_mulmatrix_op( tanIntMat.attr("output"), self.tan_npo.attr("parentInverseMatrix[0]"), self.tan_npo) pm.connectAttr(self.tan_ctl.attr("translate"), self.tan0_off.attr("translate")) pm.connectAttr(self.tan_ctl.attr("translate"), self.tan1_off.attr("translate")) # Curves ------------------------------------------- op = applyop.gear_curveslide2_op(self.slv_crv, self.mst_crv, 0, 1.5, .5, .5) pm.connectAttr(self.position_att, op + ".position") pm.connectAttr(self.maxstretch_att, op + ".maxstretch") pm.connectAttr(self.maxsquash_att, op + ".maxsquash") pm.connectAttr(self.softness_att, op + ".softness") # Volume driver ------------------------------------ crv_node = node.createCurveInfoNode(self.slv_crv) # Division ----------------------------------------- for i in range(self.settings["division"]): # References u = i / (self.settings["division"] - 1.0) cns = applyop.pathCns(self.div_cns[i], self.slv_crv, False, u, True) cns.setAttr("frontAxis", 1) # front axis is 'Y' cns.setAttr("upAxis", 0) # front axis is 'X' # Roll intMatrix = applyop.gear_intmatrix_op( self.ik0_ctl + ".worldMatrix", self.ik1_ctl + ".worldMatrix", u) dm_node = node.createDecomposeMatrixNode(intMatrix + ".output") pm.connectAttr(dm_node + ".outputRotate", self.twister[i].attr("rotate")) pm.parentConstraint(self.twister[i], self.ref_twist[i], maintainOffset=True) pm.connectAttr(self.ref_twist[i] + ".translate", cns + ".worldUpVector") # compensate scale reference div_node = node.createDivNode([1, 1, 1], [ rootWorld_node + ".outputScaleX", rootWorld_node + ".outputScaleY", rootWorld_node + ".outputScaleZ" ]) # Squash n Stretch op = applyop.gear_squashstretch2_op(self.scl_transforms[i], self.root, pm.arclen(self.slv_crv), "y", div_node + ".output") pm.connectAttr(self.volume_att, op + ".blend") pm.connectAttr(crv_node + ".arcLength", op + ".driver") pm.connectAttr(self.st_att[i], op + ".stretch") pm.connectAttr(self.sq_att[i], op + ".squash") # Controlers if i == 0: mulmat_node = applyop.gear_mulmatrix_op( self.div_cns[i].attr("worldMatrix"), self.root.attr("worldInverseMatrix")) dm_node = node.createDecomposeMatrixNode(mulmat_node + ".output") pm.connectAttr(dm_node + ".outputTranslate", self.fk_npo[i].attr("t")) else: mulmat_node = applyop.gear_mulmatrix_op( self.div_cns[i].attr("worldMatrix"), self.div_cns[i - 1].attr("worldInverseMatrix")) dm_node = node.createDecomposeMatrixNode(mulmat_node + ".output") mul_node = node.createMulNode(div_node + ".output", dm_node + ".outputTranslate") pm.connectAttr(mul_node + ".output", self.fk_npo[i].attr("t")) pm.connectAttr(dm_node + ".outputRotate", self.fk_npo[i].attr("r")) # Orientation Lock if i == 0: dm_node = node.createDecomposeMatrixNode(self.ik0_ctl + ".worldMatrix") blend_node = node.createBlendNode( [dm_node + ".outputRotate%s" % s for s in "XYZ"], [cns + ".rotate%s" % s for s in "XYZ"], self.lock_ori0_att) self.div_cns[i].attr("rotate").disconnect() pm.connectAttr(blend_node + ".output", self.div_cns[i] + ".rotate") elif i == self.settings["division"] - 1: dm_node = node.createDecomposeMatrixNode(self.ik1_ctl + ".worldMatrix") blend_node = node.createBlendNode( [dm_node + ".outputRotate%s" % s for s in "XYZ"], [cns + ".rotate%s" % s for s in "XYZ"], self.lock_ori1_att) self.div_cns[i].attr("rotate").disconnect() pm.connectAttr(blend_node + ".output", self.div_cns[i] + ".rotate") # Connections (Hooks) ------------------------------ pm.parentConstraint(self.scl_transforms[0], self.cnx0) pm.scaleConstraint(self.scl_transforms[0], self.cnx0) pm.parentConstraint(self.scl_transforms[-1], self.cnx1) pm.scaleConstraint(self.scl_transforms[-1], self.cnx1)
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. """ # Tangent position --------------------------------- # common part d = vector.getDistance(self.guide.pos["root"], self.guide.pos["neck"]) dist_node = node.createDistNode(self.root, self.ik_ctl) rootWorld_node = node.createDecomposeMatrixNode( self.root.attr("worldMatrix")) div_node = node.createDivNode(dist_node + ".distance", rootWorld_node + ".outputScaleX") div_node = node.createDivNode(div_node + ".outputX", d) # tan0 mul_node = node.createMulNode(self.tan0_att, self.tan0_loc.getAttr("ty")) res_node = node.createMulNode(mul_node + ".outputX", div_node + ".outputX") pm.connectAttr(res_node + ".outputX", self.tan0_loc + ".ty") # tan1 mul_node = node.createMulNode(self.tan1_att, self.tan1_loc.getAttr("ty")) res_node = node.createMulNode(mul_node + ".outputX", div_node + ".outputX") pm.connectAttr(res_node + ".outputX", self.tan1_loc.attr("ty")) # Curves ------------------------------------------- op = applyop.gear_curveslide2_op(self.slv_crv, self.mst_crv, 0, 1.5, .5, .5) pm.connectAttr(self.maxstretch_att, op + ".maxstretch") pm.connectAttr(self.maxsquash_att, op + ".maxsquash") pm.connectAttr(self.softness_att, op + ".softness") # Volume driver ------------------------------------ crv_node = node.createCurveInfoNode(self.slv_crv) # Division ----------------------------------------- for i in range(self.settings["division"]): # References u = i / (self.settings["division"] - 1.0) cns = applyop.pathCns(self.div_cns[i], self.slv_crv, False, u, True) cns.setAttr("frontAxis", 1) # front axis is 'Y' cns.setAttr("upAxis", 2) # front axis is 'Z' # Roll intMatrix = applyop.gear_intmatrix_op( self.intMRef + ".worldMatrix", self.ik_ctl + ".worldMatrix", u) dm_node = node.createDecomposeMatrixNode(intMatrix + ".output") pm.connectAttr(dm_node + ".outputRotate", self.twister[i].attr("rotate")) pm.parentConstraint(self.twister[i], self.ref_twist[i], maintainOffset=True) pm.connectAttr(self.ref_twist[i] + ".translate", cns + ".worldUpVector") # Squash n Stretch op = applyop.gear_squashstretch2_op(self.fk_npo[i], self.root, pm.arclen(self.slv_crv), "y") pm.connectAttr(self.volume_att, op + ".blend") pm.connectAttr(crv_node + ".arcLength", op + ".driver") pm.connectAttr(self.st_att[i], op + ".stretch") pm.connectAttr(self.sq_att[i], op + ".squash") op.setAttr("driver_min", .1) # scl compas if i != 0: div_node = node.createDivNode([1, 1, 1], [ self.fk_npo[i - 1] + ".sx", self.fk_npo[i - 1] + ".sy", self.fk_npo[i - 1] + ".sz" ]) pm.connectAttr(div_node + ".output", self.scl_npo[i] + ".scale") # Controlers if i == 0: mulmat_node = applyop.gear_mulmatrix_op( self.div_cns[i].attr("worldMatrix"), self.root.attr("worldInverseMatrix")) else: mulmat_node = applyop.gear_mulmatrix_op( self.div_cns[i].attr("worldMatrix"), self.div_cns[i - 1].attr("worldInverseMatrix")) dm_node = node.createDecomposeMatrixNode(mulmat_node + ".output") pm.connectAttr(dm_node + ".outputTranslate", self.fk_npo[i].attr("t")) pm.connectAttr(dm_node + ".outputRotate", self.fk_npo[i].attr("r")) # Orientation Lock if i == self.settings["division"] - 1: dm_node = node.createDecomposeMatrixNode(self.ik_ctl + ".worldMatrix") blend_node = node.createBlendNode( [dm_node + ".outputRotate%s" % s for s in "XYZ"], [cns + ".rotate%s" % s for s in "XYZ"], self.lock_ori_att) self.div_cns[i].attr("rotate").disconnect() pm.connectAttr(blend_node + ".output", self.div_cns[i] + ".rotate") # Head --------------------------------------------- self.fk_ctl[-1].addChild(self.head_cns) # scale compensation dm_node = node.createDecomposeMatrixNode(self.scl_npo[0] + ".parentInverseMatrix") pm.connectAttr(dm_node + ".outputScale", self.scl_npo[0] + ".scale")
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): # Tangent position --------------------------------- # common part d = vec.getDistance(self.guide.apos[0], self.guide.apos[1]) dist_node = nod.createDistNode(self.ik0_ctl, self.ik1_ctl) rootWorld_node = nod.createDecomposeMatrixNode(self.root.attr("worldMatrix")) div_node = nod.createDivNode(dist_node+".distance", rootWorld_node+".outputScaleX") div_node = nod.createDivNode(div_node+".outputX", d) # tan0 mul_node = nod.createMulNode(self.tan0_att, self.tan0_npo.getAttr("ty")) res_node = nod.createMulNode(mul_node+".outputX", div_node+".outputX") pm.connectAttr( res_node+".outputX", self.tan0_npo.attr("ty")) # tan1 mul_node = nod.createMulNode(self.tan1_att, self.tan1_npo.getAttr("ty")) res_node = nod.createMulNode(mul_node+".outputX", div_node+".outputX") pm.connectAttr( res_node+".outputX", self.tan1_npo.attr("ty")) # Curves ------------------------------------------- op = aop.gear_curveslide2_op(self.slv_crv, self.mst_crv, 0, 1.5, .5, .5) pm.connectAttr(self.position_att, op+".position") pm.connectAttr(self.maxstretch_att, op+".maxstretch") pm.connectAttr(self.maxsquash_att, op+".maxsquash") pm.connectAttr(self.softness_att, op+".softness") # Volume driver ------------------------------------ crv_node = nod.createCurveInfoNode(self.slv_crv) # Division ----------------------------------------- for i in range(self.settings["division"]): # References u = i / (self.settings["division"] - 1.0) cns = aop.pathCns(self.div_cns[i], self.slv_crv, False, u, True) cns.setAttr("frontAxis", 1)# front axis is 'Y' cns.setAttr("upAxis", 0)# front axis is 'X' # Roll intMatrix = aop.gear_intmatrix_op(self.ik0_ctl+".worldMatrix", self.ik1_ctl+".worldMatrix", u) dm_node = nod.createDecomposeMatrixNode(intMatrix+".output") pm.connectAttr(dm_node+".outputRotate", self.twister[i].attr("rotate")) pm.parentConstraint(self.twister[i], self.ref_twist[i], maintainOffset=True) pm.connectAttr(self.ref_twist[i]+".translate", cns+".worldUpVector") # Squash n Stretch op = aop.gear_squashstretch2_op(self.fk_npo[i], self.root, pm.arclen(self.slv_crv), "y") pm.connectAttr(self.volume_att, op+".blend") pm.connectAttr(crv_node+".arcLength", op+".driver") pm.connectAttr(self.st_att[i], op+".stretch") pm.connectAttr(self.sq_att[i], op+".squash") # scl compensation if i == 0: dm_node = nod.createDecomposeMatrixNode(self.root+".worldMatrix") div_node = nod.createDivNode([1,1,1], [dm_node+".outputScaleX", dm_node+".outputScaleY", dm_node+".outputScaleZ"]) pm.connectAttr(div_node+".output", self.scl_npo[i]+".scale") elif i == 1: div_node = nod.createDivNode([1,1,1], [self.fk_npo[i-1]+".sx", self.fk_npo[i-1]+".sy", self.fk_npo[i-1]+".sz"]) pm.connectAttr(div_node+".output", self.scl_npo[i]+".scale") else: div_node = nod.createDivNode([1,1,1], [self.fk_npo[i-1]+".sx", self.fk_npo[i-1]+".sy", self.fk_npo[i-1]+".sz"]) pm.connectAttr(div_node+".output", self.scl_npo[i]+".scale") # Controlers if i == 0: mulmat_node = aop.gear_mulmatrix_op(self.div_cns[i].attr("worldMatrix"), self.scl_npo[0].attr("worldInverseMatrix")) else: mulmat_node = aop.gear_mulmatrix_op(self.div_cns[i].attr("worldMatrix"), self.div_cns[i - 1].attr("worldInverseMatrix")) dm_node = nod.createDecomposeMatrixNode(mulmat_node+".output") pm.connectAttr(dm_node+".outputTranslate", self.fk_npo[i].attr("t")) pm.connectAttr(dm_node+".outputRotate", self.fk_npo[i].attr("r")) # Orientation Lock if i == 0 : dm_node = nod.createDecomposeMatrixNode(self.ik0_ctl+".worldMatrix") blend_node = nod.createBlendNode([dm_node+".outputRotate%s"%s for s in "XYZ"], [cns+".rotate%s"%s for s in "XYZ"], self.lock_ori0_att) self.div_cns[i].attr("rotate").disconnect() pm.connectAttr(blend_node+".output", self.div_cns[i]+".rotate") elif i == self.settings["division"] - 1 : dm_node = nod.createDecomposeMatrixNode(self.ik1_ctl+".worldMatrix") blend_node = nod.createBlendNode([dm_node+".outputRotate%s"%s for s in "XYZ"], [cns+".rotate%s"%s for s in "XYZ"], self.lock_ori1_att) self.div_cns[i].attr("rotate").disconnect() pm.connectAttr(blend_node+".output", self.div_cns[i]+".rotate") # Connections (Hooks) ------------------------------ pm.pointConstraint(self.div_cns[0], self.cnx0) pm.orientConstraint(self.div_cns[0], self.cnx0) pm.pointConstraint(self.fk_ctl[-1], self.cnx1) pm.orientConstraint(self.fk_ctl[-1], self.cnx1)
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")) for shp in self.fk1_roll_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")) # 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 ----------------------------------- att.setRotOrder(self.ik_ctl, "XZY") # 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.fk0_mtx, self.fk1_mtx, self.fk2_mtx, self.length0, self.length1, self.negate) pm.connectAttr(self.blend_att, node+".blend") if self.negate: mulVal = -1 else: mulVal = 1 nod.createMulNode(self.roll_att, mulVal, node+".roll") # 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") # update issue on effector scale interpolation, disconnect for stability pm.disconnectAttr(self.eff_npo.scale) # auto upvector ------------------------------------- # leg aim node = aop.aimCns(self.upv_auv, self.ik_ctl, axis="-yz", wupType=1, wupVector=[0,1,0], wupObject=self.upv2_auv, maintainOffset=False) # foot aim node = aop.aimCns(self.upv1_auv, self.root, axis="yz", wupType=4, wupVector=[0,1,0], wupObject=self.root, maintainOffset=False) # auto upvector connection node = aop.gear_mulmatrix_op(self.upv_auv.attr("worldMatrix"), self.upv_mtx.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(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 parent constraint node = aop.gear_mulmatrix_op(self.fk0_roll_ctl.attr("worldMatrix"), self.fk0_mtx.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(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 to fk1 ref parent constraint node = aop.gear_mulmatrix_op(self.fk1_ref.attr("worldMatrix"), self.fk1_loc.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(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------------------------ node = aop.gear_mulmatrix_op(self.eff_npo.attr("worldMatrix"), self.fk2_loc.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(node+".output", dm_node+".inputMatrix") pm.connectAttr(dm_node+".outputTranslate", self.fk2_loc.attr("translate")) # fk2_loc rotation constraint to bone1 ------------------------ node = aop.gear_mulmatrix_op(self.bone1.attr("worldMatrix"), self.fk2_loc.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(node+".output", dm_node+".inputMatrix") pm.connectAttr(dm_node+".outputRotate", self.fk2_loc.attr("rotate")) # foot 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_node1 = pm.createNode("decomposeMatrix") pm.connectAttr(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")) node = aop.gear_mulmatrix_op(self.eff_loc.attr("worldMatrix"), self.tws3_npo.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(node+".output", dm_node+".inputMatrix") pm.connectAttr(dm_node+".outputTranslate", self.tws3_npo.attr("translate")) node = aop.gear_mulmatrix_op(self.bone1.attr("worldMatrix"), self.tws3_npo.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(node+".output", dm_node+".inputMatrix") pm.connectAttr(dm_node+".outputRotate", self.tws3_npo.attr("rotate")) node = aop.gear_mulmatrix_op(self.tws_ref.attr("worldMatrix"), self.tws3_rot.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(node+".output", dm_node+".inputMatrix") pm.connectAttr(dm_node+".outputRotate", self.tws3_rot.attr("rotate")) # knee thickness connection if self.negate: node = nod.createMulNode([self.knee_thickness_att,self.knee_thickness_att], [0.5,-0.5,0], [self.tws1_loc+".translateX",self.tws2_loc+".translateX"]) else: node = nod.createMulNode([self.knee_thickness_att,self.knee_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 = nod.createAddNode(self.roundness0_att, .001) pm.connectAttr(add_node+".output", self.tws1_rot.attr("sx")) add_node = nod.createAddNode(self.roundness1_att, .001) pm.connectAttr(add_node+".output", self.tws2_rot.attr("sx")) #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_npo) distB_node = nod.createDistNode(self.tws1_npo, self.tws3_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 ---------------------------------------- # div mid constraint to mid ctl node = aop.gear_mulmatrix_op(self.mid_ctl.attr("worldMatrix"), self.div_mid.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(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 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: node = aop.gear_rollsplinekine_op(div_cnsUp, [self.tws1_rot, self.tws0_rot], 1-perc, 20) else: node = aop.gear_rollsplinekine_op(div_cnsUp, [self.tws0_rot, self.tws1_rot], perc, 20) pm.connectAttr(self.resample_att, node+".resample") pm.connectAttr(self.absolute_att, 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: node = aop.gear_rollsplinekine_op(div_cnsDn, [self.tws3_rot, self.tws2_rot], 1-perc, 20) else: node = aop.gear_rollsplinekine_op(div_cnsDn, [self.tws2_rot, self.tws3_rot], perc, 20) pm.connectAttr(self.resample_att, node+".resample") pm.connectAttr(self.absolute_att, 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): 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") # get the first mult_node after sq op mult_node = pm.listHistory(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): # Visibilities ------------------------------------- #shape.dispGeometry # 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) cns = aop.aimCns(self.tws0_loc, self.mid_ctl, self.n_sign+"xz", 2, [-1,0,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.tws_ref, self.tws2_rot, maintainOffset=False) # 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): if self.settings["ikSolver"]: self.ikSolver = "ikRPsolver" else: pm.mel.eval("ikSpringSolver;") self.ikSolver = "ikSpringSolver" # 1 bone chain Upv ref ===================================================================================== self.ikHandleUpvRef = pri.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]): nod.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 = nod.createMulNode(self.boneALenght_attr, self.boneALenghtMult_attr) multJnt2_node = nod.createMulNode(self.boneBLenght_attr, self.boneBLenghtMult_attr) multJnt3_node = nod.createMulNode(self.boneCLenght_attr, self.boneCLenghtMult_attr) # # IK 3 bones ====================================================================================================== self.ikHandle = pri.addIkHandle(self.softblendLoc, self.getName("ik3BonesHandle"), self.chain3bones, self.ikSolver, self.upv_ctl) # TwistTest if [ round(elem, 4) for elem in tra.getTranslation(self.chain3bones[1]) ] != [round(elem, 4) for elem in self.guide.apos[1]]: add_nodeTwist = nod.createAddNode(180.0, self.roll_att) # pm.connectAttr(add_nodeTwist+".output", self.ikHandle.attr("twist")) else: add_nodeTwist = nod.createAddNode(0, self.roll_att) # pm.connectAttr(self.roll_att, self.ikHandle.attr("twist")) if self.negate: mulVal = 1 else: mulVal = -1 nod.createMulNode(add_nodeTwist + ".output", mulVal, self.ikHandle.attr("twist")) # pm.connectAttr(add_nodeTwist+".output", self.ikHandle.attr("twist")) # stable spring solver doble rotation pm.pointConstraint(self.root_ctl, self.chain3bones[0]) # softIK 3 bones operators aop.aimCns(self.aim_tra, self.ik_ref, axis="zx", wupType=4, wupVector=[1, 0, 0], wupObject=self.root_ctl, maintainOffset=False) plusTotalLength_node = nod.createPlusMinusAverage1D([ multJnt1_node.attr("outputX"), multJnt2_node.attr("outputX"), multJnt3_node.attr("outputX") ]) subtract1_node = nod.createPlusMinusAverage1D( [plusTotalLength_node.attr("output1D"), self.soft_attr], 2) distance1_node = nod.createDistNode(self.ik_ref, self.aim_tra) div1_node = nod.createDivNode(1.0, self.rig.global_ctl + ".sx") mult1_node = nod.createMulNode(distance1_node + ".distance", div1_node + ".outputX") subtract2_node = nod.createPlusMinusAverage1D( [mult1_node.attr("outputX"), subtract1_node.attr("output1D")], 2) div2_node = nod.createDivNode(subtract2_node + ".output1D", self.soft_attr) mult2_node = nod.createMulNode(-1, div2_node + ".outputX") power_node = nod.createPowNode(self.softSpeed_attr, mult2_node + ".outputX") mult3_node = nod.createMulNode(self.soft_attr, power_node + ".outputX") subtract3_node = nod.createPlusMinusAverage1D([ plusTotalLength_node.attr("output1D"), mult3_node.attr("outputX") ], 2) cond1_node = nod.createConditionNode( self.soft_attr, 0, 2, subtract3_node + ".output1D", plusTotalLength_node + ".output1D") cond2_node = nod.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) nod.createReverseNode(self.stretch_attr, pc_node + ".target[0].targetWeight") pm.connectAttr(self.stretch_attr, pc_node + ".target[1].targetWeight", f=True) #Stretch distance2_node = nod.createDistNode(self.softblendLoc, self.wristSoftIK) mult4_node = nod.createMulNode(distance2_node + ".distance", div1_node + ".outputX") #bones for i, mulNode in enumerate( [multJnt1_node, multJnt2_node, multJnt3_node]): div3_node = nod.createDivNode(mulNode + ".outputX", plusTotalLength_node + ".output1D") mult5_node = nod.createMulNode(mult4_node + ".outputX", div3_node + ".outputX") mult6_node = nod.createMulNode(self.stretch_attr, mult5_node + ".outputX") nod.createPlusMinusAverage1D( [mulNode.attr("outputX"), mult6_node.attr("outputX")], 1, self.chain3bones[i + 1] + ".tx") # IK 2 bones ====================================================================================================== self.ikHandle2 = pri.addIkHandle(self.softblendLoc2, self.getName("ik2BonesHandle"), self.chain2bones, self.ikSolver, self.upv_ctl) nod.createMulNode(self.roll_att, mulVal, self.ikHandle2.attr("twist")) # pm.connectAttr(self.roll_att, 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) nod.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 aop.aimCns(self.aim_tra2, self.ik2b_ik_ref, axis="zx", wupType=4, wupVector=[1, 0, 0], wupObject=self.root_ctl, maintainOffset=False) plusTotalLength_node = nod.createPlusMinusAverage1D( [multJnt1_node.attr("outputX"), multJnt2_node.attr("outputX")]) subtract1_node = nod.createPlusMinusAverage1D( [plusTotalLength_node.attr("output1D"), self.soft_attr], 2) distance1_node = nod.createDistNode(self.ik2b_ik_ref, self.aim_tra2) div1_node = nod.createDivNode(1, self.rig.global_ctl + ".sx") mult1_node = nod.createMulNode(distance1_node + ".distance", div1_node + ".outputX") subtract2_node = nod.createPlusMinusAverage1D( [mult1_node.attr("outputX"), subtract1_node.attr("output1D")], 2) div2_node = nod.createDivNode(subtract2_node + ".output1D", self.soft_attr) mult2_node = nod.createMulNode(-1, div2_node + ".outputX") power_node = nod.createPowNode(self.softSpeed_attr, mult2_node + ".outputX") mult3_node = nod.createMulNode(self.soft_attr, power_node + ".outputX") subtract3_node = nod.createPlusMinusAverage1D([ plusTotalLength_node.attr("output1D"), mult3_node.attr("outputX") ], 2) cond1_node = nod.createConditionNode( self.soft_attr, 0, 2, subtract3_node + ".output1D", plusTotalLength_node + ".output1D") cond2_node = nod.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) nod.createReverseNode(self.stretch_attr, pc_node + ".target[0].targetWeight") pm.connectAttr(self.stretch_attr, pc_node + ".target[1].targetWeight", f=True) #Stretch distance2_node = nod.createDistNode(self.softblendLoc2, self.ankleSoftIK) mult4_node = nod.createMulNode(distance2_node + ".distance", div1_node + ".outputX") for i, mulNode in enumerate([multJnt1_node, multJnt2_node]): div3_node = nod.createDivNode(mulNode + ".outputX", plusTotalLength_node + ".output1D") mult5_node = nod.createMulNode(mult4_node + ".outputX", div3_node + ".outputX") mult6_node = nod.createMulNode(self.stretch_attr, mult5_node + ".outputX") nod.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]) aop.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) nod.createMulNode(-1, self.chain3bones[-1].attr("tx"), self.ik2b_ik_ref.attr("tx")) for i, x in enumerate(self.legBones): nod.createPairBlend(self.legBonesFK[i], self.legBonesIK[i], self.blend_att, 1, x) # Twist references ---------------------------------------- self.ikhArmRef, self.tmpCrv = aop.splineIK(self.getName("legRollRef"), self.rollRef, parent=self.root, cParent=self.legBones[0]) initRound = .001 multVal = 1 multTangent_node = nod.createMulNode(self.roundnessKnee_att, multVal) add_node = nod.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 = nod.createMulNode(self.roundnessAnkle_att, multVal) add_node = nod.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 = nod.createDistNode(self.tws0_loc, self.tws1_loc) distB_node = nod.createDistNode(self.tws1_loc, self.tws2_loc) distC_node = nod.createDistNode(self.tws2_loc, self.tws3_loc) add_node = nod.createAddNode(distA_node + ".distance", distB_node + ".distance") add_node2 = nod.createAddNode(distC_node + ".distance", add_node + ".output") div_node = nod.createDivNode(add_node2 + ".output", self.root_ctl.attr("sx")) #comp scaling dm_node = nod.createDecomposeMatrixNode(self.root.attr("worldMatrix")) div_node2 = nod.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 node = aop.gear_rollsplinekine_op( div_cns, [self.tws0_rot, self.tws1_rot, self.tws2_rot, self.tws3_rot], perc, subdiv) 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") # Visibilities ------------------------------------- # fk fkvis_node = nod.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 node scale compensate pm.connectAttr(self.rig.global_ctl + ".scale", self.setup + ".scale") return
def addOperators(self): # Tangent position --------------------------------- # common part d = vec.getDistance(self.guide.pos["root"], self.guide.pos["neck"]) dist_node = nod.createDistNode(self.root, self.ik_ctl) rootWorld_node = nod.createDecomposeMatrixNode(self.root.attr("worldMatrix")) div_node = nod.createDivNode(dist_node+".distance", rootWorld_node+".outputScaleX") div_node = nod.createDivNode(div_node+".outputX", d) # tan0 mul_node = nod.createMulNode(self.tan0_att, self.tan0_loc.getAttr("ty")) res_node = nod.createMulNode(mul_node+".outputX", div_node+".outputX") connectAttr( res_node+".outputX", self.tan0_loc+".ty") # tan1 mul_node = nod.createMulNode(self.tan1_att, self.tan1_loc.getAttr("ty")) res_node = nod.createMulNode(mul_node+".outputX", div_node+".outputX") connectAttr( res_node+".outputX", self.tan1_loc.attr("ty")) # Curves ------------------------------------------- op = aop.gear_curveslide2_op(self.slv_crv, self.mst_crv, 0, 1.5, .5, .5) connectAttr(self.maxstretch_att, op+".maxstretch") connectAttr(self.maxsquash_att, op+".maxsquash") connectAttr(self.softness_att, op+".softness") # Volume driver ------------------------------------ crv_node = nod.createCurveInfoNode(self.slv_crv) # Division ----------------------------------------- for i in range(self.settings["division"]): # References u = i / (self.settings["division"] - 1.0) cns = aop.pathCns(self.div_cns[i], self.slv_crv, False, u, True) cns.setAttr("frontAxis", 1)# front axis is 'Y' cns.setAttr("upAxis", 2)# front axis is 'Z' # Roll aop.gear_spinePointAtOp(cns, self.root, self.ik_ctl, u, "Z") # Squash n Stretch op = aop.gear_squashstretch2_op(self.fk_npo[i], self.root, arclen(self.slv_crv), "y") connectAttr(self.volume_att, op+".blend") connectAttr(crv_node+".arcLength", op+".driver") connectAttr(self.st_att[i], op+".stretch") connectAttr(self.sq_att[i], op+".squash") # scl compas if i != 0: div_node = nod.createDivNode([1,1,1], [self.fk_npo[i-1]+".sx", self.fk_npo[i-1]+".sy", self.fk_npo[i-1]+".sz"]) connectAttr(div_node+".output", self.scl_npo[i]+".scale") # Controlers if i == 0: mulmat_node = aop.gear_mulmatrix_op(self.div_cns[i].attr("worldMatrix"), self.root.attr("worldInverseMatrix")) else: mulmat_node = aop.gear_mulmatrix_op(self.div_cns[i].attr("worldMatrix"), self.div_cns[i-1].attr("worldInverseMatrix")) dm_node = nod.createDecomposeMatrixNode(mulmat_node+".output") connectAttr(dm_node+".outputTranslate", self.fk_npo[i].attr("t")) connectAttr(dm_node+".outputRotate", self.fk_npo[i].attr("r")) #connectAttr(dm_node+".outputScale", self.fk_npo[i].attr("s")) # Orientation Lock if i == self.settings["division"] - 1 : dm_node = nod.createDecomposeMatrixNode(self.ik_ctl+".worldMatrix") blend_node = nod.createBlendNode([dm_node+".outputRotate%s"%s for s in "XYZ"], [cns+".rotate%s"%s for s in "XYZ"], self.lock_ori_att) self.div_cns[i].attr("rotate").disconnect() connectAttr(blend_node+".output", self.div_cns[i]+".rotate") # Head --------------------------------------------- self.fk_ctl[-1].addChild(self.head_cns)