def addJoint(self, obj, name, newActiveJnt=None, UniScale=True): """ Add joint as child of the active joint or under driver object. Args: obj (dagNode): The input driver object for the joint. name (str): The joint name. newActiveJnt (bool or dagNode): If a joint is pass, this joint will be the active joint and parent of the newly created joint. Returns: dagNode: The newly created joint. """ if self.options["joint_rig"]: if newActiveJnt: self.active_jnt = newActiveJnt jnt = pri.addJoint(self.active_jnt, self.getName(str(name) + "_jnt"), tra.getTransform(obj)) #All new jnts are the active by default self.active_jnt = jnt mulmat_node = nod.createMultMatrixNode(obj + ".worldMatrix", jnt + ".parentInverseMatrix") dm_node = nod.createDecomposeMatrixNode(mulmat_node+".matrixSum") pm.connectAttr(dm_node+".outputTranslate", jnt+".t") pm.connectAttr(dm_node+".outputRotate", jnt+".r") # TODO: fix squash stretch solver to scale the joint uniform # the next line cheat the uniform scaling only fo X or Y axis oriented joints if UniScale: pm.connectAttr(dm_node+".outputScaleZ", jnt+".sx") pm.connectAttr(dm_node+".outputScaleZ", jnt+".sy") pm.connectAttr(dm_node+".outputScaleZ", jnt+".sz") else: pm.connectAttr(dm_node+".outputScale", jnt+".s") # Segment scale compensate Off to avoid issues with the global scale jnt.setAttr("segmentScaleCompensate", 0) jnt.setAttr("jointOrient", 0, 0, 0) # setting the joint orient compensation in order to have clean rotation channels jnt.attr("jointOrientX").set(jnt.attr("rx").get()) jnt.attr("jointOrientY").set(jnt.attr("ry").get()) jnt.attr("jointOrientZ").set(jnt.attr("rz").get()) m = mulmat_node.attr('matrixSum').get() im = m.inverse() mulmat_node2 = nod.createMultMatrixNode(mulmat_node.attr('matrixSum'), im, jnt,'r') else: jnt = pri.addJoint(obj, self.getName(str(name)+"_jnt"), tra.getTransform(obj)) pm.connectAttr(self.rig.jntVis_att, jnt.attr("visibility")) self.addToGroup(jnt, "deformers") return jnt
def createJntTweak(mesh, parentJnt, ctlParent): """Create a joint tweak Args: mesh (mesh): The object to deform with the tweak parentJnt (dagNode): The parent for the new joint ctlParent (dagNode): The parent for the control. """ if not isinstance(mesh, list): mesh = [mesh] name = "_".join(parentJnt.name().split("_")[:3]) # create joints jointBase = primitive.addJoint(parentJnt, name + "_tweak_jnt_lvl", parentJnt.getMatrix(worldSpace=True)) resetJntLocalSRT(jointBase) joint = primitive.addJoint(jointBase, name + "_tweak_jnt", parentJnt.getMatrix(worldSpace=True)) resetJntLocalSRT(joint) # hidding joint base by changing the draw mode # pm.setAttr(jointBase+".drawStyle", 2) try: defSet = pm.PyNode("rig_deformers_grp") except TypeError: pm.sets(n="rig_deformers_grp") defSet = pm.PyNode("rig_deformers_grp") pm.sets(defSet, add=joint) controlType = "circle" iconBase = icon.create(ctlParent, name + "_base_tweak_ctl", ctlParent.getMatrix(worldSpace=True), 13, controlType, w=.8, ro=datatypes.Vector(0, 0, 1.5708)) o_icon = icon.create(iconBase, name + "_tweak_ctl", ctlParent.getMatrix(worldSpace=True), 17, controlType, w=.5, ro=datatypes.Vector(0, 0, 1.5708)) for t in [".translate", ".scale", ".rotate"]: pm.connectAttr(iconBase + t, jointBase + t) pm.connectAttr(o_icon + t, joint + t) # magic of doritos connection for m in mesh: doritosMagic(m, joint, jointBase)
def doritosMagic(mesh, joint, jointBase, parent=None): # magic of doritos connection skinCluster = skin.getSkinCluster(mesh) if not skinCluster: if pm.objExists('static_jnt') is not True: static_jnt = primitive.addJoint(parent, "static_jnt", m=datatypes.Matrix(), vis=True) static_jnt = pm.PyNode("static_jnt") # apply initial skincluster skinCluster = pm.skinCluster(static_jnt, mesh, tsb=True, nw=2, n='%s_skinCluster' % mesh.name()) try: # we try to add the joint to the skin cluster. Will fail if is already # in the skin cluster pm.skinCluster(skinCluster, e=True, ai=joint, lw=True, wt=0) except Exception: pm.displayInfo("The Joint: %s is already in the %s." % (joint.name(), skinCluster.name())) pass cn = joint.listConnections(p=True, type="skinCluster") for x in cn: if x.type() == "matrix": if x.name().split(".")[0] == skinCluster.name(): # We force to avoid errors in case the joint is already # connected pm.connectAttr(jointBase + ".worldInverseMatrix[0]", skinCluster + ".bindPreMatrix[" + str(x.index()) + "]", f=True)
def addShadow(self, obj, name): if self.options["shadow_rig"]: shd = pri.addJoint(self.shd_org, self.getName(str(name)+"_shd"), tra.getTransform(obj)) shd.setAttr("jointOrient", 0, 0, 0) # parentConstraint(obj, shd, maintainOffset=False) # scaleConstraint(obj, shd, maintainOffset=False) mulmat_node = aop.gear_mulmatrix_op(obj+".worldMatrix", shd+".parentInverseMatrix") dm_node = nod.createDecomposeMatrixNode(mulmat_node+".output") connectAttr(dm_node+".outputTranslate", shd+".t") connectAttr(dm_node+".outputRotate", shd+".r") connectAttr(dm_node+".outputScale", shd+".s") self.shd_org = shd else: shd = pri.addJoint(obj, self.getName(str(name)+"_shd"), tra.getTransform(obj)) shd.setAttr("jointOrient", 0, 0, 0) shd.setAttr("rotate", 0, 0, 0) connectAttr(self.rig.shdVis_att, shd.attr("visibility")) self.addToGroup(shd, "deformers") return shd
def createRivetTweakLayer(layerMesh, bst, edgeList, tweakName, parent=None, ctlParent=None): """Create a rivet tweak layer Args: layerMesh (mesh): The tweak layer mesh bst (mesh): The mesh blendshape target edgeList (list): List of edges tweakName (string): The name for the tweak parent (None or dagNode, optional): The parent for the tweak ctlParent (None or dagNode, optional): the parent for the tweak control """ # Apply blendshape from blendshapes layer mesh blendShapes.connectWithBlendshape(layerMesh, bst) # create static joint if pm.objExists('static_jnt') is not True: static_jnt = primitive.addJoint(parent, "static_jnt", m=datatypes.Matrix(), vis=True) static_jnt = pm.PyNode("static_jnt") # apply initial skincluster pm.skinCluster(static_jnt, layerMesh, tsb=True, nw=2, n='%s_skinCluster' % layerMesh.name()) # create doritos createRivetTweak(layerMesh, edgeList, tweakName, parent, ctlParent)
def createRivetTweak(mesh, edgePair, name, parent=None, ctlParent=None, color=[0, 0, 0], size=.04, defSet=None): """Create a tweak joint attached to the mesh using a rivet Args: mesh (mesh): The object to add the tweak edgePair (pari list): The edge pairt to create the rivet name (str): The name for the tweak parent (None or dagNode, optional): The parent for the tweak ctlParent (None or dagNode, optional): The parent for the tweak control color (list, optional): The color for the control """ blendShape = blendShapes.getBlendShape(mesh) inputMesh = blendShape.listConnections(sh=True, t="shape", d=False)[0] oRivet = rivet.rivet() base = oRivet.create(inputMesh, edgePair[0], edgePair[1], parent) # get side if base.getTranslation(space='world')[0] < -0.01: side = "R" elif base.getTranslation(space='world')[0] > 0.01: side = "L" else: side = "C" nameSide = name + "_tweak_" + side pm.rename(base, nameSide) # Joints NPO npo = pm.PyNode( pm.createNode("transform", n=nameSide + "_npo", p=ctlParent, ss=True)) pm.pointConstraint(base, npo) # set proper orientation pos = base.getTranslation(space="world") temp = pm.spaceLocator() pm.parent(temp, base) temp.attr("ty").set(0) temp.attr("tz").set(0) temp.attr("tx").set(1) lookat = temp.getTranslation(space="world") up = datatypes.Vector(0, 1, 0) t = transform.getTransformLookingAt(pos, lookat, up, axis="xy", negate=False) npo.setMatrix(t, worldSpace=True) pm.delete(temp) # create joints jointBase = primitive.addJoint(npo, nameSide + "_jnt_lvl") joint = primitive.addJoint(jointBase, nameSide + "_jnt") # hidding joint base by changing the draw mode pm.setAttr(jointBase + ".drawStyle", 2) if not defSet: try: defSet = pm.PyNode("rig_deformers_grp") except TypeError: pm.sets(n="rig_deformers_grp") defSet = pm.PyNode("rig_deformers_grp") pm.sets(defSet, add=joint) controlType = "sphere" o_icon = icon.create(jointBase, nameSide + "_ctl", datatypes.Matrix(), color, controlType, w=size) for t in [".translate", ".scale", ".rotate"]: pm.connectAttr(o_icon + t, joint + t) # create the attributes to handlde mirror and symetrical pose attribute.addAttribute(o_icon, "invTx", "bool", 0, keyable=False, niceName="Invert Mirror TX") attribute.addAttribute(o_icon, "invTy", "bool", 0, keyable=False, niceName="Invert Mirror TY") attribute.addAttribute(o_icon, "invTz", "bool", 0, keyable=False, niceName="Invert Mirror TZ") attribute.addAttribute(o_icon, "invRx", "bool", 0, keyable=False, niceName="Invert Mirror RX") attribute.addAttribute(o_icon, "invRy", "bool", 0, keyable=False, niceName="Invert Mirror RY") attribute.addAttribute(o_icon, "invRz", "bool", 0, keyable=False, niceName="Invert Mirror RZ") attribute.addAttribute(o_icon, "invSx", "bool", 0, keyable=False, niceName="Invert Mirror SX") attribute.addAttribute(o_icon, "invSy", "bool", 0, keyable=False, niceName="Invert Mirror SY") attribute.addAttribute(o_icon, "invSz", "bool", 0, keyable=False, niceName="Invert Mirror SZ") # magic of doritos connection doritosMagic(mesh, joint, jointBase) # reset axis and inver behaviour for axis in "XYZ": pm.setAttr(jointBase + ".jointOrient" + axis, 0) pm.setAttr(npo + ".translate" + axis, 0) pm.setAttr(jointBase + ".translate" + axis, 0) p = o_icon.getParent().getParent() pp = p.getParent() pm.parent(p, w=True) for axis in "xyz": p.attr("r" + axis).set(0) if side == "R": p.attr("ry").set(180) p.attr("sz").set(-1) pm.parent(p, pp) return o_icon
def addObjects(self): """Add all the objects needed to create the component.""" self.setup = primitive.addTransformFromPos(self.setupWS, self.getName("WS")) attribute.lockAttribute(self.setup) self.WIP = self.options["mode"] self.normal = self.getNormalFromPos(self.guide.apos) self.length0 = vector.getDistance(self.guide.apos[0], self.guide.apos[1]) self.length1 = vector.getDistance(self.guide.apos[1], self.guide.apos[2]) self.length2 = vector.getDistance(self.guide.apos[2], self.guide.apos[3]) self.length3 = vector.getDistance(self.guide.apos[3], self.guide.apos[4]) # 3bones chain self.chain3bones = primitive.add2DChain( self.setup, self.getName("chain3bones%s_jnt"), self.guide.apos[0:4], self.normal, False, self.WIP) # 2bones chain self.chain2bones = primitive.add2DChain( self.setup, self.getName("chain2bones%s_jnt"), self.guide.apos[0:3], self.normal, False, self.WIP) # Leg chain self.legBones = primitive.add2DChain(self.root, self.getName("legBones%s_jnt"), self.guide.apos[0:4], self.normal, False, self.WIP) # Leg chain FK ref self.legBonesFK = primitive.add2DChain(self.root, self.getName("legFK%s_jnt"), self.guide.apos[0:4], self.normal, False, self.WIP) # Leg chain IK ref self.legBonesIK = primitive.add2DChain(self.root, self.getName("legIK%s_jnt"), self.guide.apos[0:4], self.normal, False, self.WIP) # 1 bone chain for upv ref self.legChainUpvRef = primitive.add2DChain( self.root, self.getName("legUpvRef%s_jnt"), [self.guide.apos[0], self.guide.apos[3]], self.normal, False, self.WIP) # mid joints self.mid1_jnt = primitive.addJoint( self.legBones[0], self.getName("mid1_jnt"), self.legBones[1].getMatrix(worldSpace=True), self.WIP) self.mid1_jnt.attr("radius").set(3) self.mid1_jnt.setAttr("jointOrient", 0, 0, 0) self.mid2_jnt = primitive.addJoint( self.legBones[1], self.getName("mid2_jnt"), self.legBones[2].getMatrix(worldSpace=True), self.WIP) self.mid2_jnt.attr("radius").set(3) self.mid2_jnt.setAttr("jointOrient", 0, 0, 0) # base Controlers ----------------------------------- t = transform.getTransformFromPos(self.guide.apos[0]) self.root_npo = primitive.addTransform(self.root, self.getName("root_npo"), t) self.root_ctl = self.addCtl(self.root_npo, "root_ctl", t, self.color_fk, "circle", w=self.length0 / 6, tp=self.parentCtlTag) attribute.lockAttribute(self.root_ctl, ["sx", "sy", "sz", "v"]) # FK Controlers ----------------------------------- t = transform.getTransformLookingAt(self.guide.apos[0], self.guide.apos[1], self.normal, "xz", self.negate) self.fk0_npo = primitive.addTransform(self.root_ctl, self.getName("fk0_npo"), t) self.fk0_ctl = self.addCtl(self.fk0_npo, "fk0_ctl", t, self.color_fk, "cube", w=self.length0, h=self.size * .1, d=self.size * .1, po=datatypes.Vector( .5 * self.length0 * self.n_factor, 0, 0), tp=self.root_ctl) attribute.setKeyableAttributes(self.fk0_ctl) t = transform.getTransformLookingAt(self.guide.apos[1], self.guide.apos[2], self.normal, "xz", self.negate) self.fk1_npo = primitive.addTransform(self.fk0_ctl, self.getName("fk1_npo"), t) self.fk1_ctl = self.addCtl(self.fk1_npo, "fk1_ctl", t, self.color_fk, "cube", w=self.length1, h=self.size * .1, d=self.size * .1, po=datatypes.Vector( .5 * self.length1 * self.n_factor, 0, 0), tp=self.fk0_ctl) attribute.setKeyableAttributes(self.fk1_ctl) t = transform.getTransformLookingAt(self.guide.apos[2], self.guide.apos[3], self.normal, "xz", self.negate) self.fk2_npo = primitive.addTransform(self.fk1_ctl, self.getName("fk2_npo"), t) self.fk2_ctl = self.addCtl(self.fk2_npo, "fk2_ctl", t, self.color_fk, "cube", w=self.length2, h=self.size * .1, d=self.size * .1, po=datatypes.Vector( .5 * self.length2 * self.n_factor, 0, 0), tp=self.fk1_ctl) attribute.setKeyableAttributes(self.fk2_ctl) t = transform.getTransformLookingAt(self.guide.apos[3], self.guide.apos[4], self.normal, "xz", self.negate) self.fk3_npo = primitive.addTransform(self.fk2_ctl, self.getName("fk3_npo"), t) self.fk3_ctl = self.addCtl(self.fk3_npo, "fk3_ctl", t, self.color_fk, "cube", w=self.length3, h=self.size * .1, d=self.size * .1, po=datatypes.Vector( .5 * self.length3 * self.n_factor, 0, 0), tp=self.fk2_ctl) attribute.setKeyableAttributes(self.fk3_ctl) self.fk_ctl = [self.fk0_ctl, self.fk1_ctl, self.fk2_ctl, self.fk3_ctl] for x in self.fk_ctl: attribute.setInvertMirror(x, ["tx", "ty", "tz"]) # Mid Controlers ------------------------------------ self.knee_lvl = primitive.addTransform( self.root, self.getName("knee_lvl"), transform.getTransform(self.mid1_jnt)) self.knee_ctl = self.addCtl(self.knee_lvl, "knee_ctl", transform.getTransform(self.mid1_jnt), self.color_ik, "sphere", w=self.size * .2, tp=self.root_ctl) attribute.setInvertMirror(self.knee_ctl, ["tx", "ty", "tz"]) attribute.lockAttribute(self.knee_ctl, ["sx", "sy", "sz", "v"]) self.ankle_lvl = primitive.addTransform( self.root, self.getName("ankle_lvl"), transform.getTransform(self.mid2_jnt)) self.ankle_ctl = self.addCtl(self.ankle_lvl, "ankle_ctl", transform.getTransform(self.mid2_jnt), self.color_ik, "sphere", w=self.size * .2, tp=self.knee_ctl) attribute.setInvertMirror(self.ankle_ctl, ["tx", "ty", "tz"]) attribute.lockAttribute(self.ankle_ctl, ["sx", "sy", "sz", "v"]) # IK controls -------------------------------------------------------- # foot IK if self.settings["ikOri"]: t = transform.getTransformLookingAt(self.guide.pos["foot"], self.guide.pos["eff"], self.x_axis, "zx", False) else: t = transform.getTransformLookingAt(self.guide.apos[3], self.guide.apos[4], self.normal, "z-x", False) self.ik_cns = primitive.addTransform(self.root_ctl, self.getName("ik_cns"), t) self.ikcns_ctl = self.addCtl(self.ik_cns, "ikcns_ctl", t, self.color_ik, "null", w=self.size * .12, tp=self.ankle_ctl) attribute.setInvertMirror(self.ikcns_ctl, ["tx"]) attribute.lockAttribute(self.ikcns_ctl, ["sx", "sy", "sz", "v"]) self.ik_ctl = self.addCtl(self.ikcns_ctl, "ik_ctl", t, self.color_ik, "cube", w=self.size * .12, h=self.size * .12, d=self.size * .12, tp=self.ikcns_ctl) attribute.setKeyableAttributes(self.ik_ctl) attribute.setRotOrder(self.ik_ctl, "XZY") attribute.setInvertMirror(self.ik_ctl, ["tx", "ry", "rz"]) attribute.lockAttribute(self.ik_ctl, ["sx", "sy", "sz", "v"]) # 2 bones ik layer self.ik2b_ikCtl_ref = primitive.addTransform( self.ik_ctl, self.getName("ik2B_A_ref"), t) self.ik2b_bone_ref = primitive.addTransform(self.chain3bones[3], self.getName("ik2B_B_ref"), t) self.ik2b_blend = primitive.addTransform(self.ik_ctl, self.getName("ik2B_blend"), t) self.roll_ctl = self.addCtl(self.ik2b_blend, "roll_ctl", t, self.color_ik, "crossarrow", w=self.length2 * .5 * self.n_factor, tp=self.ik_ctl) self.ik2b_ik_npo = primitive.addTransform( self.roll_ctl, self.getName("ik2B_ik_npo"), transform.getTransform(self.chain3bones[-1])) self.ik2b_ik_ref = primitive.addTransformFromPos( self.ik2b_ik_npo, self.getName("ik2B_ik_ref"), self.guide.pos["ankle"]) attribute.lockAttribute(self.roll_ctl, ["tx", "ty", "tz", "sx", "sy", "sz", "v"]) # upv v = self.guide.apos[2] - self.guide.apos[0] v = self.normal ^ v v.normalize() v *= self.size * .5 v += self.guide.apos[1] self.upv_lvl = primitive.addTransformFromPos(self.root, self.getName("upv_lvl"), v) self.upv_cns = primitive.addTransformFromPos(self.upv_lvl, self.getName("upv_cns"), v) self.upv_ctl = self.addCtl(self.upv_cns, "upv_ctl", transform.getTransform(self.upv_cns), self.color_ik, "diamond", w=self.size * .12, tp=self.ik_ctl) attribute.setInvertMirror(self.upv_ctl, ["tx"]) attribute.setKeyableAttributes(self.upv_ctl, ["tx", "ty", "tz"]) # Soft IK objects 3 bones chain -------------------------------- t = transform.getTransformLookingAt(self.guide.pos["root"], self.guide.pos["foot"], self.x_axis, "zx", False) self.aim_tra = primitive.addTransform(self.root_ctl, self.getName("aimSoftIK"), t) t = transform.getTransformFromPos(self.guide.pos["foot"]) self.wristSoftIK = primitive.addTransform(self.aim_tra, self.getName("wristSoftIK"), t) self.softblendLoc = primitive.addTransform( self.root, self.getName("softblendLoc"), t) # Soft IK objects 2 Bones chain ---------------------------- t = transform.getTransformLookingAt(self.guide.pos["root"], self.guide.pos["ankle"], self.x_axis, "zx", False) self.aim_tra2 = primitive.addTransform(self.root_ctl, self.getName("aimSoftIK2"), t) t = transform.getTransformFromPos(self.guide.pos["ankle"]) self.ankleSoftIK = primitive.addTransform(self.aim_tra2, self.getName("ankleSoftIK"), t) self.softblendLoc2 = primitive.addTransform( self.root, self.getName("softblendLoc2"), t) # References -------------------------------------- self.ik_ref = primitive.addTransform( self.ik_ctl, self.getName("ik_ref"), transform.getTransform(self.ik_ctl)) self.fk_ref = primitive.addTransform( self.fk_ctl[3], self.getName("fk_ref"), transform.getTransform(self.ik_ctl)) # twist references -------------------------------------- self.rollRef = primitive.add2DChain(self.root, self.getName("rollChain"), self.guide.apos[:2], self.normal, False, self.WIP) self.tws0_loc = primitive.addTransform( self.rollRef[0], self.getName("tws0_loc"), transform.getTransform(self.legBones[0])) self.tws0_rot = primitive.addTransform( self.tws0_loc, self.getName("tws0_rot"), transform.getTransform(self.legBones[0])) self.tws0_rot.setAttr("sx", .001) self.tws1_loc = primitive.addTransform( self.mid1_jnt, self.getName("tws1_loc"), transform.getTransform(self.mid1_jnt)) self.tws1_rot = primitive.addTransform( self.tws1_loc, self.getName("tws1_rot"), transform.getTransform(self.mid1_jnt)) self.tws1_rot.setAttr("sx", .001) self.tws2_loc = primitive.addTransform( self.mid2_jnt, self.getName("tws2_loc"), transform.getTransform(self.mid2_jnt)) self.tws2_rot = primitive.addTransform( self.tws2_loc, self.getName("tws2_rot"), transform.getTransform(self.mid2_jnt)) self.tws2_rot.setAttr("sx", .001) self.tws3_loc = primitive.addTransform( self.legBones[3], self.getName("tws3_loc"), transform.getTransform(self.legBones[3])) self.tws3_rot = primitive.addTransform( self.tws3_loc, self.getName("tws3_rot"), transform.getTransform(self.legBones[3])) self.tws3_rot.setAttr("sx", .001) # Divisions ---------------------------------------- # We have at least one division at the start, the end and one for # the knee and one ankle o_set = self.settings self.divisions = o_set["div0"] + o_set["div1"] + o_set["div2"] + 4 self.div_cns = [] for i in range(self.divisions): div_cns = primitive.addTransform(self.root_ctl, self.getName("div%s_loc" % i)) self.div_cns.append(div_cns) self.jnt_pos.append([div_cns, i]) # End reference ------------------------------------ # To help the deformation on the foot self.end_ref = primitive.addTransform( self.tws3_rot, self.getName("end_ref"), transform.getTransform(self.legBones[3])) self.jnt_pos.append([self.end_ref, 'end'])
def addJoint(self, obj, name, newActiveJnt=None, UniScale=False, segComp=0, gearMulMatrix=True): """Add joint as child of the active joint or under driver object. Args: obj (dagNode): The input driver object for the joint. name (str): The joint name. newActiveJnt (bool or dagNode): If a joint is pass, this joint will be the active joint and parent of the newly created joint. UniScale (bool): Connects the joint scale with the Z axis for a unifor scalin, if set Falsewill connect with each axis separated. segComp (bool): Set True or False the segment compensation in the joint.. gearMulMatrix (bool): Use the custom gear_multiply matrix node, if False will use Maya's default mulMatrix node. Returns: dagNode: The newly created joint. """ if self.options["joint_rig"]: if newActiveJnt: self.active_jnt = newActiveJnt jnt = primitive.addJoint(self.active_jnt, self.getName(str(name) + "_jnt"), transform.getTransform(obj)) # TODO: Set the joint to have always positive scaling # jnt.scale.set([1, 1, 1]) # Disconnect inversScale for better preformance if isinstance(self.active_jnt, pm.nodetypes.Joint): try: pm.disconnectAttr(self.active_jnt.scale, jnt.inverseScale) except RuntimeError: # This handle the situation where we have in between joints # transformation due a negative scaling pm.ungroup(jnt.getParent()) # All new jnts are the active by default self.active_jnt = jnt if gearMulMatrix: mulmat_node = applyop.gear_mulmatrix_op( obj + ".worldMatrix", jnt + ".parentInverseMatrix") dm_node = node.createDecomposeMatrixNode(mulmat_node + ".output") m = mulmat_node.attr('output').get() else: mulmat_node = node.createMultMatrixNode( obj + ".worldMatrix", jnt + ".parentInverseMatrix") dm_node = node.createDecomposeMatrixNode(mulmat_node + ".matrixSum") m = mulmat_node.attr('matrixSum').get() pm.connectAttr(dm_node + ".outputTranslate", jnt + ".t") pm.connectAttr(dm_node + ".outputRotate", jnt + ".r") # TODO: fix squash stretch solver to scale the joint uniform # the next line cheat the uniform scaling only fo X or Y axis # oriented joints if UniScale: pm.connectAttr(dm_node + ".outputScaleZ", jnt + ".sx") pm.connectAttr(dm_node + ".outputScaleZ", jnt + ".sy") pm.connectAttr(dm_node + ".outputScaleZ", jnt + ".sz") else: pm.connectAttr(dm_node + ".outputScale", jnt + ".s") pm.connectAttr(dm_node + ".outputShear", jnt + ".shear") # Segment scale compensate Off to avoid issues with the global # scale jnt.setAttr("segmentScaleCompensate", segComp) jnt.setAttr("jointOrient", 0, 0, 0) # setting the joint orient compensation in order to have clean # rotation channels jnt.attr("jointOrientX").set(jnt.attr("rx").get()) jnt.attr("jointOrientY").set(jnt.attr("ry").get()) jnt.attr("jointOrientZ").set(jnt.attr("rz").get()) im = m.inverse() if gearMulMatrix: mul_nod = applyop.gear_mulmatrix_op(mulmat_node.attr('output'), im, jnt, 'r') dm_node2 = mul_nod.output.listConnections()[0] else: mul_nod = node.createMultMatrixNode( mulmat_node.attr('matrixSum'), im, jnt, 'r') dm_node2 = mul_nod.matrixSum.listConnections()[0] if jnt.attr("sz").get() < 0: # if negative scaling we have to negate some axis for rotation neg_rot_node = pm.createNode("multiplyDivide") pm.setAttr(neg_rot_node + ".operation", 1) pm.connectAttr(dm_node2.outputRotate, neg_rot_node + ".input1", f=True) for v, axis in zip([-1, -1, 1], "XYZ"): pm.setAttr(neg_rot_node + ".input2" + axis, v) pm.connectAttr(neg_rot_node + ".output", jnt + ".r", f=True) # set not keyable attribute.setNotKeyableAttributes(jnt) else: jnt = primitive.addJoint(obj, self.getName(str(name) + "_jnt"), transform.getTransform(obj)) pm.connectAttr(self.rig.jntVis_att, jnt.attr("visibility")) attribute.lockAttribute(jnt) self.addToGroup(jnt, "deformers") # This is a workaround due the evaluation problem with compound attr # TODO: This workaround, should be removed onces the evaluation issue # is fixed # github issue: Shifter: Joint connection: Maya evaluation Bug #210 dm = jnt.r.listConnections(p=True, type="decomposeMatrix") if dm: at = dm[0] dm_node = at.node() pm.disconnectAttr(at, jnt.r) pm.connectAttr(dm_node.outputRotateX, jnt.rx) pm.connectAttr(dm_node.outputRotateY, jnt.ry) pm.connectAttr(dm_node.outputRotateZ, jnt.rz) dm = jnt.t.listConnections(p=True, type="decomposeMatrix") if dm: at = dm[0] dm_node = at.node() pm.disconnectAttr(at, jnt.t) pm.connectAttr(dm_node.outputTranslateX, jnt.tx) pm.connectAttr(dm_node.outputTranslateY, jnt.ty) pm.connectAttr(dm_node.outputTranslateZ, jnt.tz) dm = jnt.s.listConnections(p=True, type="decomposeMatrix") if dm: at = dm[0] dm_node = at.node() pm.disconnectAttr(at, jnt.s) pm.connectAttr(dm_node.outputScaleX, jnt.sx) pm.connectAttr(dm_node.outputScaleY, jnt.sy) pm.connectAttr(dm_node.outputScaleZ, jnt.sz) return jnt
def addJoint(self, obj, name, newActiveJnt=None, UniScale=True, segComp=0, gearMulMatrix=True): """Add joint as child of the active joint or under driver object. Args: obj (dagNode): The input driver object for the joint. name (str): The joint name. newActiveJnt (bool or dagNode): If a joint is pass, this joint will be the active joint and parent of the newly created joint. UniScale (bool): Connects the joint scale with the Z axis for a unifor scalin, if set Falsewill connect with each axis separated. segComp (bool): Set True or False the segment compensation in the joint.. gearMulMatrix (bool): Use the custom gear_multiply matrix node, if False will use Maya's default mulMatrix node. Returns: dagNode: The newly created joint. """ if self.options["joint_rig"]: if newActiveJnt: self.active_jnt = newActiveJnt jnt = primitive.addJoint(self.active_jnt, self.getName(str(name) + "_jnt"), transform.getTransform(obj)) # All new jnts are the active by default self.active_jnt = jnt if gearMulMatrix: mulmat_node = applyop.gear_mulmatrix_op( obj + ".worldMatrix", jnt + ".parentInverseMatrix") dm_node = node.createDecomposeMatrixNode(mulmat_node + ".output") m = mulmat_node.attr('output').get() else: mulmat_node = node.createMultMatrixNode( obj + ".worldMatrix", jnt + ".parentInverseMatrix") dm_node = node.createDecomposeMatrixNode(mulmat_node + ".matrixSum") m = mulmat_node.attr('matrixSum').get() pm.connectAttr(dm_node + ".outputTranslate", jnt + ".t") pm.connectAttr(dm_node + ".outputRotate", jnt + ".r") # TODO: fix squash stretch solver to scale the joint uniform # the next line cheat the uniform scaling only fo X or Y axis # oriented joints if UniScale: pm.connectAttr(dm_node + ".outputScaleZ", jnt + ".sx") pm.connectAttr(dm_node + ".outputScaleZ", jnt + ".sy") pm.connectAttr(dm_node + ".outputScaleZ", jnt + ".sz") else: pm.connectAttr(dm_node + ".outputScale", jnt + ".s") pm.connectAttr(dm_node + ".outputShear", jnt + ".shear") # Segment scale compensate Off to avoid issues with the global # scale jnt.setAttr("segmentScaleCompensate", segComp) jnt.setAttr("jointOrient", 0, 0, 0) # setting the joint orient compensation in order to have clean # rotation channels jnt.attr("jointOrientX").set(jnt.attr("rx").get()) jnt.attr("jointOrientY").set(jnt.attr("ry").get()) jnt.attr("jointOrientZ").set(jnt.attr("rz").get()) im = m.inverse() if gearMulMatrix: applyop.gear_mulmatrix_op(mulmat_node.attr('output'), im, jnt, 'r') else: node.createMultMatrixNode(mulmat_node.attr('matrixSum'), im, jnt, 'r') else: jnt = primitive.addJoint(obj, self.getName(str(name) + "_jnt"), transform.getTransform(obj)) pm.connectAttr(self.rig.jntVis_att, jnt.attr("visibility")) self.addToGroup(jnt, "deformers") return jnt