def cycleTweak(name, edgePair, mirrorAxis, baseMesh, rotMesh, transMesh, setupParent, ctlParent, jntOrg=None, grp=None, iconType="square", size=.025, color=13, ro=datatypes.Vector(1.5708, 0, 1.5708 / 2)): """The command to create a cycle tweak. A cycle tweak is a tweak that cycles to the parent position but doesn't create a cycle of dependency. This type of tweaks are very useful to create facial tweakers. Args: name (string): Name for the cycle tweak edgePair (list): List of edge pair to attach the cycle tweak mirrorAxis (bool): If true, will mirror the x axis behaviour. baseMesh (Mesh): The base mesh for the cycle tweak. rotMesh (Mesh): The mesh that will support the rotation transformations for the cycle tweak transMesh (Mesh): The mesh that will support the translation and scale transformations for the cycle tweak setupParent (dagNode): The parent for the setup objects ctlParent (dagNode): The parent for the control objects jntOrg (None or dagNode, optional): The parent for the joints grp (None or set, optional): The set to add the controls iconType (str, optional): The controls shape size (float, optional): The control size color (int, optional): The control color ro (TYPE, optional): The control shape rotation offset Returns: multi: the tweak control and the list of related joints. """ # rotation sctructure rRivet = rivet.rivet() rBase = rRivet.create( baseMesh, edgePair[0], edgePair[1], setupParent, name + "_rRivet_loc") pos = rBase.getTranslation(space="world") # translation structure tRivetParent = pm.createNode("transform", n=name + "_tRivetBase", p=ctlParent) tRivetParent.setMatrix(datatypes.Matrix(), worldSpace=True) tRivet = rivet.rivet() tBase = tRivet.create(transMesh, edgePair[0], edgePair[1], tRivetParent, name + "_tRivet_loc") # create the control tweakBase = pm.createNode("transform", n=name + "_tweakBase", p=ctlParent) tweakBase.setMatrix(datatypes.Matrix(), worldSpace=True) tweakNpo = pm.createNode("transform", n=name + "_tweakNpo", p=tweakBase) tweakBase.setTranslation(pos, space="world") tweakCtl = icon.create(tweakNpo, name + "_ctl", tweakNpo.getMatrix(worldSpace=True), color, iconType, w=size, d=size, ro=ro) inverseTranslateParent(tweakCtl) pm.pointConstraint(tBase, tweakBase) # rot rotBase = pm.createNode("transform", n=name + "_rotBase", p=setupParent) rotBase.setMatrix(datatypes.Matrix(), worldSpace=True) rotNPO = pm.createNode("transform", n=name + "_rot_npo", p=rotBase) rotJointDriver = pm.createNode("transform", n=name + "_rotJointDriver", p=rotNPO) rotBase.setTranslation(pos, space="world") node.createMulNode([rotNPO.attr("tx"), rotNPO.attr("ty"), rotNPO.attr("tz")], [-1, -1, -1], [rotJointDriver.attr("tx"), rotJointDriver.attr("ty"), rotJointDriver.attr("tz")]) pm.pointConstraint(rBase, rotNPO) pm.connectAttr(tweakCtl.r, rotNPO.r) pm.connectAttr(tweakCtl.s, rotNPO.s) # transform posNPO = pm.createNode("transform", n=name + "_pos_npo", p=setupParent) posJointDriver = pm.createNode("transform", n=name + "_posJointDriver", p=posNPO) posNPO.setTranslation(pos, space="world") pm.connectAttr(tweakCtl.t, posJointDriver.t) # mirror behaviour if mirrorAxis: tweakBase.attr("ry").set(tweakBase.attr("ry").get() + 180) rotBase.attr("ry").set(rotBase.attr("ry").get() + 180) posNPO.attr("ry").set(posNPO.attr("ry").get() + 180) tweakBase.attr("sz").set(-1) rotBase.attr("sz").set(-1) posNPO.attr("sz").set(-1) # create joints rJoint = rigbits.addJnt(rotJointDriver, jntOrg, True, grp) tJoint = rigbits.addJnt(posJointDriver, jntOrg, True, grp) # add to rotation skin # TODO: add checker to see if joint is in the skincluster. rSK = skin.getSkinCluster(rotMesh) pm.skinCluster(rSK, e=True, ai=rJoint, lw=True, wt=0) # add to transform skin # TODO: add checker to see if joint is in the skincluster. tSK = skin.getSkinCluster(transMesh) pm.skinCluster(tSK, e=True, ai=tJoint, lw=True, wt=0) return tweakCtl, [rJoint, tJoint]
def createRivetTweak(mesh, edgePair, name, parent=None, ctlParent=None, jntParent=None, color=[0, 0, 0], size=.04, defSet=None, ctlSet=None, side=None, gearMulMatrix=True, attach_rot=False, inputMesh=None): """Create a tweak joint attached to the mesh using a rivet Args: mesh (mesh): The object to add the tweak edgePair (pair list): The edge pair to create the rivet name (str): The name for the tweak parent (None or dagNode, optional): The parent for the tweak jntParent (None or dagNode, optional): The parent for the joints ctlParent (None or dagNode, optional): The parent for the tweak control color (list, optional): The color for the control size (float, optional): Size of the control defSet (None or set, optional): Deformer set to add the joints ctlSet (None or set, optional): the set to add the controls side (None, str): String to set the side. Valid values are L, R or C. If the side is not set or the value is not valid, the side will be set automatically based on the world position gearMulMatrix (bool, optional): If False will use Maya default multiply matrix node Returns: PyNode: The tweak control """ blendShape = blendShapes.getBlendShape(mesh) if not inputMesh: 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 not side or side not in ["L", "R", "C"]: 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) if not ctlParent: ctlParent = base ctl_parent_tag = None else: ctl_parent_tag = ctlParent # Joints NPO npo = pm.PyNode(pm.createNode("transform", n=nameSide + "_npo", p=ctlParent, ss=True)) if attach_rot: # npo.setTranslation(base.getTranslation(space="world"), space="world") pm.parentConstraint(base, npo, mo=False) else: pm.pointConstraint(base, npo, mo=False) # create joints if not jntParent: jntParent = npo matrix_cnx = False else: # need extra connection to ensure is moving with th npo, even is # not child of npo matrix_cnx = True jointBase = primitive.addJoint(jntParent, nameSide + "_jnt_lvl") joint = primitive.addJoint(jointBase, nameSide + "_jnt") # reset axis and invert behaviour for axis in "XYZ": pm.setAttr(jointBase + ".jointOrient" + axis, 0) pm.setAttr(npo + ".translate" + axis, 0) # pm.setAttr(jointBase + ".translate" + axis, 0) pp = npo.getParent() pm.parent(npo, w=True) for axis in "xyz": npo.attr("r" + axis).set(0) if side == "R": npo.attr("ry").set(180) npo.attr("sz").set(-1) pm.parent(npo, pp) dm_node = None if matrix_cnx: mulmat_node = applyop.gear_mulmatrix_op( npo + ".worldMatrix", jointBase + ".parentInverseMatrix") dm_node = node.createDecomposeMatrixNode( mulmat_node + ".output") m = mulmat_node.attr('output').get() pm.connectAttr(dm_node + ".outputTranslate", jointBase + ".t") pm.connectAttr(dm_node + ".outputRotate", jointBase + ".r") # invert negative scaling in Joints. We only inver Z axis, so is # the only axis that we are checking print(dm_node.attr("outputScaleZ").get()) if dm_node.attr("outputScaleZ").get() < 0: mul_nod_invert = node.createMulNode( dm_node.attr("outputScaleZ"), -1) out_val = mul_nod_invert.attr("outputX") else: out_val = dm_node.attr("outputScaleZ") pm.connectAttr(dm_node.attr("outputScaleX"), jointBase + ".sx") pm.connectAttr(dm_node.attr("outputScaleY"), jointBase + ".sy") pm.connectAttr(out_val, jointBase + ".sz") pm.connectAttr(dm_node + ".outputShear", jointBase + ".shear") # Segment scale compensate Off to avoid issues with the global # scale jointBase.setAttr("segmentScaleCompensate", 0) joint.setAttr("segmentScaleCompensate", 0) jointBase.setAttr("jointOrient", 0, 0, 0) # setting the joint orient compensation in order to have clean # rotation channels jointBase.attr("jointOrientX").set(jointBase.attr("rx").get()) jointBase.attr("jointOrientY").set(jointBase.attr("ry").get()) jointBase.attr("jointOrientZ").set(jointBase.attr("rz").get()) im = m.inverse() if gearMulMatrix: mul_nod = applyop.gear_mulmatrix_op( mulmat_node.attr('output'), im, jointBase, 'r') dm_node2 = mul_nod.output.listConnections()[0] else: mul_nod = node.createMultMatrixNode( mulmat_node.attr('matrixSum'), im, jointBase, 'r') dm_node2 = mul_nod.matrixSum.listConnections()[0] if dm_node.attr("outputScaleZ").get() < 0: negateTransformConnection(dm_node2.outputRotate, jointBase.rotate) else: resetJntLocalSRT(jointBase) # 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", empty=True) defSet = pm.PyNode("rig_deformers_grp") pm.sets(defSet, add=joint) controlType = "sphere" o_icon = icon.create(npo, nameSide + "_ctl", datatypes.Matrix(), color, controlType, w=size) attribute.addAttribute(o_icon, "isCtl", "bool", keyable=False) transform.resetTransform(o_icon) if dm_node and dm_node.attr("outputScaleZ").get() < 0: pm.connectAttr(o_icon.scale, joint.scale) negateTransformConnection(o_icon.rotate, joint.rotate) negateTransformConnection(o_icon.translate, joint.translate, [1, 1, -1]) else: 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 pre_bind_matrix_connect(mesh, joint, jointBase) # add control tag node.add_controller_tag(o_icon, ctl_parent_tag) if not ctlSet: try: ctlSet = pm.PyNode("rig_controllers_grp") except TypeError: pm.sets(n="rig_controllers_grp", empty=True) ctlSet = pm.PyNode("rig_controllers_grp") pm.sets(ctlSet, add=o_icon) return o_icon