def createCTL(type="square", child=False, *args): """Create a control for each selected object. The newly create control can be parent or child of the object. Args: type (str): The shape of the control. child (bool): if True, the control will be created as a child of the object. """ iconList = [] if child: if len(pm.selected()) > 0: for x in pm.selected(): oChilds = [item for item in x.listRelatives(ad=True, type="transform") if item.longName().split("|")[-2] == x.name()] o_icon = icon.create( None, x.name() + "_ctl", None, [1, 0, 0], type) iconList.append(o_icon) o_icon.setTransformation(x.getMatrix(worldSpace=True)) pm.parent(o_icon, x) for child in oChilds: pm.parent(child, o_icon) else: o_icon = icon.create( None, type + "_ctl", datatypes.Matrix(), [1, 0, 0], type) iconList.append(o_icon) else: if len(pm.selected()) > 0: for x in pm.selected(): oParent = x.getParent() o_icon = icon.create(oParent, x.name() + "_ctl", x.getMatrix(), [1, 0, 0], type) iconList.append(o_icon) o_icon.setTransformation(x.getMatrix()) pm.parent(x, o_icon) else: o_icon = icon.create( None, type + "_ctl", datatypes.Matrix(), [1, 0, 0], type) iconList.append(o_icon) try: defSet = pm.PyNode("rig_controllers_grp") for ico in iconList: pm.sets(defSet, add=ico) except TypeError: print "not rig_controllers_grp found" pass
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 addCtl(self, parent, name, m, color, icon, **kwargs): """ Create the control and apply the shape, if this is alrealdy stored in the guide controllers grp. Args: parent (dagNode): The control parent name (str): The control name. m (matrix): The transfromation matrix for the control. color (int or list of float): The color for the control in idex or RGB. icon (str): The controls default shape. kwargs (variant): Other arguments for the icon type variations. Returns: dagNode: The Control. """ if name in self.guide.controllers.keys(): ctl_ref = self.guide.controllers[name] ctl = pri.addTransform(parent, name, m) for shape in ctl_ref.getShapes(): ctl.addChild(shape, shape=True, add=True) else: ctl = ico.create(parent, name, m, color, icon, **kwargs) self.addToGroup(ctl, "controllers") return ctl
def addCtl(self, parent, name, m, color, icon, **kwargs): if name in self.guide.controlers.keys(): ctl_ref = self.guide.controlers[name] ctl = pri.addTransform(parent, name, m) for shape in ctl_ref.getShapes(): ctl.addChild(shape, shape=True, add=True) else: ctl = ico.create(parent, name, m, color, icon, **kwargs) self.addToGroup(ctl, "controlers") return ctl
def addCtl(self, parent, name, m, color, iconShape, **kwargs): """Create the control and apply the shape, if this is alrealdy stored in the guide controllers grp. Args: parent (dagNode): The control parent name (str): The control name. m (matrix): The transfromation matrix for the control. color (int or list of float): The color for the control in index or RGB. iconShape (str): The controls default shape. kwargs (variant): Other arguments for the iconShape type variations Returns: dagNode: The Control. """ if "degree" not in kwargs.keys(): kwargs["degree"] = 1 bufferName = name + "_controlBuffer" if bufferName in self.guide.controllers.keys(): ctl_ref = self.guide.controllers[bufferName] ctl = primitive.addTransform(parent, name, m) for shape in ctl_ref.getShapes(): ctl.addChild(shape, shape=True, add=True) pm.rename(shape, name + "Shape") else: ctl = icon.create(parent, name, m, color, iconShape, **kwargs) self.addToGroup(ctl, "controllers") # Set the control shapes isHistoricallyInteresting for oShape in ctl.getShapes(): oShape.isHistoricallyInteresting.set(False) # set controller tag if versions.current() >= 201650: pm.controller(ctl) self.add_controller_tag(ctl, None) return ctl
def addCtl(self, parent, name, m, color, icon, **kwargs): """ Create the control and apply the shape, if this is alrealdy stored in the guide controllers grp. Args: parent (dagNode): The control parent name (str): The control name. m (matrix): The transfromation matrix for the control. color (int or list of float): The color for the control in idex or RGB. icon (str): The controls default shape. kwargs (variant): Other arguments for the icon type variations. Returns: dagNode: The Control. """ fullName = self.getName(name) if fullName in self.rig.guide.controllers.keys(): ctl_ref = self.rig.guide.controllers[fullName] ctl = pri.addTransform(parent, fullName, m) for shape in ctl_ref.getShapes(): ctl.addChild(shape, shape=True, add=True) ico.setcolor(ctl, color) else: ctl = ico.create(parent, fullName, m, color, icon, **kwargs) # create the attributes to handlde mirror and symetrical pose att.addAttribute(ctl, "invTx", "bool", 0, keyable=False, niceName="Invert Mirror TX") att.addAttribute(ctl, "invTy", "bool", 0, keyable=False, niceName="Invert Mirror TY") att.addAttribute(ctl, "invTz", "bool", 0, keyable=False, niceName="Invert Mirror TZ") att.addAttribute(ctl, "invRx", "bool", 0, keyable=False, niceName="Invert Mirror RX") att.addAttribute(ctl, "invRy", "bool", 0, keyable=False, niceName="Invert Mirror RY") att.addAttribute(ctl, "invRz", "bool", 0, keyable=False, niceName="Invert Mirror RZ") att.addAttribute(ctl, "invSx", "bool", 0, keyable=False, niceName="Invert Mirror SX") att.addAttribute(ctl, "invSy", "bool", 0, keyable=False, niceName="Invert Mirror SY") att.addAttribute(ctl, "invSz", "bool", 0, keyable=False, niceName="Invert Mirror SZ") self.addToGroup(ctl, "controllers") return ctl
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 simpleRig(rigName="rig", wCntCtl=False, *args): """Create a simple 1Click rig. Args: rigName (str, optional): Name of the rig. wCntCtl (bool, optional): Place the Golbal control in the wolrd center or use the general BBox of the selection. *args: Description Returns: dagNode: Rig top node """ meshList = [] ctlList = [] lvlList = [] absBB = [] absRadio = 0.5 listSelection = [oSel for oSel in pm.selected()] # Create base structure rig = pm.createNode('transform', n=rigName) geo = pm.createNode('transform', n="geo", p=rig) geo.attr("overrideEnabled").set(1) geo.attr("overrideDisplayType").set(2) attribute.addAttribute(rig, "is_rig", "bool", True) attribute.addAttribute(rig, "rig_name", "string", "rig") attribute.addAttribute(rig, "user", "string", getpass.getuser()) attribute.addAttribute(rig, "date", "string", str(datetime.datetime.now())) attribute.addAttribute(rig, "maya_version", "string", str(pm.mel.eval("getApplicationVersionAsFloat"))) attribute.addAttribute(rig, "gear_version", "string", mgear.getVersion()) attribute.addAttribute(rig, "ctl_vis", "bool", True) attribute.addAttribute(rig, "jnt_vis", "bool", False) attribute.addAttribute(rig, "quickselA", "string", "") attribute.addAttribute(rig, "quickselB", "string", "") attribute.addAttribute(rig, "quickselC", "string", "") attribute.addAttribute(rig, "quickselD", "string", "") attribute.addAttribute(rig, "quickselE", "string", "") attribute.addAttribute(rig, "quickselF", "string", "") rig.addAttr("rigGroups", at='message', m=1) rig.addAttr("rigPoses", at='message', m=1) for oSel in listSelection: bbCenter, bbRadio, bb = bBoxData(oSel) lvl = pm.createNode('transform', n=oSel.name().split("_")[0] + "_npo") lvlList.append(lvl) t = transform.getTransformFromPos(bbCenter) lvl.setTransformation(t) ctl = ico.create(lvl, oSel.name().split("_")[0] + "_ctl", t, 14, icon="circle", w=bbRadio * 2) cnsPart(ctl, oSel) ctlList.append(ctl) for oShape in oSel.listRelatives(ad=True, s=True, type='mesh'): pm.connectAttr(ctl + ".visibility", oShape + ".visibility", f=True) meshList.append(oShape) # Reparenting pm.parent(oSel, geo) # calculate the global control BB if not wCntCtl: if not absBB: absBB = bb else: absBB = [ [min(bb[0][0], absBB[0][0]), max(bb[0][1], absBB[0][1])], [min(bb[1][0], absBB[1][0]), max(bb[1][1], absBB[1][1])], [min(bb[2][0], absBB[2][0]), max(bb[2][1], absBB[2][1])] ] userPivots = dag.findChildrenPartial(oSel, PIVOT_EXTENSION) # Loop selection uPivotCtl = [] if userPivots: for uPivot in userPivots: try: pstr = uPivot.name().split('_')[0] + "_" + PGROUP_EXTENSION pgrp = pm.PyNode(pstr) except TypeError: pm.displayError("The selected pivot dont have the group" " contrapart. Review your rig structure") return False objList = pgrp.listRelatives(ad=True) if objList: bbCenter, bbRadio, bb = bBoxData(objList) t = uPivot.getMatrix(worldSpace=True) lvlParent = pm.listRelatives( uPivot, p=True)[0].name().split("_")[0] + "_ctl" lvl = pm.createNode('transform', n=uPivot.split("_")[0] + "_npo") lvl.setTransformation(t) icon = iconList[uPivot.attr("ctlIcon").get()] ctlKeyable = [] if uPivot.attr("animTranslation").get(): ctlKeyable = ctlKeyable + ["tx", "ty", "tz"] if uPivot.attr("animRotation").get(): ctlKeyable = ctlKeyable + ["ro", "rx", "ry", "rz"] if uPivot.attr("animScale").get(): ctlKeyable = ctlKeyable + ["sx", "sy", "sz"] ctl = ico.create(lvl, uPivot.split("_")[0] + "_ctl", t, 15, icon=icon, w=bbRadio * 2, h=bbRadio * 2, d=bbRadio * 2) attribute.setKeyableAttributes(ctl, ctlKeyable) pm.parent(lvl, lvlParent) attribute.setKeyableAttributes(lvl, []) uPivotCtl.append(ctl) # Constraint cnsPart(ctl, pgrp) for oShape in uPivot.listRelatives(ad=True, s=True, type='mesh'): pm.connectAttr(ctl + ".visibility", oShape + ".visibility", f=True) meshList.append(oShape) # hidde user pivot uPivot.attr("visibility").set(False) # setting the global control if wCntCtl: absCenter = [0, 0, 0] else: absCenter = [(axis[0] + axis[1]) / 2 for axis in absBB] # set the cencter in the floor absCenter[1] = absBB[1][0] absRadio = max([absBB[0][1] - absBB[0][0], absBB[2][1] - absBB[2][0] ]) / 1.7 t = transform.getTransformFromPos(absCenter) lvl = pm.createNode('transform', n="global_npo") lvl.setTransformation(t) pm.parent(lvl, rig) ctlGlobal = ico.create(lvl, "global_ctl", t, 17, icon="square", w=absRadio * 2, d=absRadio * 2) pm.parent(lvlList, ctlGlobal) ctlList.append(ctlGlobal) attribute.setKeyableAttributes(lvl, []) for lvl in lvlList: attribute.setKeyableAttributes(lvl, []) # Create sets meshSet = pm.sets(meshList, n="CACHE_grp") ctlSet = pm.sets([ctlList, uPivotCtl], n="rig_controllers_grp") deformersSet = pm.sets(meshList, n="rig_deformers_grp") compGroup = pm.sets(meshList, n="rig_componentsRoots_grp") rigSets = pm.sets([meshSet, ctlSet, deformersSet, compGroup], n="rig_Sets_grp") pm.connectAttr(rigSets.attr("message"), "rig.rigGroups[0]") pm.connectAttr(meshSet.attr("message"), "rig.rigGroups[1]") pm.connectAttr(ctlSet.attr("message"), "rig.rigGroups[2]") pm.connectAttr(deformersSet.attr("message"), "rig.rigGroups[3]") pm.connectAttr(compGroup.attr("message"), "rig.rigGroups[4]") if oSel.hasAttr("animSets") and oSel.attr("animSets").get(): # create anim Sets pm.sets(n="animNodes", em=True) animNodes_set = pm.PyNode("animNodes") pm.sets(n="animSets", em=True) animSets_set = pm.PyNode("animSets") # adding set pm.sets(animSets_set, add=animNodes_set) pm.sets(animNodes_set, add=ctlSet.members()) pm.connectAttr(animSets_set.attr("message"), "rig.rigGroups[5]") pm.connectAttr(animNodes_set.attr("message"), "rig.rigGroups[6]") # create dagPose pm.select(ctlSet) o_node = pm.dagPose(save=True, selection=True) pm.connectAttr(o_node.message, rig.rigPoses[0]) return rig
def addCtl(self, parent, name, m, color, iconShape, tp=None, lp=True, mirrorConf=[0, 0, 0, 0, 0, 0, 0, 0, 0], **kwargs): """ Create the control and apply the shape, if this is alrealdy stored in the guide controllers grp. Args: parent (dagNode): The control parent name (str): The control name. m (matrix): The transfromation matrix for the control. color (int or list of float): The color for the control in index or RGB. iconShape (str): The controls default shape. tp (dagNode): Tag Parent Control object to connect as a parent controller lp (bool): Lock the parent controller channels kwargs (variant): Other arguments for the iconShape type variations Returns: dagNode: The Control. """ if "degree" not in kwargs.keys(): kwargs["degree"] = 1 fullName = self.getName(name) bufferName = fullName + "_controlBuffer" if bufferName in self.rig.guide.controllers.keys(): ctl_ref = self.rig.guide.controllers[bufferName] ctl = primitive.addTransform(parent, fullName, m) for shape in ctl_ref.getShapes(): ctl.addChild(shape, shape=True, add=True) pm.rename(shape, fullName + "Shape") icon.setcolor(ctl, color) else: ctl = icon.create(parent, fullName, m, color, iconShape, **kwargs) # create the attributes to handlde mirror and symetrical pose attribute.add_mirror_config_channels(ctl, mirrorConf) if self.settings["ctlGrp"]: ctlGrp = self.settings["ctlGrp"] self.addToGroup(ctl, ctlGrp, "controllers") else: ctlGrp = "controllers" self.addToGroup(ctl, ctlGrp) # lock the control parent attributes if is not a control if parent not in self.groups[ctlGrp] and lp: self.transform2Lock.append(parent) # Set the control shapes isHistoricallyInteresting for oShape in ctl.getShapes(): oShape.isHistoricallyInteresting.set(False) # set controller tag if versions.current() >= 201650: try: oldTag = pm.PyNode(ctl.name() + "_tag") if not oldTag.controllerObject.connections(): # NOTE: The next line is comment out. Because this will # happend alot since maya does't clean # controller tags after deleting the control Object of the # tag. This have been log to Autodesk. # If orphane tags are found, it will be clean in silence. # pm.displayWarning("Orphane Tag: %s will be delete and # created new for: %s"%(oldTag.name(), ctl.name())) pm.delete(oldTag) except TypeError: pass self.add_controller_tag(ctl, tp) return ctl
def lipsRig(eLoop, upVertex, lowVertex, namePrefix, thickness, doSkin, rigidLoops, falloffLoops, headJnt=None, jawJnt=None, parent=None, ctlName="ctl"): ###### # Var ###### FRONT_OFFSET = .02 NB_ROPE = 15 ################## # Helper functions ################## def setName(name, side="C", idx=None): namesList = [namePrefix, side, name] if idx is not None: namesList[1] = side + str(idx) name = "_".join(namesList) return name ############### # Checkers ############## # Loop if eLoop: try: eLoop = [pm.PyNode(e) for e in eLoop.split(",")] except pm.MayaNodeError: pm.displayWarning( "Some of the edges listed in edge loop can not be found") return else: pm.displayWarning("Please set the edge loop first") return # Vertex if upVertex: try: upVertex = pm.PyNode(upVertex) except pm.MayaNodeError: pm.displayWarning("%s can not be found" % upVertex) return else: pm.displayWarning("Please set the upper lip central vertex") return if lowVertex: try: lowVertex = pm.PyNode(lowVertex) except pm.MayaNodeError: pm.displayWarning("%s can not be found" % lowVertex) return else: pm.displayWarning("Please set the lower lip central vertex") return # skinnign data if doSkin: if not headJnt: pm.displayWarning("Please set the Head Jnt or unCheck Compute " "Topological Autoskin") return else: try: headJnt = pm.PyNode(headJnt) except pm.MayaNodeError: pm.displayWarning("Head Joint: %s can not be found" % headJnt) return if not jawJnt: pm.displayWarning("Please set the Jaw Jnt or unCheck Compute " "Topological Autoskin") return else: try: jawJnt = pm.PyNode(jawJnt) except pm.MayaNodeError: pm.displayWarning("Jaw Joint: %s can not be found" % jawJnt) return # check if the rig already exist in the current scene if pm.ls(setName("root")): pm.displayWarning("The object %s already exist in the scene. Please " "choose another name prefix" % setName("root")) return ##################### # Root creation ##################### lips_root = primitive.addTransform(None, setName("root")) lipsCrv_root = primitive.addTransform(lips_root, setName("crvs")) lipsRope_root = primitive.addTransform(lips_root, setName("rope")) ##################### # Geometry ##################### geo = pm.listRelatives(eLoop[0], parent=True)[0] ##################### # Groups ##################### try: ctlSet = pm.PyNode("rig_controllers_grp") except pm.MayaNodeError: pm.sets(n="rig_controllers_grp", em=True) ctlSet = pm.PyNode("rig_controllers_grp") try: defset = pm.PyNode("rig_deformers_grp") except pm.MayaNodeError: pm.sets(n="rig_deformers_grp", em=True) defset = pm.PyNode("rig_deformers_grp") ##################### # Curves creation ##################### # get extreme position using the outer loop extr_v = meshNavigation.getExtremeVertexFromLoop(eLoop) upPos = extr_v[0] lowPos = extr_v[1] inPos = extr_v[2] outPos = extr_v[3] edgeList = extr_v[4] vertexList = extr_v[5] upPos = upVertex lowPos = lowVertex # upper crv upLip_edgeRange = meshNavigation.edgeRangeInLoopFromMid( edgeList, upPos, inPos, outPos) upCrv = curve.createCuveFromEdges(upLip_edgeRange, setName("upperLip"), parent=lipsCrv_root) # store the closest vertex by curv cv index. To be use fo the auto skining upLip_closestVtxList = [] # offset upper lip Curve cvs = upCrv.getCVs(space="world") for i, cv in enumerate(cvs): closestVtx = meshNavigation.getClosestVertexFromTransform(geo, cv) upLip_closestVtxList.append(closestVtx) if i == 0: # we know the curv starts from right to left offset = [cv[0] - thickness, cv[1], cv[2] - thickness] elif i == len(cvs) - 1: offset = [cv[0] + thickness, cv[1], cv[2] - thickness] else: offset = [cv[0], cv[1] + thickness, cv[2]] upCrv.setCV(i, offset, space='world') # lower crv lowLip_edgeRange = meshNavigation.edgeRangeInLoopFromMid( edgeList, lowPos, inPos, outPos) lowCrv = curve.createCuveFromEdges(lowLip_edgeRange, setName("lowerLip"), parent=lipsCrv_root) lowLip_closestVtxList = [] # offset lower lip Curve cvs = lowCrv.getCVs(space="world") for i, cv in enumerate(cvs): closestVtx = meshNavigation.getClosestVertexFromTransform(geo, cv) lowLip_closestVtxList.append(closestVtx) if i == 0: # we know the curv starts from right to left offset = [cv[0] - thickness, cv[1], cv[2] - thickness] elif i == len(cvs) - 1: offset = [cv[0] + thickness, cv[1], cv[2] - thickness] else: # we populate the closest vertext list here to skipt the first # and latest point offset = [cv[0], cv[1] - thickness, cv[2]] lowCrv.setCV(i, offset, space='world') upCrv_ctl = curve.createCurveFromCurve(upCrv, setName("upCrv_%s" % ctlName), nbPoints=7, parent=lipsCrv_root) lowCrv_ctl = curve.createCurveFromCurve(lowCrv, setName("lowCrv_%s" % ctlName), nbPoints=7, parent=lipsCrv_root) upRope = curve.createCurveFromCurve(upCrv, setName("upRope_crv"), nbPoints=NB_ROPE, parent=lipsCrv_root) lowRope = curve.createCurveFromCurve(lowCrv, setName("lowRope_crv"), nbPoints=NB_ROPE, parent=lipsCrv_root) upCrv_upv = curve.createCurveFromCurve(upCrv, setName("upCrv_upv"), nbPoints=7, parent=lipsCrv_root) lowCrv_upv = curve.createCurveFromCurve(lowCrv, setName("lowCrv_upv"), nbPoints=7, parent=lipsCrv_root) upRope_upv = curve.createCurveFromCurve(upCrv, setName("upRope_upv"), nbPoints=NB_ROPE, parent=lipsCrv_root) lowRope_upv = curve.createCurveFromCurve(lowCrv, setName("lowRope_upv"), nbPoints=NB_ROPE, parent=lipsCrv_root) # offset upv curves for crv in [upCrv_upv, lowCrv_upv, upRope_upv, lowRope_upv]: cvs = crv.getCVs(space="world") for i, cv in enumerate(cvs): # we populate the closest vertext list here to skipt the first # and latest point offset = [cv[0], cv[1], cv[2] + FRONT_OFFSET] crv.setCV(i, offset, space='world') rigCrvs = [ upCrv, lowCrv, upCrv_ctl, lowCrv_ctl, upRope, lowRope, upCrv_upv, lowCrv_upv, upRope_upv, lowRope_upv ] for crv in rigCrvs: crv.attr("visibility").set(False) ################## # Controls ################## # Controls lists upControls = [] upVec = [] upNpo = [] lowControls = [] lowVec = [] lowNpo = [] # controls options axis_list = ["sx", "sy", "sz", "ro", "rx", "ry", "rz"] upCtlOptions = [["corner", "R", "square", 4, .05, axis_list], ["upOuter", "R", "circle", 14, .03, []], ["upInner", "R", "circle", 14, .03, []], ["upper", "C", "square", 4, .05, axis_list], ["upInner", "L", "circle", 14, .03, []], ["upOuter", "L", "circle", 14, .03, []], ["corner", "L", "square", 4, .05, axis_list]] lowCtlOptions = [["lowOuter", "R", "circle", 14, .03, []], ["lowInner", "R", "circle", 14, .03, []], ["lower", "C", "square", 4, .05, axis_list], ["lowInner", "L", "circle", 14, .03, []], ["lowOuter", "L", "circle", 14, .03, []]] params = ["tx", "ty", "tz"] # upper controls cvs = upCrv_ctl.getCVs(space="world") pm.progressWindow(title='Upper controls', progress=0, max=len(cvs)) v0 = transform.getTransformFromPos(cvs[0]) v1 = transform.getTransformFromPos(cvs[-1]) distSize = vector.getDistance(v0, v1) * 3 # print distSize for i, cv in enumerate(cvs): pm.progressWindow(e=True, step=1, status='\nCreating control for%s' % cv) t = transform.getTransformFromPos(cv) oName = upCtlOptions[i][0] oSide = upCtlOptions[i][1] o_icon = upCtlOptions[i][2] color = upCtlOptions[i][3] wd = upCtlOptions[i][4] oPar = upCtlOptions[i][5] npo = primitive.addTransform(lips_root, setName("%s_npo" % oName, oSide), t) upNpo.append(npo) ctl = icon.create(npo, setName("%s_%s" % (oName, ctlName), oSide), t, icon=o_icon, w=wd * distSize, d=wd * distSize, ro=datatypes.Vector(1.57079633, 0, 0), po=datatypes.Vector(0, 0, .07 * distSize), color=color) upControls.append(ctl) if len(ctlName.split("_")) == 2 and ctlName.split("_")[-1] == "ghost": pass else: pm.sets(ctlSet, add=ctl) attribute.setKeyableAttributes(ctl, params + oPar) upv = primitive.addTransform(ctl, setName("%s_upv" % oName, oSide), t) upv.attr("tz").set(FRONT_OFFSET) upVec.append(upv) if oSide == "R": npo.attr("sx").set(-1) pm.progressWindow(e=True, endProgress=True) # lower controls cvs = lowCrv_ctl.getCVs(space="world") pm.progressWindow(title='Lower controls', progress=0, max=len(cvs)) for i, cv in enumerate(cvs[1:-1]): pm.progressWindow(e=True, step=1, status='\nCreating control for%s' % cv) t = transform.getTransformFromPos(cv) oName = lowCtlOptions[i][0] oSide = lowCtlOptions[i][1] o_icon = lowCtlOptions[i][2] color = lowCtlOptions[i][3] wd = lowCtlOptions[i][4] oPar = lowCtlOptions[i][5] npo = primitive.addTransform(lips_root, setName("%s_npo" % oName, oSide), t) lowNpo.append(npo) ctl = icon.create(npo, setName("%s_%s" % (oName, ctlName), oSide), t, icon=o_icon, w=wd * distSize, d=wd * distSize, ro=datatypes.Vector(1.57079633, 0, 0), po=datatypes.Vector(0, 0, .07 * distSize), color=color) lowControls.append(ctl) if len(ctlName.split("_")) == 2 and ctlName.split("_")[-1] == "ghost": pass else: pm.sets(ctlSet, add=ctl) attribute.setKeyableAttributes(ctl, params + oPar) upv = primitive.addTransform(ctl, setName("%s_upv" % oName, oSide), t) upv.attr("tz").set(FRONT_OFFSET) lowVec.append(upv) if oSide == "R": npo.attr("sx").set(-1) pm.progressWindow(e=True, endProgress=True) # reparentig controls pm.parent(upNpo[1], lowNpo[0], upControls[0]) pm.parent(upNpo[2], upNpo[4], upControls[3]) pm.parent(upNpo[-2], lowNpo[-1], upControls[-1]) pm.parent(lowNpo[1], lowNpo[3], lowControls[2]) # Connecting control crvs with controls applyop.gear_curvecns_op(upCrv_ctl, upControls) applyop.gear_curvecns_op(lowCrv_ctl, [upControls[0]] + lowControls + [upControls[-1]]) applyop.gear_curvecns_op(upCrv_upv, upVec) applyop.gear_curvecns_op(lowCrv_upv, [upVec[0]] + lowVec + [upVec[-1]]) # adding wires pm.wire(upCrv, w=upCrv_ctl) pm.wire(lowCrv, w=lowCrv_ctl) pm.wire(upRope, w=upCrv_ctl) pm.wire(lowRope, w=lowCrv_ctl) pm.wire(upRope_upv, w=upCrv_upv) pm.wire(lowRope_upv, w=lowCrv_upv) # setting constrains # up cns_node = pm.parentConstraint(upControls[0], upControls[3], upControls[1].getParent(), mo=True, skipRotate=["x", "y", "z"]) cns_node.attr(upControls[0].name() + "W0").set(.75) cns_node.attr(upControls[3].name() + "W1").set(.25) cns_node = pm.parentConstraint(upControls[0], upControls[3], upControls[2].getParent(), mo=True, skipRotate=["x", "y", "z"]) cns_node.attr(upControls[0].name() + "W0").set(.25) cns_node.attr(upControls[3].name() + "W1").set(.75) cns_node = pm.parentConstraint(upControls[3], upControls[6], upControls[4].getParent(), mo=True, skipRotate=["x", "y", "z"]) cns_node.attr(upControls[3].name() + "W0").set(.75) cns_node.attr(upControls[6].name() + "W1").set(.25) cns_node = pm.parentConstraint(upControls[3], upControls[6], upControls[5].getParent(), mo=True, skipRotate=["x", "y", "z"]) cns_node.attr(upControls[3].name() + "W0").set(.25) cns_node.attr(upControls[6].name() + "W1").set(.75) # low cns_node = pm.parentConstraint(upControls[0], lowControls[2], lowControls[0].getParent(), mo=True, skipRotate=["x", "y", "z"]) cns_node.attr(upControls[0].name() + "W0").set(.75) cns_node.attr(lowControls[2].name() + "W1").set(.25) cns_node = pm.parentConstraint(upControls[0], lowControls[2], lowControls[1].getParent(), mo=True, skipRotate=["x", "y", "z"]) cns_node.attr(upControls[0].name() + "W0").set(.25) cns_node.attr(lowControls[2].name() + "W1").set(.75) cns_node = pm.parentConstraint(lowControls[2], upControls[6], lowControls[3].getParent(), mo=True, skipRotate=["x", "y", "z"]) cns_node.attr(lowControls[2].name() + "W0").set(.75) cns_node.attr(upControls[6].name() + "W1").set(.25) cns_node = pm.parentConstraint(lowControls[2], upControls[6], lowControls[4].getParent(), mo=True, skipRotate=["x", "y", "z"]) cns_node.attr(lowControls[2].name() + "W0").set(.25) cns_node.attr(upControls[6].name() + "W1").set(.75) ################## # Joints ################## lvlType = "transform" # upper joints upperJoints = [] cvs = upCrv.getCVs(space="world") pm.progressWindow(title='Creating Upper Joints', progress=0, max=len(cvs)) for i, cv in enumerate(cvs): pm.progressWindow(e=True, step=1, status='\nCreating Joint for %s' % cv) oTransUpV = pm.PyNode( pm.createNode(lvlType, n=setName("upLipRopeUpv", idx=str(i).zfill(3)), p=lipsRope_root, ss=True)) oTrans = pm.PyNode( pm.createNode(lvlType, n=setName("upLipRope", idx=str(i).zfill(3)), p=lipsRope_root, ss=True)) oParam, oLength = curve.getCurveParamAtPosition(upRope, cv) uLength = curve.findLenghtFromParam(upRope, oParam) u = uLength / oLength applyop.pathCns(oTransUpV, upRope_upv, cnsType=False, u=u, tangent=False) cns = applyop.pathCns(oTrans, upRope, cnsType=False, u=u, tangent=False) cns.setAttr("worldUpType", 1) cns.setAttr("frontAxis", 0) cns.setAttr("upAxis", 1) pm.connectAttr(oTransUpV.attr("worldMatrix[0]"), cns.attr("worldUpMatrix")) # getting joint parent if headJnt and isinstance(headJnt, str): try: j_parent = pm.PyNode(headJnt) except pm.MayaNodeError: j_parent = False elif headJnt and isinstance(headJnt, pm.PyNode): j_parent = headJnt else: j_parent = False jnt = rigbits.addJnt(oTrans, noReplace=True, parent=j_parent) upperJoints.append(jnt) pm.sets(defset, add=jnt) pm.progressWindow(e=True, endProgress=True) # lower joints lowerJoints = [] cvs = lowCrv.getCVs(space="world") pm.progressWindow(title='Creating Lower Joints', progress=0, max=len(cvs)) for i, cv in enumerate(cvs): pm.progressWindow(e=True, step=1, status='\nCreating Joint for %s' % cv) oTransUpV = pm.PyNode( pm.createNode(lvlType, n=setName("lowLipRopeUpv", idx=str(i).zfill(3)), p=lipsRope_root, ss=True)) oTrans = pm.PyNode( pm.createNode(lvlType, n=setName("lowLipRope", idx=str(i).zfill(3)), p=lipsRope_root, ss=True)) oParam, oLength = curve.getCurveParamAtPosition(lowRope, cv) uLength = curve.findLenghtFromParam(lowRope, oParam) u = uLength / oLength applyop.pathCns(oTransUpV, lowRope_upv, cnsType=False, u=u, tangent=False) cns = applyop.pathCns(oTrans, lowRope, cnsType=False, u=u, tangent=False) cns.setAttr("worldUpType", 1) cns.setAttr("frontAxis", 0) cns.setAttr("upAxis", 1) pm.connectAttr(oTransUpV.attr("worldMatrix[0]"), cns.attr("worldUpMatrix")) # getting joint parent if jawJnt and isinstance(jawJnt, str): try: j_parent = pm.PyNode(jawJnt) except pm.MayaNodeError: pass elif jawJnt and isinstance(jawJnt, pm.PyNode): j_parent = jawJnt else: j_parent = False jnt = rigbits.addJnt(oTrans, noReplace=True, parent=j_parent) lowerJoints.append(jnt) pm.sets(defset, add=jnt) pm.progressWindow(e=True, endProgress=True) ########################################### # Connecting rig ########################################### if parent: try: if isinstance(parent, basestring): parent = pm.PyNode(parent) parent.addChild(lips_root) except pm.MayaNodeError: pm.displayWarning("The Lips rig can not be parent to: %s. Maybe " "this object doesn't exist." % parent) if headJnt and jawJnt: try: if isinstance(headJnt, basestring): headJnt = pm.PyNode(headJnt) except pm.MayaNodeError: pm.displayWarning("Head Joint or Upper Lip Joint %s. Can not be " "fount in the scene" % headJnt) return try: if isinstance(jawJnt, basestring): jawJnt = pm.PyNode(jawJnt) except pm.MayaNodeError: pm.displayWarning("Jaw Joint or Lower Lip Joint %s. Can not be " "fount in the scene" % jawJnt) return # right corner connection pm.parentConstraint(headJnt, jawJnt, upControls[0].getParent(), mo=True) # left corner connection pm.parentConstraint(headJnt, jawJnt, upControls[-1].getParent(), mo=True) # up control connection pm.parentConstraint(headJnt, upControls[3].getParent(), mo=True) # low control connection pm.parentConstraint(jawJnt, lowControls[2].getParent(), mo=True) ########################################### # Auto Skinning ########################################### if doSkin: # eyelid vertex rows totalLoops = rigidLoops + falloffLoops vertexLoopList = meshNavigation.getConcentricVertexLoop( vertexList, totalLoops) vertexRowList = meshNavigation.getVertexRowsFromLoops(vertexLoopList) # we set the first value 100% for the first initial loop skinPercList = [1.0] # we expect to have a regular grid topology for r in range(rigidLoops): for rr in range(2): skinPercList.append(1.0) increment = 1.0 / float(falloffLoops) # we invert to smooth out from 100 to 0 inv = 1.0 - increment for r in range(falloffLoops): for rr in range(2): if inv < 0.0: inv = 0.0 skinPercList.append(inv) inv -= increment # this loop add an extra 0.0 indices to avoid errors for r in range(10): for rr in range(2): skinPercList.append(0.0) # base skin if headJnt: try: headJnt = pm.PyNode(headJnt) except pm.MayaNodeError: pm.displayWarning("Auto skin aborted can not find %s " % headJnt) return # Check if the object has a skinCluster objName = pm.listRelatives(geo, parent=True)[0] skinCluster = skin.getSkinCluster(objName) if not skinCluster: skinCluster = pm.skinCluster(headJnt, geo, tsb=True, nw=2, n='skinClsEyelid') lipsJoints = upperJoints + lowerJoints closestVtxList = upLip_closestVtxList + lowLip_closestVtxList pm.progressWindow(title='Auto skinning process', progress=0, max=len(lipsJoints)) for i, jnt in enumerate(lipsJoints): pm.progressWindow(e=True, step=1, status='\nSkinning %s' % jnt) skinCluster.addInfluence(jnt, weight=0) v = closestVtxList[i] for row in vertexRowList: if v in row: for i, rv in enumerate(row): # find the deformer with max value for each vertex w = pm.skinPercent(skinCluster, rv, query=True, value=True) transJoint = pm.skinPercent(skinCluster, rv, query=True, t=None) max_value = max(w) max_index = w.index(max_value) perc = skinPercList[i] t_value = [(jnt, perc), (transJoint[max_index], 1.0 - perc)] pm.skinPercent(skinCluster, rv, transformValue=t_value) pm.progressWindow(e=True, endProgress=True)
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 eyeRig(eyeMesh, edgeLoop, blinkH, namePrefix, offset, rigidLoops, falloffLoops, headJnt, doSkin, parent=None, ctlName="ctl", sideRange=False, customCorner=False, intCorner=None, extCorner=None, ctlGrp=None, defGrp=None): """Create eyelid and eye rig Args: eyeMesh (TYPE): Description edgeLoop (TYPE): Description blinkH (TYPE): Description namePrefix (TYPE): Description offset (TYPE): Description rigidLoops (TYPE): Description falloffLoops (TYPE): Description headJnt (TYPE): Description doSkin (TYPE): Description parent (None, optional): Description ctlName (str, optional): Description sideRange (bool, optional): Description customCorner (bool, optional): Description intCorner (None, optional): Description extCorner (None, optional): Description ctlGrp (None, optional): Description defGrp (None, optional): Description Returns: TYPE: Description """ # Checkers if edgeLoop: edgeLoopList = [pm.PyNode(e) for e in edgeLoop.split(",")] else: pm.displayWarning("Please set the edge loop first") return if eyeMesh: try: eyeMesh = pm.PyNode(eyeMesh) except pm.MayaNodeError: pm.displayWarning("The object %s can not be found in the " "scene" % (eyeMesh)) return else: pm.displayWarning("Please set the eye mesh first") if doSkin: if not headJnt: pm.displayWarning("Please set the Head Jnt or unCheck " "Compute Topological Autoskin") return # Initial Data bboxCenter = meshNavigation.bboxCenter(eyeMesh) extr_v = meshNavigation.getExtremeVertexFromLoop(edgeLoopList, sideRange) upPos = extr_v[0] lowPos = extr_v[1] inPos = extr_v[2] outPos = extr_v[3] edgeList = extr_v[4] vertexList = extr_v[5] # Detect the side L or R from the x value if inPos.getPosition(space='world')[0] < 0.0: side = "R" inPos = extr_v[3] outPos = extr_v[2] normalPos = outPos npw = normalPos.getPosition(space='world') normalVec = npw - bboxCenter else: side = "L" normalPos = outPos npw = normalPos.getPosition(space='world') normalVec = bboxCenter - npw # Manual Vertex corners if customCorner: if intCorner: try: if side == "R": inPos = pm.PyNode(extCorner) else: inPos = pm.PyNode(intCorner) except pm.MayaNodeError: pm.displayWarning("%s can not be found" % intCorner) return else: pm.displayWarning("Please set the internal eyelid corner") return if extCorner: try: normalPos = pm.PyNode(extCorner) npw = normalPos.getPosition(space='world') if side == "R": outPos = pm.PyNode(intCorner) normalVec = npw - bboxCenter else: outPos = pm.PyNode(extCorner) normalVec = bboxCenter - npw except pm.MayaNodeError: pm.displayWarning("%s can not be found" % extCorner) return else: pm.displayWarning("Please set the external eyelid corner") return # Check if we have prefix: if namePrefix: namePrefix = string.removeInvalidCharacter(namePrefix) else: pm.displayWarning("Prefix is needed") return def setName(name, ind=None): namesList = [namePrefix, side, name] if ind is not None: namesList[1] = side + str(ind) name = "_".join(namesList) return name if pm.ls(setName("root")): pm.displayWarning("The object %s already exist in the scene. Please " "choose another name prefix" % setName("root")) return # Eye root eye_root = primitive.addTransform(None, setName("root")) eyeCrv_root = primitive.addTransform(eye_root, setName("crvs")) # Eyelid Main crvs try: upEyelid = meshNavigation.edgeRangeInLoopFromMid( edgeList, upPos, inPos, outPos) upCrv = curve.createCurveFromOrderedEdges( upEyelid, inPos, setName("upperEyelid"), parent=eyeCrv_root) upCrv_ctl = curve.createCurveFromOrderedEdges( upEyelid, inPos, setName("upCrv_%s" % ctlName), parent=eyeCrv_root) pm.rebuildCurve(upCrv_ctl, s=2, rt=0, rpo=True, ch=False) lowEyelid = meshNavigation.edgeRangeInLoopFromMid( edgeList, lowPos, inPos, outPos) lowCrv = curve.createCurveFromOrderedEdges( lowEyelid, inPos, setName("lowerEyelid"), parent=eyeCrv_root) lowCrv_ctl = curve.createCurveFromOrderedEdges( lowEyelid, inPos, setName("lowCrv_%s" % ctlName), parent=eyeCrv_root) pm.rebuildCurve(lowCrv_ctl, s=2, rt=0, rpo=True, ch=False) except UnboundLocalError: if customCorner: pm.displayWarning("This error is maybe caused because the custom " "Corner vertex is not part of the edge loop") pm.displayError(traceback.format_exc()) return upBlink = curve.createCurveFromCurve( upCrv, setName("upblink_crv"), nbPoints=30, parent=eyeCrv_root) lowBlink = curve.createCurveFromCurve( lowCrv, setName("lowBlink_crv"), nbPoints=30, parent=eyeCrv_root) upTarget = curve.createCurveFromCurve( upCrv, setName("upblink_target"), nbPoints=30, parent=eyeCrv_root) lowTarget = curve.createCurveFromCurve( lowCrv, setName("lowBlink_target"), nbPoints=30, parent=eyeCrv_root) midTarget = curve.createCurveFromCurve( lowCrv, setName("midBlink_target"), nbPoints=30, parent=eyeCrv_root) rigCrvs = [upCrv, lowCrv, upCrv_ctl, lowCrv_ctl, upBlink, lowBlink, upTarget, lowTarget, midTarget] for crv in rigCrvs: crv.attr("visibility").set(False) # localBBOX localBBox = eyeMesh.getBoundingBox(invisible=True, space='world') wRadius = abs((localBBox[0][0] - localBBox[1][0])) dRadius = abs((localBBox[0][1] - localBBox[1][1]) / 1.7) # Groups if not ctlGrp: ctlGrp = "rig_controllers_grp" try: ctlSet = pm.PyNode(ctlGrp) except pm.MayaNodeError: pm.sets(n=ctlGrp, em=True) ctlSet = pm.PyNode(ctlGrp) if not defGrp: defGrp = "rig_deformers_grp" try: defset = pm.PyNode(defGrp) except pm.MayaNodeError: pm.sets(n=defGrp, em=True) defset = pm.PyNode(defGrp) # Calculate center looking at averagePosition = ((upPos.getPosition(space='world') + lowPos.getPosition(space='world') + inPos.getPosition(space='world') + outPos.getPosition(space='world')) / 4) if side == "R": negate = False offset = offset over_offset = dRadius else: negate = False over_offset = dRadius if side == "R" and sideRange or side == "R" and customCorner: axis = "z-x" # axis = "zx" else: axis = "z-x" t = transform.getTransformLookingAt( bboxCenter, averagePosition, normalVec, axis=axis, negate=negate) over_npo = primitive.addTransform( eye_root, setName("center_lookatRoot"), t) over_ctl = icon.create(over_npo, setName("over_%s" % ctlName), t, icon="square", w=wRadius, d=dRadius, ro=datatypes.Vector(1.57079633, 0, 0), po=datatypes.Vector(0, 0, over_offset), color=4) node.add_controller_tag(over_ctl) attribute.add_mirror_config_channels(over_ctl) attribute.setKeyableAttributes( over_ctl, params=["tx", "ty", "tz", "ro", "rx", "ry", "rz", "sx", "sy", "sz"]) if side == "R": over_npo.attr("rx").set(over_npo.attr("rx").get() * -1) over_npo.attr("ry").set(over_npo.attr("ry").get() + 180) over_npo.attr("sz").set(-1) if len(ctlName.split("_")) == 2 and ctlName.split("_")[-1] == "ghost": pass else: pm.sets(ctlSet, add=over_ctl) center_lookat = primitive.addTransform( over_ctl, setName("center_lookat"), t) # Tracking # Eye aim control t_arrow = transform.getTransformLookingAt(bboxCenter, averagePosition, upPos.getPosition(space='world'), axis="zy", negate=False) radius = abs((localBBox[0][0] - localBBox[1][0]) / 1.7) arrow_npo = primitive.addTransform(eye_root, setName("aim_npo"), t_arrow) arrow_ctl = icon.create(arrow_npo, setName("aim_%s" % ctlName), t_arrow, icon="arrow", w=1, po=datatypes.Vector(0, 0, radius), color=4) if len(ctlName.split("_")) == 2 and ctlName.split("_")[-1] == "ghost": pass else: pm.sets(ctlSet, add=arrow_ctl) attribute.setKeyableAttributes(arrow_ctl, params=["rx", "ry", "rz"]) # tracking custom trigger if side == "R": tt = t_arrow else: tt = t aimTrigger_root = primitive.addTransform( center_lookat, setName("aimTrigger_root"), tt) aimTrigger_lvl = primitive.addTransform( aimTrigger_root, setName("aimTrigger_lvl"), tt) aimTrigger_lvl.attr("tz").set(1.0) aimTrigger_ref = primitive.addTransform( aimTrigger_lvl, setName("aimTrigger_ref"), tt) aimTrigger_ref.attr("tz").set(0.0) # connect trigger with arrow_ctl pm.parentConstraint(arrow_ctl, aimTrigger_ref, mo=True) # Controls lists upControls = [] trackLvl = [] # upper eyelid controls upperCtlNames = ["inCorner", "upInMid", "upMid", "upOutMid", "outCorner"] cvs = upCrv_ctl.getCVs(space="world") if side == "R" and not sideRange: # if side == "R": cvs = [cv for cv in reversed(cvs)] for i, cv in enumerate(cvs): if utils.is_odd(i): color = 14 wd = .5 icon_shape = "circle" params = ["tx", "ty", "tz"] else: color = 4 wd = .7 icon_shape = "square" params = ["tx", "ty", "tz", "ro", "rx", "ry", "rz", "sx", "sy", "sz"] t = transform.setMatrixPosition(t, cvs[i]) npo = primitive.addTransform(center_lookat, setName("%s_npo" % upperCtlNames[i]), t) npoBase = npo if i == 2: # we add an extra level to input the tracking ofset values npo = primitive.addTransform(npo, setName("%s_trk" % upperCtlNames[i]), t) trackLvl.append(npo) ctl = icon.create(npo, setName("%s_%s" % (upperCtlNames[i], ctlName)), t, icon=icon_shape, w=wd, d=wd, ro=datatypes.Vector(1.57079633, 0, 0), po=datatypes.Vector(0, 0, offset), color=color) attribute.add_mirror_config_channels(ctl) node.add_controller_tag(ctl, over_ctl) upControls.append(ctl) if len(ctlName.split("_")) == 2 and ctlName.split("_")[-1] == "ghost": pass else: pm.sets(ctlSet, add=ctl) attribute.setKeyableAttributes(ctl, params) if side == "R": npoBase.attr("ry").set(180) npoBase.attr("sz").set(-1) # adding parent average contrains to odd controls for i, ctl in enumerate(upControls): if utils.is_odd(i): pm.parentConstraint(upControls[i - 1], upControls[i + 1], ctl.getParent(), mo=True) # lower eyelid controls lowControls = [upControls[0]] lowerCtlNames = ["inCorner", "lowInMid", "lowMid", "lowOutMid", "outCorner"] cvs = lowCrv_ctl.getCVs(space="world") if side == "R" and not sideRange: cvs = [cv for cv in reversed(cvs)] for i, cv in enumerate(cvs): # we skip the first and last point since is already in the uper eyelid if i in [0, 4]: continue if utils.is_odd(i): color = 14 wd = .5 icon_shape = "circle" params = ["tx", "ty", "tz"] else: color = 4 wd = .7 icon_shape = "square" params = ["tx", "ty", "tz", "ro", "rx", "ry", "rz", "sx", "sy", "sz"] t = transform.setMatrixPosition(t, cvs[i]) npo = primitive.addTransform(center_lookat, setName("%s_npo" % lowerCtlNames[i]), t) npoBase = npo if i == 2: # we add an extra level to input the tracking ofset values npo = primitive.addTransform(npo, setName("%s_trk" % lowerCtlNames[i]), t) trackLvl.append(npo) ctl = icon.create(npo, setName("%s_%s" % (lowerCtlNames[i], ctlName)), t, icon=icon_shape, w=wd, d=wd, ro=datatypes.Vector(1.57079633, 0, 0), po=datatypes.Vector(0, 0, offset), color=color) attribute.add_mirror_config_channels(ctl) lowControls.append(ctl) if len(ctlName.split("_")) == 2 and ctlName.split("_")[-1] == "ghost": pass else: pm.sets(ctlSet, add=ctl) attribute.setKeyableAttributes(ctl, params) # mirror behaviout on R side controls if side == "R": npoBase.attr("ry").set(180) npoBase.attr("sz").set(-1) for lctl in reversed(lowControls[1:]): node.add_controller_tag(lctl, over_ctl) lowControls.append(upControls[-1]) # adding parent average contrains to odd controls for i, ctl in enumerate(lowControls): if utils.is_odd(i): pm.parentConstraint(lowControls[i - 1], lowControls[i + 1], ctl.getParent(), mo=True) # Connecting control crvs with controls applyop.gear_curvecns_op(upCrv_ctl, upControls) applyop.gear_curvecns_op(lowCrv_ctl, lowControls) # adding wires w1 = pm.wire(upCrv, w=upBlink)[0] w2 = pm.wire(lowCrv, w=lowBlink)[0] w3 = pm.wire(upTarget, w=upCrv_ctl)[0] w4 = pm.wire(lowTarget, w=lowCrv_ctl)[0] # adding blendshapes bs_upBlink = pm.blendShape(upTarget, midTarget, upBlink, n="blendShapeUpBlink") bs_lowBlink = pm.blendShape(lowTarget, midTarget, lowBlink, n="blendShapeLowBlink") bs_mid = pm.blendShape(lowTarget, upTarget, midTarget, n="blendShapeLowBlink") # setting blendshape reverse connections rev_node = pm.createNode("reverse") pm.connectAttr(bs_upBlink[0].attr(midTarget.name()), rev_node + ".inputX") pm.connectAttr(rev_node + ".outputX", bs_upBlink[0].attr(upTarget.name())) rev_node = pm.createNode("reverse") pm.connectAttr(bs_lowBlink[0].attr(midTarget.name()), rev_node + ".inputX") pm.connectAttr(rev_node + ".outputX", bs_lowBlink[0].attr(lowTarget.name())) rev_node = pm.createNode("reverse") pm.connectAttr(bs_mid[0].attr(upTarget.name()), rev_node + ".inputX") pm.connectAttr(rev_node + ".outputX", bs_mid[0].attr(lowTarget.name())) # setting default values bs_mid[0].attr(upTarget.name()).set(blinkH) # joints root jnt_root = primitive.addTransformFromPos( eye_root, setName("joints"), pos=bboxCenter) # head joint if headJnt: try: headJnt = pm.PyNode(headJnt) jnt_base = headJnt except pm.MayaNodeError: pm.displayWarning( "Aborted can not find %s " % headJnt) return else: # Eye root jnt_base = jnt_root eyeTargets_root = primitive.addTransform(eye_root, setName("targets")) eyeCenter_jnt = rigbits.addJnt(arrow_ctl, jnt_base, grp=defset, jntName=setName("center_jnt")) # Upper Eyelid joints ################################################## cvs = upCrv.getCVs(space="world") upCrv_info = node.createCurveInfoNode(upCrv) # aim constrain targets and joints upperEyelid_aimTargets = [] upperEyelid_jnt = [] upperEyelid_jntRoot = [] for i, cv in enumerate(cvs): # aim targets trn = primitive.addTransformFromPos(eyeTargets_root, setName("upEyelid_aimTarget", i), pos=cv) upperEyelid_aimTargets.append(trn) # connecting positions with crv pm.connectAttr(upCrv_info + ".controlPoints[%s]" % str(i), trn.attr("translate")) # joints jntRoot = primitive.addJointFromPos(jnt_root, setName("upEyelid_jnt_base", i), pos=bboxCenter) jntRoot.attr("radius").set(.08) jntRoot.attr("visibility").set(False) upperEyelid_jntRoot.append(jntRoot) applyop.aimCns(jntRoot, trn, axis="zy", wupObject=jnt_root) jnt_ref = primitive.addJointFromPos(jntRoot, setName("upEyelid_jnt_ref", i), pos=cv) jnt_ref.attr("radius").set(.08) jnt_ref.attr("visibility").set(False) jnt = rigbits.addJnt(jnt_ref, jnt_base, grp=defset, jntName=setName("upEyelid_jnt", i)) upperEyelid_jnt.append(jnt) # Lower Eyelid joints ################################################## cvs = lowCrv.getCVs(space="world") lowCrv_info = node.createCurveInfoNode(lowCrv) # aim constrain targets and joints lowerEyelid_aimTargets = [] lowerEyelid_jnt = [] lowerEyelid_jntRoot = [] for i, cv in enumerate(cvs): if i in [0, len(cvs) - 1]: continue # aim targets trn = primitive.addTransformFromPos(eyeTargets_root, setName("lowEyelid_aimTarget", i), pos=cv) lowerEyelid_aimTargets.append(trn) # connecting positions with crv pm.connectAttr(lowCrv_info + ".controlPoints[%s]" % str(i), trn.attr("translate")) # joints jntRoot = primitive.addJointFromPos(jnt_root, setName("lowEyelid_base", i), pos=bboxCenter) jntRoot.attr("radius").set(.08) jntRoot.attr("visibility").set(False) lowerEyelid_jntRoot.append(jntRoot) applyop.aimCns(jntRoot, trn, axis="zy", wupObject=jnt_root) jnt_ref = primitive.addJointFromPos(jntRoot, setName("lowEyelid_jnt_ref", i), pos=cv) jnt_ref.attr("radius").set(.08) jnt_ref.attr("visibility").set(False) jnt = rigbits.addJnt(jnt_ref, jnt_base, grp=defset, jntName=setName("lowEyelid_jnt", i)) lowerEyelid_jnt.append(jnt) # Channels # Adding and connecting attributes for the blink up_ctl = upControls[2] blink_att = attribute.addAttribute( over_ctl, "blink", "float", 0, minValue=0, maxValue=1) blinkMult_att = attribute.addAttribute( over_ctl, "blinkMult", "float", 1, minValue=1, maxValue=2) midBlinkH_att = attribute.addAttribute( over_ctl, "blinkHeight", "float", blinkH, minValue=0, maxValue=1) mult_node = node.createMulNode(blink_att, blinkMult_att) pm.connectAttr(mult_node + ".outputX", bs_upBlink[0].attr(midTarget.name())) pm.connectAttr(mult_node + ".outputX", bs_lowBlink[0].attr(midTarget.name())) pm.connectAttr(midBlinkH_att, bs_mid[0].attr(upTarget.name())) low_ctl = lowControls[2] # Adding channels for eye tracking upVTracking_att = attribute.addAttribute(up_ctl, "vTracking", "float", .02, minValue=0, maxValue=1, keyable=False, channelBox=True) upHTracking_att = attribute.addAttribute(up_ctl, "hTracking", "float", .01, minValue=0, maxValue=1, keyable=False, channelBox=True) lowVTracking_att = attribute.addAttribute(low_ctl, "vTracking", "float", .01, minValue=0, maxValue=1, keyable=False, channelBox=True) lowHTracking_att = attribute.addAttribute(low_ctl, "hTracking", "float", .01, minValue=0, maxValue=1, keyable=False, channelBox=True) mult_node = node.createMulNode(upVTracking_att, aimTrigger_ref.attr("ty")) pm.connectAttr(mult_node + ".outputX", trackLvl[0].attr("ty")) mult_node = node.createMulNode(upHTracking_att, aimTrigger_ref.attr("tx")) pm.connectAttr(mult_node + ".outputX", trackLvl[0].attr("tx")) mult_node = node.createMulNode(lowVTracking_att, aimTrigger_ref.attr("ty")) pm.connectAttr(mult_node + ".outputX", trackLvl[1].attr("ty")) mult_node = node.createMulNode(lowHTracking_att, aimTrigger_ref.attr("tx")) pm.connectAttr(mult_node + ".outputX", trackLvl[1].attr("tx")) # Tension on blink node.createReverseNode(blink_att, w1.scale[0]) node.createReverseNode(blink_att, w3.scale[0]) node.createReverseNode(blink_att, w2.scale[0]) node.createReverseNode(blink_att, w4.scale[0]) ########################################### # Reparenting ########################################### if parent: try: if isinstance(parent, basestring): parent = pm.PyNode(parent) parent.addChild(eye_root) except pm.MayaNodeError: pm.displayWarning("The eye rig can not be parent to: %s. Maybe " "this object doesn't exist." % parent) ########################################### # Auto Skinning ########################################### if doSkin: # eyelid vertex rows totalLoops = rigidLoops + falloffLoops vertexLoopList = meshNavigation.getConcentricVertexLoop(vertexList, totalLoops) vertexRowList = meshNavigation.getVertexRowsFromLoops(vertexLoopList) # we set the first value 100% for the first initial loop skinPercList = [1.0] # we expect to have a regular grid topology for r in range(rigidLoops): for rr in range(2): skinPercList.append(1.0) increment = 1.0 / float(falloffLoops) # we invert to smooth out from 100 to 0 inv = 1.0 - increment for r in range(falloffLoops): for rr in range(2): if inv < 0.0: inv = 0.0 skinPercList.append(inv) inv -= increment # this loop add an extra 0.0 indices to avoid errors for r in range(10): for rr in range(2): skinPercList.append(0.0) # base skin geo = pm.listRelatives(edgeLoopList[0], parent=True)[0] # Check if the object has a skinCluster objName = pm.listRelatives(geo, parent=True)[0] skinCluster = skin.getSkinCluster(objName) if not skinCluster: skinCluster = pm.skinCluster(headJnt, geo, tsb=True, nw=2, n='skinClsEyelid') eyelidJoints = upperEyelid_jnt + lowerEyelid_jnt pm.progressWindow(title='Auto skinning process', progress=0, max=len(eyelidJoints)) firstBoundary = False for jnt in eyelidJoints: pm.progressWindow(e=True, step=1, status='\nSkinning %s' % jnt) skinCluster.addInfluence(jnt, weight=0) v = meshNavigation.getClosestVertexFromTransform(geo, jnt) for row in vertexRowList: if v in row: it = 0 # iterator inc = 1 # increment for i, rv in enumerate(row): try: perc = skinPercList[it] t_val = [(jnt, perc), (headJnt, 1.0 - perc)] pm.skinPercent(skinCluster, rv, transformValue=t_val) if rv.isOnBoundary(): # we need to compare with the first boundary # to check if the row have inverted direction # and offset the value if not firstBoundary: firstBoundary = True firstBoundaryValue = it else: if it < firstBoundaryValue: it -= 1 elif it > firstBoundaryValue: it += 1 inc = 2 except IndexError: continue it = it + inc pm.progressWindow(e=True, endProgress=True) # Eye Mesh skinning skinCluster = skin.getSkinCluster(eyeMesh) if not skinCluster: skinCluster = pm.skinCluster(eyeCenter_jnt, eyeMesh, tsb=True, nw=1, n='skinClsEye')
def addCtl(self, parent, name, m, color, icon, tp=None, **kwargs): """ Create the control and apply the shape, if this is alrealdy stored in the guide controllers grp. Args: parent (dagNode): The control parent name (str): The control name. m (matrix): The transfromation matrix for the control. color (int or list of float): The color for the control in idex or RGB. icon (str): The controls default shape. tp (dagNode): Tag Parent Control object to connect as a parent controller kwargs (variant): Other arguments for the icon type variations. Returns: dagNode: The Control. """ fullName = self.getName(name) bufferName = fullName + "_controlBuffer" if bufferName in self.rig.guide.controllers.keys(): ctl_ref = self.rig.guide.controllers[bufferName] ctl = pri.addTransform(parent, fullName, m) for shape in ctl_ref.getShapes(): ctl.addChild(shape, shape=True, add=True) pm.rename(shape, fullName + "Shape") ico.setcolor(ctl, color) else: ctl = ico.create(parent, fullName, m, color, icon, **kwargs) # create the attributes to handlde mirror and symetrical pose att.addAttribute(ctl, "invTx", "bool", 0, keyable=False, niceName="Invert Mirror TX") att.addAttribute(ctl, "invTy", "bool", 0, keyable=False, niceName="Invert Mirror TY") att.addAttribute(ctl, "invTz", "bool", 0, keyable=False, niceName="Invert Mirror TZ") att.addAttribute(ctl, "invRx", "bool", 0, keyable=False, niceName="Invert Mirror RX") att.addAttribute(ctl, "invRy", "bool", 0, keyable=False, niceName="Invert Mirror RY") att.addAttribute(ctl, "invRz", "bool", 0, keyable=False, niceName="Invert Mirror RZ") att.addAttribute(ctl, "invSx", "bool", 0, keyable=False, niceName="Invert Mirror SX") att.addAttribute(ctl, "invSy", "bool", 0, keyable=False, niceName="Invert Mirror SY") att.addAttribute(ctl, "invSz", "bool", 0, keyable=False, niceName="Invert Mirror SZ") if self.settings["ctlGrp"]: ctlGrp = self.settings["ctlGrp"] self.addToGroup(ctl, ctlGrp, "controllers") else: ctlGrp = "controllers" self.addToGroup(ctl, ctlGrp) #lock the control parent attributes if is not a control if parent not in self.groups[ctlGrp]: self.transform2Lock.append(parent) # Set the control shapes isHistoricallyInteresting for oShape in ctl.getShapes(): oShape.isHistoricallyInteresting.set(False) #set controller tag if versions.current() >= 201650: try: oldTag = pm.PyNode(ctl.name() + "_tag") if not oldTag.controllerObject.connections(): # NOTE: The next line is comment out. Because this will happend alot since maya does't clean # controller tags after deleting the control Object of the tag. This have been log to Autodesk. # If orphane tags are found, it will be clean in silence. # pm.displayWarning("Orphane Tag: %s will be delete and created new for: %s"%(oldTag.name(), ctl.name())) pm.delete(oldTag) except: pass pm.controller(ctl) if tp: ctt = pm.PyNode(pm.controller(ctl, q=True)[0]) tpTagNode = pm.PyNode(pm.controller(tp, q=True)[0]) tpTagNode.cycleWalkSibling.set(True) pm.connectAttr(tpTagNode.prepopulate, ctt.prepopulate, f=True) # The connectAttr to the children attribute is giving error # i.e: pm.connectAttr(ctt.attr("parent"), tpTagNode.attr("children"), na=True) # if using the next available option tag # I was expecting to use ctt.setParent(tp) but doest't work as expected. # After reading the documentation this method looks prety useless. # Looks like is boolean and works based on selection :( # this is a dirty loop workaround. Naaah! i = 0 while True: try: pm.connectAttr(ctt.parent, tpTagNode.attr("children[%s]" % str(i))) break except: i += 1 if i > 100: pm.displayWarning( "The controller tag for %s has reached the limit index of 100 children" % ctl.name()) break return ctl
def _createSoftTweakControls(name, parent=None, t=datatypes.Matrix(), grps=None, size=0.5): root_name = "{}_{}".format(name, "softTweak_root") namespace = None try: # simple check if exist a tweak with the same name exist = pm.PyNode(root_name) if exist: pm.displayError("the tweak: {} already exist. Please use a " "unique name.".format(name)) return False, False except pm.MayaNodeError: if parent: try: p = pm.PyNode(parent) namespace = p.namespace() except pm.MayaNodeError: pm.displayWarning("{} is not a valid parent or doesn't " "exist".format(parent)) p = None else: p = None root = primitive.addTransform(p, root_name, t) attribute.addAttribute(root, "iconSize", "float", size, keyable=False) baseCtl = icon.create(parent=root, name="{}_{}".format(name, "baseSoftTweak_ctl"), m=t, color=[1, 0.622, 0], icon="square", d=size, w=size) tweakCtl = icon.create(parent=baseCtl, name="{}_{}".format(name, "softTweak_ctl"), m=t, color=[0.89, 0.0, 0.143], icon="diamond", w=size * .8) attribute.addAttribute(tweakCtl, "falloff", "float", size) if grps: if not isinstance(grps, list): grps = [grps] for grp in grps: try: # try if exist oGrp = pm.PyNode(grp) except pm.MayaNodeError: # create a new grp if does't exist if len(grp.split("_")) >= 3: # check name convention name = grp else: name = "rig_{}_grp".format(grp) # namespace basic handling # NOTE: Doesn't support more than one namespace stacked if namespace and len(name.split(":")) < 2: name = namespace + name oGrp = pm.sets(n=name, em=True) pm.sets(oGrp, add=[baseCtl, tweakCtl]) if t: root.setMatrix(t, worldSpace=True) return baseCtl, tweakCtl