def attachSecondaryControlsToMainCurve(self): secControlsMerged = [] tempMainCtlCurves = self.mainCtlCurves tempMainUpvCurves = self.mainCtlUpvs secControlsMerged.append(self.secondaryControls) for secCtl in self.secondaryControls: constraints.matrixConstraint(self.root, secCtl.getParent(2), 'rs', True) # controls tags # node.add_controller_tag(secCtl, tagParent=parent_tag_L) # create hooks on the main ctl curve for j, crv in enumerate(self.secondaryCurves): lvlType = 'transform' cvs = crv.getCVs(space="object") for i, cv in enumerate(cvs): oTransUpV = pm.PyNode( pm.createNode(lvlType, n=self.getName("secNpoUpv", str(i).zfill(3)), p=self.browsHooks_root, ss=True)) oTrans = pm.PyNode( pm.createNode(lvlType, n=self.getName("secNpo", str(i).zfill(3)), p=self.browsHooks_root, ss=True)) oParam, oLength = curve.getCurveParamAtPosition(crv, cv) uLength = curve.findLenghtFromParam(crv, oParam) u = uLength / oLength # create motion paths transforms on main ctl curves cns = applyPathCnsLocal(oTransUpV, tempMainUpvCurves[j], u) cns = applyPathCnsLocal(oTrans, tempMainCtlCurves[j], u) pm.connectAttr(oTransUpV.attr("worldMatrix[0]"), cns.attr("worldUpMatrix")) # connect secondary control to oTrans hook. constraints.matrixConstraint( oTrans, secControlsMerged[j][i].getParent(2), 't', True)
def rig(edge_loop="", up_vertex="", low_vertex="", name_prefix="", thickness=0.3, do_skin=True, rigid_loops=5, falloff_loops=8, head_joint=None, jaw_joint=None, parent_node=None, control_name="ctl", upper_lip_ctl=None, lower_lip_ctl=None): ###### # Var ###### FRONT_OFFSET = .02 NB_ROPE = 15 ################## # Helper functions ################## def setName(name, side="C", idx=None): namesList = [name_prefix, side, name] if idx is not None: namesList[1] = side + str(idx) name = "_".join(namesList) return name ############### # Checkers ############## # Loop if edge_loop: try: edge_loop = [pm.PyNode(e) for e in edge_loop.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 up_vertex: try: up_vertex = pm.PyNode(up_vertex) except pm.MayaNodeError: pm.displayWarning("%s can not be found" % up_vertex) return else: pm.displayWarning("Please set the upper lip central vertex") return if low_vertex: try: low_vertex = pm.PyNode(low_vertex) except pm.MayaNodeError: pm.displayWarning("%s can not be found" % low_vertex) return else: pm.displayWarning("Please set the lower lip central vertex") return # skinnign data if do_skin: if not head_joint: pm.displayWarning("Please set the Head Jnt or unCheck Compute " "Topological Autoskin") return else: try: head_joint = pm.PyNode(head_joint) except pm.MayaNodeError: pm.displayWarning( "Head Joint: %s can not be found" % head_joint ) return if not jaw_joint: pm.displayWarning("Please set the Jaw Jnt or unCheck Compute " "Topological Autoskin") return else: try: jaw_joint = pm.PyNode(jaw_joint) except pm.MayaNodeError: pm.displayWarning("Jaw Joint: %s can not be found" % jaw_joint) 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(edge_loop[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(edge_loop) 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 = up_vertex lowPos = low_vertex # 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("upCtl_crv"), nbPoints=7, parent=lipsCrv_root) lowCrv_ctl = curve.createCurveFromCurve(lowCrv, setName("lowCtl_crv"), 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) ################## # 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 head_joint and isinstance(head_joint, (str, string_types)): try: j_parent = pm.PyNode(head_joint) except pm.MayaNodeError: j_parent = False elif head_joint and isinstance(head_joint, pm.PyNode): j_parent = head_joint 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 jaw_joint and isinstance(jaw_joint, (str, string_types)): try: j_parent = pm.PyNode(jaw_joint) except pm.MayaNodeError: pass elif jaw_joint and isinstance(jaw_joint, pm.PyNode): j_parent = jaw_joint 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) ################## # Controls ################## # Controls lists upControls = [] upVec = [] upNpo = [] lowControls = [] lowVec = [] lowNpo = [] # controls options axis_list = ["sx", "sy", "sz", "ro"] 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", "rx", "ry", "rz"] # 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 for i, cv in enumerate(cvs): pm.progressWindow(e=True, step=1, status='\nCreating control for%s' % cv) t = transform.getTransformFromPos(cv) # Get nearest joint for orientation of controls joints = upperJoints + lowerJoints nearest_joint = None nearest_distance = None for joint in joints: distance = vector.getDistance( transform.getTranslation(joint), cv ) if nearest_distance is None or distance < nearest_distance: nearest_distance = distance nearest_joint = joint if nearest_joint: t = transform.setMatrixPosition( transform.getTransform(nearest_joint), cv ) temp = primitive.addTransform( lips_root, setName("temp"), t ) temp.rx.set(0) t = transform.getTransform(temp) pm.delete(temp) 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, control_name), 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) name_split = control_name.split("_") if len(name_split) == 2 and name_split[-1] == "ghost": pass else: pm.sets(ctlSet, add=ctl) attribute.addAttribute(ctl, "isCtl", "bool", keyable=False) 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) # Get nearest joint for orientation of controls joints = upperJoints + lowerJoints nearest_joint = None nearest_distance = None for joint in joints: distance = vector.getDistance( transform.getTranslation(joint), cv ) if nearest_distance is None or distance < nearest_distance: nearest_distance = distance nearest_joint = joint if nearest_joint: t = transform.setMatrixPosition( transform.getTransform(nearest_joint), cv ) temp = primitive.addTransform( lips_root, setName("temp"), t ) temp.rx.set(0) t = transform.getTransform(temp) pm.delete(temp) 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, control_name), 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) name_split = control_name.split("_") if len(name_split) == 2 and control_name.split("_")[-1] == "ghost": pass else: pm.sets(ctlSet, add=ctl) attribute.addAttribute(ctl, "isCtl", "bool", keyable=False) 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, dropoffDistance=[0, 1000]) pm.wire(lowCrv, w=lowCrv_ctl, dropoffDistance=[0, 1000]) pm.wire(upRope, w=upCrv_ctl, dropoffDistance=[0, 1000]) pm.wire(lowRope, w=lowCrv_ctl, dropoffDistance=[0, 1000]) pm.wire(upRope_upv, w=upCrv_upv, dropoffDistance=[0, 1000]) pm.wire(lowRope_upv, w=lowCrv_upv, dropoffDistance=[0, 1000]) # 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.interpType.set(0) # noFlip 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.interpType.set(0) # noFlip 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.interpType.set(0) # noFlip 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) cns_node.interpType.set(0) # noFlip # 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.interpType.set(0) # noFlip 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.interpType.set(0) # noFlip 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.interpType.set(0) # noFlip 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) cns_node.interpType.set(0) # noFlip ########################################### # Connecting rig ########################################### if parent_node: try: if isinstance(parent_node, string_types): parent_node = pm.PyNode(parent_node) parent_node.addChild(lips_root) except pm.MayaNodeError: pm.displayWarning("The Lips rig can not be parent to: %s. Maybe " "this object doesn't exist." % parent_node) if head_joint and jaw_joint: try: if isinstance(head_joint, string_types): head_joint = pm.PyNode(head_joint) except pm.MayaNodeError: pm.displayWarning("Head Joint or Upper Lip Joint %s. Can not be " "fount in the scene" % head_joint) return try: if isinstance(jaw_joint, string_types): jaw_joint = pm.PyNode(jaw_joint) except pm.MayaNodeError: pm.displayWarning("Jaw Joint or Lower Lip Joint %s. Can not be " "fount in the scene" % jaw_joint) return ref_ctls = [head_joint, jaw_joint] if upper_lip_ctl and lower_lip_ctl: try: if isinstance(upper_lip_ctl, string_types): upper_lip_ctl = pm.PyNode(upper_lip_ctl) except pm.MayaNodeError: pm.displayWarning("Upper Lip Ctl %s. Can not be " "fount in the scene" % upper_lip_ctl) return try: if isinstance(lower_lip_ctl, string_types): lower_lip_ctl = pm.PyNode(lower_lip_ctl) except pm.MayaNodeError: pm.displayWarning("Lower Lip Ctl %s. Can not be " "fount in the scene" % lower_lip_ctl) return ref_ctls = [upper_lip_ctl, lower_lip_ctl] # in order to avoid flips lets create a reference transform # also to avoid flips, set any multi target parentConstraint to noFlip ref_cns_list = [] print (ref_ctls) for cns_ref in ref_ctls: t = transform.getTransformFromPos( cns_ref.getTranslation(space='world')) ref = pm.createNode("transform", n=cns_ref.name() + "_cns", p=cns_ref, ss=True) ref.setMatrix(t, worldSpace=True) ref_cns_list.append(ref) # right corner connection cns_node = pm.parentConstraint(ref_cns_list[0], ref_cns_list[1], upControls[0].getParent(), mo=True) cns_node.interpType.set(0) # noFlip # left corner connection cns_node = pm.parentConstraint(ref_cns_list[0], ref_cns_list[1], upControls[-1].getParent(), mo=True) cns_node.interpType.set(0) # noFlip # up control connection cns_node = pm.parentConstraint(ref_cns_list[0], upControls[3].getParent(), mo=True) # low control connection cns_node = pm.parentConstraint(ref_cns_list[1], lowControls[2].getParent(), mo=True) ########################################### # Auto Skinning ########################################### if do_skin: # eyelid vertex rows totalLoops = rigid_loops + falloff_loops 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(rigid_loops): for rr in range(2): skinPercList.append(1.0) increment = 1.0 / float(falloff_loops) # we invert to smooth out from 100 to 0 inv = 1.0 - increment for r in range(falloff_loops): 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 head_joint: try: head_joint = pm.PyNode(head_joint) except pm.MayaNodeError: pm.displayWarning( "Auto skin aborted can not find %s " % head_joint) 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(head_joint, 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 addOperators(self): """Create operators and set the relations for the component rig Apply operators, constraints, expressions to the hierarchy. In order to keep the code clean and easier to debug, we shouldn't create any new object in this method. """ # Auto bend ---------------------------- if self.settings["autoBend"]: mul_node = node.createMulNode( [self.autoBendChain[0].ry, self.autoBendChain[0].rz], [self.sideBend_att, self.frontBend_att]) mul_node.outputX >> self.ik1autoRot_lvl.rz mul_node.outputY >> self.ik1autoRot_lvl.rx self.ikHandleAutoBend = primitive.addIkHandle( self.autoBend_ctl, self.getName("ikHandleAutoBend"), self.autoBendChain, "ikSCsolver") # Tangent position --------------------------------- # common part d = vector.getDistance(self.guide.apos[1], self.guide.apos[-2]) dist_node = node.createDistNode(self.ik0_ctl, self.ik1_ctl) rootWorld_node = node.createDecomposeMatrixNode( self.root.attr("worldMatrix")) div_node = node.createDivNode(dist_node + ".distance", rootWorld_node + ".outputScaleX") div_node = node.createDivNode(div_node + ".outputX", d) # tan0 mul_node = node.createMulNode(self.tan0_att, self.tan0_npo.getAttr("ty")) res_node = node.createMulNode(mul_node + ".outputX", div_node + ".outputX") pm.connectAttr(res_node + ".outputX", self.tan0_npo.attr("ty")) # tan1 mul_node = node.createMulNode(self.tan1_att, self.tan1_npo.getAttr("ty")) res_node = node.createMulNode(mul_node + ".outputX", div_node + ".outputX") pm.connectAttr(res_node + ".outputX", self.tan1_npo.attr("ty")) # Tangent Mid -------------------------------------- if self.settings["centralTangent"]: tanIntMat = applyop.gear_intmatrix_op( self.tan0_npo.attr("worldMatrix"), self.tan1_npo.attr("worldMatrix"), .5) applyop.gear_mulmatrix_op( tanIntMat.attr("output"), self.tan_npo.attr("parentInverseMatrix[0]"), self.tan_npo) pm.connectAttr(self.tan_ctl.attr("translate"), self.tan0_off.attr("translate")) pm.connectAttr(self.tan_ctl.attr("translate"), self.tan1_off.attr("translate")) # Curves ------------------------------------------- op = applyop.gear_curveslide2_op(self.slv_crv, self.mst_crv, 0, 1.5, .5, .5) pm.connectAttr(self.position_att, op + ".position") pm.connectAttr(self.maxstretch_att, op + ".maxstretch") pm.connectAttr(self.maxsquash_att, op + ".maxsquash") pm.connectAttr(self.softness_att, op + ".softness") # Volume driver ------------------------------------ crv_node = node.createCurveInfoNode(self.slv_crv) # Division ----------------------------------------- tangents = [None, "tan0", "tan1"] for i in range(self.settings["division"]): # References u = i / (self.settings["division"] - 1.0) # check the indx to calculate mid point based on number of division # we want to use the same spine for mannequin and metahuman spine if self.settings["division"] == 4 and i in [1, 2]: u_param = curve.getCurveParamAtPosition( self.slv_crv, self.guide.pos[tangents[i]])[0] cnsType = True elif self.settings["division"] == 3 and i in [1]: u_param = curve.getCurveParamAtPosition( self.slv_crv, self.guide.pos[tangents[i]])[0] cnsType = True else: u_param = u cnsType = False cns = applyop.pathCns(self.div_cns[i], self.slv_crv, cnsType, u_param, True) cns.setAttr("frontAxis", 1) # front axis is 'Y' cns.setAttr("upAxis", 0) # front axis is 'X' # Roll intMatrix = applyop.gear_intmatrix_op( self.ik0_ctl + ".worldMatrix", self.ik1_ctl + ".worldMatrix", u) dm_node = node.createDecomposeMatrixNode(intMatrix + ".output") pm.connectAttr(dm_node + ".outputRotate", self.twister[i].attr("rotate")) pm.parentConstraint(self.twister[i], self.ref_twist[i], maintainOffset=True) pm.connectAttr(self.ref_twist[i] + ".translate", cns + ".worldUpVector") # compensate scale reference div_node = node.createDivNode([1, 1, 1], [ rootWorld_node + ".outputScaleX", rootWorld_node + ".outputScaleY", rootWorld_node + ".outputScaleZ" ]) # Squash n Stretch op = applyop.gear_squashstretch2_op(self.scl_transforms[i], self.root, pm.arclen(self.slv_crv), "y", div_node + ".output") pm.connectAttr(self.volume_att, op + ".blend") pm.connectAttr(crv_node + ".arcLength", op + ".driver") pm.connectAttr(self.st_att[i], op + ".stretch") pm.connectAttr(self.sq_att[i], op + ".squash") # Controlers if i == 0: mulmat_node = applyop.gear_mulmatrix_op( self.div_cns[i].attr("worldMatrix"), self.root.attr("worldInverseMatrix")) dm_node = node.createDecomposeMatrixNode(mulmat_node + ".output") pm.connectAttr(dm_node + ".outputTranslate", self.fk_npo[i].attr("t")) else: mulmat_node = applyop.gear_mulmatrix_op( self.div_cns[i].attr("worldMatrix"), self.div_cns[i - 1].attr("worldInverseMatrix")) dm_node = node.createDecomposeMatrixNode(mulmat_node + ".output") mul_node = node.createMulNode(div_node + ".output", dm_node + ".outputTranslate") pm.connectAttr(mul_node + ".output", self.fk_npo[i].attr("t")) pm.connectAttr(dm_node + ".outputRotate", self.fk_npo[i].attr("r")) # Orientation Lock if i == 0: dm_node = node.createDecomposeMatrixNode(self.ik0_ctl + ".worldMatrix") blend_node = node.createBlendNode( [dm_node + ".outputRotate%s" % s for s in "XYZ"], [cns + ".rotate%s" % s for s in "XYZ"], self.lock_ori0_att) self.div_cns[i].attr("rotate").disconnect() pm.connectAttr(blend_node + ".output", self.div_cns[i] + ".rotate") elif i == self.settings["division"] - 1: dm_node = node.createDecomposeMatrixNode(self.ik1_ctl + ".worldMatrix") blend_node = node.createBlendNode( [dm_node + ".outputRotate%s" % s for s in "XYZ"], [cns + ".rotate%s" % s for s in "XYZ"], self.lock_ori1_att) self.div_cns[i].attr("rotate").disconnect() pm.connectAttr(blend_node + ".output", self.div_cns[i] + ".rotate") # change parent after operators applied pm.parent(self.scl_transforms[-1], self.fk_ctl[-1]) # Connections (Hooks) ------------------------------ pm.parentConstraint(self.pelvis_lvl, self.cnx0) pm.scaleConstraint(self.pelvis_lvl, self.cnx0) transform.matchWorldTransform(self.scl_transforms[-1], self.cnx1) t = transform.setMatrixPosition(transform.getTransform(self.cnx1), self.guide.apos[-1]) self.cnx1.setMatrix(t, worldSpace=True) pm.parentConstraint(self.scl_transforms[-1], self.cnx1, mo=True) pm.scaleConstraint(self.scl_transforms[-1], self.cnx1)