def connectWorldTransform(source, target): """Connect the source world transform of one object to another object. Args: source (dagNode): Source dagNode. target (dagNode): target dagNode. """ mulmat_node = node.createMultMatrixNode(source + ".worldMatrix", target + ".parentInverseMatrix") dm_node = node.createDecomposeMatrixNode(mulmat_node + ".matrixSum") pm.connectAttr(dm_node + ".outputTranslate", target + ".t") pm.connectAttr(dm_node + ".outputRotate", target + ".r") pm.connectAttr(dm_node + ".outputScale", target + ".s")
def connect_blended_orient(self): if not self.parent == self.root.getParent(): self.parent.addChild(self.root) refArray = self.settings["orientrefarray"] print 'function called: CustomComponent.connect_blended_orient()' if refArray: print 'ref array: %s' % refArray ref_names = self.get_valid_ref_list(refArray.split(",")) if len(ref_names) == 1: print 'RELOADED' ref = self.rig.findRelative(ref_names[0]) self.staticOffsetMtx = matrix44FromMtxAttr( (ref.worldMatrix[0].get() * self.root.worldInverseMatrix[0].get())) self.targetMtx = node.createMultMatrixNode( ref.worldMatrix[0], self.root.worldInverseMatrix[0]) self.targetInverseMtx = pm.createNode('inverseMatrix') self.targetMtx.matrixSum.connect( self.targetInverseMtx.inputMatrix) self.resultMtx = node.createMultMatrixNode( self.staticOffsetMtx.output, self.targetInverseMtx.outputMatrix) dm = node.createDecomposeMatrixNode(self.resultMtx.matrixSum) pb = pm.createNode('pairBlend') dm.outputRotate.connect(pb.inRotate1) pb.rotInterpolation.set(1) pb.weight.set(0.5) pb.outRotateZ.connect(self.ik_cns.rotateZ) ''' Do not use world space align in component settings - then control will be built oriented the same as the guide Align root to ik_cns. Then add above systems to ik_cns - this will offset away from original orientation of guide Add a buffer between ik_cns and control to maintain original orientation from guide. Align this buffer back to root ''' else: pass
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
def addJnt(obj=False, parent=False, noReplace=False, grp=None, jntName=None, *args): """Create one joint for each selected object. Args: obj (bool or dagNode, optional): The object to drive the new joint. If False will use the current selection. parent (bool or dagNode, optional): The parent for the joint. If False will try to parent to jnt_org. If jnt_org doesn't exist will parent the joint under the obj noReplace (bool, optional): If True will add the extension "_jnt" to the new joint name grp (pyNode or None, optional): The set to add the new joint. If none will use "rig_deformers_grp" *args: Maya's dummy Returns: pyNode: The New created joint. """ if not obj: oSel = pm.selected() else: oSel = [obj] for obj in oSel: if not parent: try: oParent = pm.PyNode("jnt_org") except TypeError: oParent = obj else: oParent = parent if not jntName: if noReplace: jntName = "_".join(obj.name().split("_")) + "_jnt" else: jntName = "_".join(obj.name().split("_")[:-1]) + "_jnt" jnt = pm.createNode("joint", n=jntName) if grp: grp.add(jnt) else: try: defSet = pm.PyNode("rig_deformers_grp") pm.sets(defSet, add=jnt) except TypeError: pm.sets(n="rig_deformers_grp") defSet = pm.PyNode("rig_deformers_grp") pm.sets(defSet, add=jnt) oParent.addChild(jnt) jnt.setAttr("jointOrient", 0, 0, 0) try: mulmat_node = node.createMultMatrixNode( obj + ".worldMatrix", jnt + ".parentInverseMatrix") dm_node = node.createDecomposeMatrixNode(mulmat_node + ".matrixSum") pm.connectAttr(dm_node + ".outputTranslate", jnt + ".t") pm.connectAttr(dm_node + ".outputRotate", jnt + ".r") pm.connectAttr(dm_node + ".outputScale", jnt + ".s") except RuntimeError: for axis in ["tx", "ty", "tz", "rx", "ry", "rz"]: jnt.attr(axis).set(0.0) return jnt
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. """ customName = self.getCustomJointName(len(self.jointList)) if self.options["joint_rig"]: if newActiveJnt: self.active_jnt = newActiveJnt jnt = primitive.addJoint(self.active_jnt, customName or self.getName(str(name) + "_jnt"), transform.getTransform(obj)) # 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 self.options["force_uniScale"]: UniScale = True # invert negative scaling in Joints. We only inver Z axis, so is # the only axis that we are checking 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") # connect scaling if UniScale: pm.connectAttr(out_val, jnt + ".sx") pm.connectAttr(out_val, jnt + ".sy") pm.connectAttr(out_val, jnt + ".sz") else: pm.connectAttr(dm_node.attr("outputScaleX"), jnt + ".sx") pm.connectAttr(dm_node.attr("outputScaleY"), jnt + ".sy") pm.connectAttr(out_val, jnt + ".sz") 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 dm_node.attr("outputScaleZ").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, customName or 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