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. """ applyop.aimCns(self.ref_base, self.tip_ctl, axis="yx", wupType=2, wupVector=[1, 0, 0], wupObject=self.ctl, maintainOffset=False) applyop.aimCns(self.ref_tip, self.ctl, axis="-yx", wupType=2, wupVector=[1, 0, 0], wupObject=self.tip_ctl, maintainOffset=False) bIncrement = 1.0 / (self.settings["div"] - 1) blend = 0 for i, div_cns in enumerate(self.div_cns): intMatrix = applyop.gear_intmatrix_op( self.ref_base.attr("worldMatrix"), self.ref_tip.attr("worldMatrix"), blend) applyop.gear_mulmatrix_op(intMatrix.attr("output"), div_cns.attr("parentInverseMatrix[0]"), div_cns) blend = blend + bIncrement
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. """ for e, _ in enumerate(self.ik_ctl): out_glob = self.ik_global_out[e] out_ref = self.ik_global_ref[e] applyop.gear_mulmatrix_op( out_ref.attr("worldMatrix"), out_glob.attr("parentInverseMatrix[0]"), out_glob) if self.settings["isGlobalMaster"]: pass else: self.addOperatorsNotGlobalMaster() pm.parentConstraint(self.ik_ctl[0], self.aim_npo, mo=True, skipRotate=("x", "y", "z")) if False or self.settings["isUpvectorAimToTip"]: aimv = (0., 1., 0.) upv = (0., 1., 0.) _bx = abs(self.guide.blades["blade"].y[0]) _by = abs(self.guide.blades["blade"].y[1]) _bz = abs(self.guide.blades["blade"].y[2]) _bmax = max(_bx, _by, _bz) if _bmax == _bx: aimv = (1., 0., 0.) elif _bmax == _by: aimv = (0., 1., 0.) elif _bmax == _bz: aimv = (0., 0., 1.) aim = pm.aimConstraint(self.ik_ctl[-1], self.aim_npo, mo=True, aimVector=aimv, upVector=upv, worldUpType="objectrotation", worldUpObject=self.root, worldUpVector=(-1.0, 0., 0.) ) # pm.setAttr(aim + ".upVectorX", 0) # pm.setAttr(aim + ".upVectorY", 1) # pm.setAttr(aim + ".upVectorZ", 0) # TODO: optional for sine curve deformer self.addOperatorSineCurveExprespy() # TODO: Add option for length controller to be added or not self.addOperatorLengthExpression()
def addOperators(self): """Create operators and set the relations for the component rig Apply operators/Solvers, 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. """ applyop.aimCns(self.ref_base, self.squash_ctl, axis="yx", wupType=2, wupVector=[1, 0, 0], wupObject=self.ctl, maintainOffset=False) applyop.aimCns(self.ref_squash, self.ctl, axis="-yx", wupType=2, wupVector=[1, 0, 0], wupObject=self.squash_ctl, maintainOffset=False) bIncrement = 1.0 blend = 0 for i, div_cns in enumerate(self.div_cns): intMatrix = applyop.gear_intmatrix_op( self.ref_base.attr("worldMatrix"), self.ref_squash.attr("worldMatrix"), blend) applyop.gear_mulmatrix_op(intMatrix.attr("output"), div_cns.attr("parentInverseMatrix[0]"), div_cns) blend = blend + bIncrement d = vector.getDistance(self.guide.apos[0], self.guide.apos[1]) dist_node = node.createDistNode(self.squash_ctl, self.ctl) rootWorld_node = node.createDecomposeMatrixNode( self.ctl.attr("worldMatrix")) div_node = node.createDivNode(dist_node + ".distance", rootWorld_node + ".outputScaleY") div_node = node.createDivNode(div_node + ".outputX", d) rev_node = node.createReverseNode(div_node + ".outputX") add_node = pm.createNode("plusMinusAverage") add_node.input1D[0].set(1.0) rev_node.outputX >> add_node.input1D[1] div_node.outputX >> self.ref_base.scaleY add_node.output1D >> self.ref_base.scaleX add_node.output1D >> self.ref_base.scaleZ
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. """ # Chain of deformers ------------------------------- for i, loc in enumerate(self.loc): pm.parentConstraint(self.fk_ctl[i], loc, maintainOffset=False) # spring operators # settings aim contraints for i, tranCns in enumerate(self.spring_aim): if self.negate: aimAxis = "-xy" else: aimAxis = "xy" applyop.aimCns(tranCns, self.spring_target[i], aimAxis, 2, [0, 1, 0], self.fk_npo[i], False) ori_cns = applyop.oriCns(tranCns, self.spring_cns[i]) springOP = applyop.gear_spring_op(self.spring_target[i]) blend_node = pm.createNode("pairBlend") pm.connectAttr(ori_cns.constraintRotate, blend_node.inRotate2) pm.connectAttr(self.aSpring_intensity, blend_node.weight) pm.disconnectAttr(ori_cns.constraintRotate, self.spring_cns[i].rotate) pm.connectAttr(blend_node.outRotateX, self.spring_cns[i].rotateX) pm.connectAttr(blend_node.outRotateY, self.spring_cns[i].rotateY) pm.connectAttr(blend_node.outRotateZ, self.spring_cns[i].rotateZ) pm.connectAttr(self.aSpring_intensity, springOP + ".intensity") pm.connectAttr(self.aDamping[i], springOP + ".damping") pm.connectAttr(self.aStiffness[i], springOP + ".stiffness") # connect out ctl = self.fk_ctl[i] out_loc = self.fk_local_out[i] applyop.gear_mulmatrix_op(ctl.attr("worldMatrix"), out_loc.attr("parentInverseMatrix[0]"), out_loc) out_glob = self.fk_global_out[i] out_ref = self.fk_global_ref[i] applyop.gear_mulmatrix_op(out_ref.attr("worldMatrix"), out_glob.attr("parentInverseMatrix[0]"), out_glob)
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. """ # CONNECT STACK # master components mstr_global = self.settings["masterChainGlobal"] mstr_local = self.settings["masterChainLocal"] if mstr_global: mstr_global = self.rig.components[mstr_global] if mstr_local: mstr_local = self.rig.components[mstr_local] # connect the fk chain ctls for e, ctl in enumerate(self.fk_ctl): # connect out out_loc = self.fk_local_out[e] applyop.gear_mulmatrix_op(ctl.attr("worldMatrix"), out_loc.attr("parentInverseMatrix[0]"), out_loc) out_glob = self.fk_global_out[e] out_ref = self.fk_global_ref[e] applyop.gear_mulmatrix_op(out_ref.attr("worldMatrix"), out_glob.attr("parentInverseMatrix[0]"), out_glob) # connect in global if mstr_global: self.connect_master(mstr_global.fk_global_out, self.fk_global_in, e, self.settings["cnxOffset"], self.blend_world_att) # connect in local if mstr_local: self.connect_master(mstr_local.fk_local_out, self.fk_local_in, e, self.settings["cnxOffset"], self.blend_local_att) for shp in ctl.getShapes(): pm.connectAttr(self.fkVis_att, shp.attr("visibility")) for ctl in self.tweak_ctl: for shp in ctl.getShapes(): pm.connectAttr(self.ikVis_att, shp.attr("visibility"))
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. """ if self.negate: o_node = applyop.aimCns(self.mtx, self.end, axis="-xy", wupType=4, wupVector=[0, 1, 0], wupObject=self.mtx, maintainOffset=False) else: o_node = applyop.aimCns(self.mtx, self.end, axis="xy", wupType=4, wupVector=[0, 1, 0], wupObject=self.mtx, maintainOffset=False) # position constrint loc to ref o_node = applyop.gear_mulmatrix_op( self.end.attr("worldMatrix"), self.loc.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") pb_node = pm.createNode("pairBlend") # move back a little bit to avoid overlapping with limb jts pm.setAttr(pb_node + ".weight", 0.98) pm.connectAttr(dm_node + ".outputTranslate", pb_node + ".inTranslate2") pm.connectAttr(pb_node + ".outTranslate", self.loc.attr("translate"))
def addOperatorsIkRoll(self): for i in range(0, self.settings["ikNb"]): roll_ratio = (i + 0.0001) / (len(self.ik_ctl) - 1.) mul1 = pm.createNode("multDoubleLinear") pm.connectAttr(self.decomp_tip_ik_rot.attr("outRoll"), mul1.attr("input1")) pm.setAttr(mul1.attr("input2"), roll_ratio) compose_rot = pm.createNode("composeRotate") pm.setAttr(compose_rot.attr("axisOrientX"), 90.0) pm.setAttr(compose_rot.attr("axisOrientZ"), 90.0) pm.connectAttr(mul1.attr("output"), compose_rot.attr("roll")) pm.connectAttr(compose_rot.attr("outRotate"), self.ik_roll_npo[i].attr("rotate")) rot = pm.createNode("decomposeRotate") pm.setAttr(rot.attr("axisOrientX"), 90.0) pm.setAttr(rot.attr("axisOrientZ"), 90.0) if i != (len(self.ik_ctl) - 1): mul2 = applyop.gear_mulmatrix_op(self.ik_ctl[i].attr("matrix"), self.ik_roll_npo[i].attr("matrix")) dm_node = node.createDecomposeMatrixNode(mul2 + ".output") pm.connectAttr(dm_node.attr("outputRotate"), rot.attr("rotate")) else: pm.connectAttr(self.ik_roll_npo[i].attr("rotate"), rot.attr("rotate")) self.ik_decompose_rot.append(rot)
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. """ for e, _ in enumerate(self.ik_ctl): out_glob = self.ik_global_out[e] out_ref = self.ik_global_ref[e] applyop.gear_mulmatrix_op(out_ref.attr("worldMatrix"), out_glob.attr("parentInverseMatrix[0]"), out_glob) self.addOperatorsNotGlobalMaster()
def createInterpolateTransform(objects=None, blend=.5, *args): """ Create space locator and apply gear_intmatrix_op, to interpolate the his pose between 2 selected objects. Args: objects (None or list of 2 dagNode, optional): The 2 dagNode to interpolate the transform. blend (float, optional): The interpolation blend factor. *args: Maya's dummy Returns: pyNode: The new transformation witht the interpolate matrix o_node applied. """ if objects or len(pm.selected()) >= 2: if objects: refA = objects[0] refB = objects[1] else: refA = pm.selected()[0] refB = pm.selected()[1] intMatrix = applyop.gear_intmatrix_op(refA.attr("worldMatrix"), refB.attr("worldMatrix"), blend) intTrans = primitive.addTransform( refA, refA.name() + "_INTER_" + refB.name(), datatypes.Matrix()) applyop.gear_mulmatrix_op(intMatrix.attr("output"), intTrans.attr("parentInverseMatrix[0]"), intTrans) pm.displayInfo("Interpolated Transform: " + intTrans.name() + " created") else: pm.displayWarning("Please select 2 objects. ") return return intTrans
def spaceJump(ref=None, space=None, *args): """Space Jump gimmick This function create a local reference space from another space in the hierarchy Args: ref (None, optional): Transform reference space (None, optional): Space reference *args: Maya dummy Returns: pyNode: Transform """ if not ref and not space: if len(pm.selected()) == 2: ref = pm.selected()[0] space = pm.selected()[1] else: pm.displayWarning("Please select 2 objects. Reference Space " "and Jump Space") return refLocal = primitive.addTransform(ref, ref.name() + "_SPACE_" + space.name(), space.getMatrix(worldSpace=True)) spaceLocal = primitive.addTransform(space, ref.name() + "_JUMP_" + space.name(), space.getMatrix(worldSpace=True)) applyop.gear_mulmatrix_op(refLocal.attr("worldMatrix"), spaceLocal.attr("parentInverseMatrix[0]"), spaceLocal) pm.displayInfo("Jump Space for local space: " + space.name() + "created") return spaceLocal
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. """ # Visibilities ------------------------------------- if self.isFkIk: # fk fkvis_node = node.createReverseNode(self.blend_att) for fk_ctl in self.fk_ctl: for shp in fk_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) # ik for shp in self.upv_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ikcns_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ik_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) # FK Chain ----------------------------------------- if self.isFk: for off, ref in zip(self.fk_off[1:], self.fk_ref): applyop.gear_mulmatrix_op(ref.worldMatrix, off.parentInverseMatrix, off, "rt") # IK Chain ----------------------------------------- if self.isIk: self.ikh = primitive.addIkHandle(self.root, self.getName("ikh"), self.chain) self.ikh.attr("visibility").set(False) # Constraint and up vector pm.pointConstraint(self.ik_ctl, self.ikh, maintainOffset=False) pm.poleVectorConstraint(self.upv_ctl, self.ikh) # TwistTest o_list = [round(elem, 4) for elem in transform.getTranslation(self.chain[1])] \ != [round(elem, 4) for elem in self.guide.apos[1]] if o_list: add_nodeTwist = node.createAddNode(180.0, self.roll_att) pm.connectAttr(add_nodeTwist + ".output", self.ikh.attr("twist")) else: pm.connectAttr(self.roll_att, self.ikh.attr("twist")) # Chain of deformers ------------------------------- if self.settings["mode"] == 0: # fk only # Loop until the last one and connect aim constraints from index+1 for i, loc in enumerate(self.loc[0:-1]): pm.pointConstraint(self.fk_ctl[i], loc, maintainOffset=False) pm.connectAttr(self.fk_ctl[i] + ".scale", loc + ".scale") pm.aimConstraint( self.fk_ctl[i + 1], loc, maintainOffset=False, aimVector=(1, 0, 0), upVector=(0, 1, 0), worldUpType='none', ) oRoot = rigbits.addNPO(loc)[0] pm.parentConstraint(self.fk_ctl[i], oRoot, mo=True) attribute.lockAttribute(oRoot) # Then connect the last in the chain as a parent constraint pm.parentConstraint(self.fk_ctl[-1], self.loc[-1], maintainOffset=False) pm.connectAttr(self.fk_ctl[-1] + ".scale", self.loc[-1] + ".scale")
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. """ # setup out channels. This channels are pass through for stack node.createPlusMinusAverage1D( [self.mid_wide_att, self.mid_wide_in_att, -1.0], 1, self.mid_wide_out_att) node.createPlusMinusAverage1D( [self.mid_depth_att, self.mid_depth_in_att, -1.0], 1, self.mid_depth_out_att) node.createPlusMinusAverage1D( [self.tip_wide_att, self.tip_wide_in_att, -1.0], 1, self.tip_wide_out_att) node.createPlusMinusAverage1D( [self.tip_depth_att, self.tip_depth_in_att, -1.0], 1, self.tip_depth_out_att) node.createPlusMinusAverage1D( [self.mid_twist_att, self.mid_twist_in_att], 1, self.mid_twist_out_att) node.createPlusMinusAverage1D( [self.tip_twist_att, self.tip_twist_in_att], 1, self.tip_twist_out_att) if not self.settings["simpleFK"]: dm_node_scl = node.createDecomposeMatrixNode(self.root.worldMatrix) if self.settings["keepLength"]: arclen_node = pm.arclen(self.mst_crv, ch=True) alAttr = pm.getAttr(arclen_node + ".arcLength") ration_node = node.createMulNode(self.length_ratio_att, alAttr) pm.addAttr(self.mst_crv, ln="length_ratio", k=True, w=True) node.createDivNode(arclen_node.arcLength, ration_node.outputX, self.mst_crv.length_ratio) div_node_scl = node.createDivNode(self.mst_crv.length_ratio, dm_node_scl.outputScaleX) step = 1.000 / (self.def_number - 1) step_mid = 1.000 / ((self.def_number - 1) / 2.0) u = 0.000 u_mid = 0.000 pass_mid = False for i in range(self.def_number): cnsUpv = applyop.pathCns(self.upv_cns[i], self.upv_crv, cnsType=False, u=u, tangent=False) cns = applyop.pathCns(self.div_cns[i], self.mst_crv, False, u, True) # Connecting the scale for scaling compensation # for axis, AX in zip("xyz", "XYZ"): for axis, AX in zip("x", "X"): pm.connectAttr( dm_node_scl.attr("outputScale{}".format(AX)), self.div_cns[i].attr("s{}".format(axis))) if self.settings["keepLength"]: div_node2 = node.createDivNode(u, div_node_scl.outputX) cond_node = node.createConditionNode( div_node2.input1X, div_node2.outputX, 4, div_node2.input1X, div_node2.outputX) pm.connectAttr(cond_node + ".outColorR", cnsUpv + ".uValue") pm.connectAttr(cond_node + ".outColorR", cns + ".uValue") cns.setAttr("worldUpType", 1) cns.setAttr("frontAxis", 0) cns.setAttr("upAxis", 1) pm.connectAttr(self.upv_cns[i].attr("worldMatrix[0]"), cns.attr("worldUpMatrix")) # Connect scale Wide and Depth # wide and Depth mid_mul_node = node.createMulNode( [self.mid_wide_att, self.mid_depth_att], [self.mid_wide_in_att, self.mid_depth_in_att]) mid_mul_node2 = node.createMulNode( [mid_mul_node.outputX, mid_mul_node.outputY], [u_mid, u_mid]) mid_mul_node3 = node.createMulNode( [mid_mul_node2.outputX, mid_mul_node2.outputY], [ dm_node_scl.attr("outputScaleX"), dm_node_scl.attr("outputScaleY") ]) tip_mul_node = node.createMulNode( [self.tip_wide_att, self.tip_depth_att], [self.tip_wide_in_att, self.tip_depth_in_att]) tip_mul_node2 = node.createMulNode( [tip_mul_node.outputX, tip_mul_node.outputY], [u, u]) node.createPlusMinusAverage1D([ mid_mul_node3.outputX, 1.0 - u_mid, tip_mul_node2.outputX, 1.0 - u, -1.0 ], 1, self.div_cns[i].attr("sy")) node.createPlusMinusAverage1D([ mid_mul_node3.outputY, 1.0 - u_mid, tip_mul_node2.outputY, 1.0 - u, -1.0 ], 1, self.div_cns[i].attr("sz")) # Connect Twist "cns.frontTwist" twist_mul_node = node.createMulNode( [self.mid_twist_att, self.tip_twist_att], [u_mid, u]) twist_mul_node2 = node.createMulNode( [self.mid_twist_in_att, self.tip_twist_in_att], [u_mid, u]) node.createPlusMinusAverage1D([ twist_mul_node.outputX, twist_mul_node.outputY, twist_mul_node2.outputX, twist_mul_node2.outputY, ], 1, cns.frontTwist) # u_mid calc if u_mid >= 1.0 or pass_mid: u_mid -= step_mid pass_mid = True else: u_mid += step_mid if u_mid > 1.0: u_mid = 1.0 # ensure the tip is never affected byt the mid if i == (self.def_number - 1): u_mid = 0.0 u += step if self.settings["keepLength"]: # add the safty distance offset self.tweakTip_npo.attr("tx").set(self.off_dist) # connect vis line ref for shp in self.line_ref.getShapes(): pm.connectAttr(self.ikVis_att, shp.attr("visibility")) # CONNECT STACK # master components mstr_global = self.settings["masterChainGlobal"] mstr_local = self.settings["masterChainLocal"] if mstr_global: mstr_global = self.rig.components[mstr_global] if mstr_local: mstr_local = self.rig.components[mstr_local] # connect twist and scale if mstr_global and mstr_local: node.createPlusMinusAverage1D([ mstr_global.root.mid_twist_out, mstr_local.root.mid_twist_out ], 1, self.mid_twist_in_att) node.createPlusMinusAverage1D([ mstr_global.root.tip_twist_out, mstr_local.root.tip_twist_out ], 1, self.tip_twist_in_att) node.createPlusMinusAverage1D([ mstr_global.root.mid_wide_out, mstr_local.root.mid_wide_out, -1 ], 1, self.mid_wide_in_att) node.createPlusMinusAverage1D([ mstr_global.root.tip_wide_out, mstr_local.root.tip_wide_out, -1 ], 1, self.tip_wide_in_att) node.createPlusMinusAverage1D([ mstr_global.root.mid_depth_out, mstr_local.root.mid_depth_out, -1 ], 1, self.mid_depth_in_att) node.createPlusMinusAverage1D([ mstr_global.root.tip_depth_out, mstr_local.root.tip_depth_out, -1 ], 1, self.tip_depth_in_att) elif mstr_local or mstr_global: for master_chain in [mstr_local, mstr_global]: if master_chain: pm.connectAttr(master_chain.root.mid_twist_out, self.mid_twist_in_att) pm.connectAttr(master_chain.root.tip_twist_out, self.tip_twist_in_att) pm.connectAttr(master_chain.root.mid_wide_out, self.mid_wide_in_att) pm.connectAttr(master_chain.root.tip_wide_out, self.tip_wide_in_att) pm.connectAttr(master_chain.root.mid_depth_out, self.mid_depth_in_att) pm.connectAttr(master_chain.root.tip_depth_out, self.tip_depth_in_att) # connect the fk chain ctls for e, ctl in enumerate(self.fk_ctl): # connect out out_loc = self.fk_local_out[e] applyop.gear_mulmatrix_op(ctl.attr("worldMatrix"), out_loc.attr("parentInverseMatrix[0]"), out_loc) out_glob = self.fk_global_out[e] out_ref = self.fk_global_ref[e] applyop.gear_mulmatrix_op(out_ref.attr("worldMatrix"), out_glob.attr("parentInverseMatrix[0]"), out_glob) # connect in global if mstr_global: self.connect_master(mstr_global.fk_global_out, self.fk_global_in, e, self.settings["cnxOffset"]) # connect in local if mstr_local: self.connect_master(mstr_local.fk_local_out, self.fk_local_in, e, self.settings["cnxOffset"]) for shp in ctl.getShapes(): pm.connectAttr(self.fkVis_att, shp.attr("visibility")) for ctl in self.tweak_ctl: for shp in ctl.getShapes(): pm.connectAttr(self.ikVis_att, shp.attr("visibility")) if self.settings["extraTweak"]: for tweak_ctl in self.extratweak_ctl: for shp in tweak_ctl.getShapes(): pm.connectAttr(self.tweakVis_att, shp.attr("visibility"))
def addFkOperator(self, i, rootWorld_node, crv_node): if i == 0 and self.settings["isSplitHip"]: s = self.fk_hip_ctl d = self.fk_local_npo[0], # maintainOffset, skipRotate, skipTranslate _ = pm.parentConstraint(s, d, mo=True, sr=("x", "y", "z"), st=()) s = self.ik_global_out[0] d = self.hip_fk_local_in, # maintainOffset, skipRotate, skipTranslate pm.parentConstraint(s, d, mo=True) # break FK hierarchical orient if i not in [len(self.guide.apos), 0]: s = self.fk_ctl[i - 1] s2 = self.fk_npo[i] d = self.fk_local_npo[i] mulmat_node = applyop.gear_mulmatrix_op(s2.attr("matrix"), s.attr("matrix")) mulmat_node2 = applyop.gear_mulmatrix_op(mulmat_node.attr("output"), s2.attr("inverseMatrix")) dm_node = node.createDecomposeMatrixNode(mulmat_node2 + ".output") pm.connectAttr(dm_node + ".outputTranslate", d.attr("t")) check_list = (pm.Attribute, unicode, str) # noqa cond = pm.createNode("condition") pm.setAttr(cond + ".operation", 4) # greater attribute.connectSet(self.fk_collapsed_att, cond + ".secondTerm", check_list) attribute.connectSet(dm_node + ".outputRotate", cond + ".colorIfTrue", check_list) pm.setAttr(cond + ".colorIfFalseR", 0.) pm.setAttr(cond + ".colorIfFalseG", 0.) pm.setAttr(cond + ".colorIfFalseB", 0.) pm.connectAttr(cond + ".outColor", d.attr("r")) # References if i == 0: # we add extra 10% to the first position u = (1.0 / (len(self.guide.apos) - 1.0)) / 1000 else: u = getCurveUAtPoint(self.slv_crv, self.guide.apos[i]) tmp_div_npo_transform = getTransform(self.div_cns_npo[i]) # to fix mismatch before/after later cns = applyop.pathCns(self.div_cns[i], self.slv_crv, False, u, True) cns.setAttr("frontAxis", 1) # front axis is 'Y' cns.setAttr("upAxis", 0) # front axis is 'X' # Roll # choose ik_ctls for _i, uv in enumerate(self.ik_uv_param): if u < uv: ik_a = self.ik_ctl[_i - 1] ik_b = self.ik_ctl[_i] if self.settings["isSplitHip"] and i == 0: u = (i + 1) / (len(self.guide.apos) - 1.0) ratio = u / uv * .5 else: ratio = u / uv break else: ik_a = self.ik_ctl[-2] ik_b = self.ik_ctl[-1] ratio = 1. intMatrix = applyop.gear_intmatrix_op( ik_a + ".worldMatrix", ik_b + ".worldMatrix", ratio) 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") self.div_cns_npo[i].setMatrix(tmp_div_npo_transform, worldSpace=True) # 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 tmp_local_npo_transform = getTransform(self.fk_local_npo[i]) # to fix mismatch before/after later if i == 0: mulmat_node = applyop.gear_mulmatrix_op( self.div_cns_npo[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_npo[i].attr("worldMatrix"), self.div_cns_npo[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")) self.addOperatorsOrientationLock(i, cns) self.fk_local_npo[i].setMatrix(tmp_local_npo_transform, worldSpace=True) # References if i < (len(self.fk_ctl) - 1): aim = pm.aimConstraint(self.div_cns_npo[i + 1], self.div_cns_npo[i], maintainOffset=False) pm.setAttr(aim + ".aimVectorX", 0) pm.setAttr(aim + ".aimVectorY", 1) pm.setAttr(aim + ".aimVectorZ", 0) pm.setAttr(aim + ".upVectorX", 0) pm.setAttr(aim + ".upVectorY", 1) pm.setAttr(aim + ".upVectorZ", 0)
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. """ # 1 bone chain Upv ref ============================== self.ikHandleUpvRef = primitive.addIkHandle( self.root, self.getName("ikHandleLegChainUpvRef"), self.legChainUpvRef, "ikSCsolver") pm.pointConstraint(self.ik_ctl, self.ikHandleUpvRef) pm.parentConstraint(self.legChainUpvRef[0], self.ik_ctl, self.upv_cns, mo=True) # Visibilities ------------------------------------- # shape.dispGeometry # fk fkvis_node = node.createReverseNode(self.blend_att) for shp in self.fk0_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) for shp in self.fk1_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) for shp in self.fk2_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) # ik for shp in self.upv_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ikcns_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ik_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.line_ref.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) # IK Solver ----------------------------------------- out = [self.bone0, self.bone1, self.ctrn_loc, self.eff_loc] o_node = applyop.gear_ikfk2bone_op(out, self.root_ctl, self.ik_ref, self.upv_ctl, self.fk_ctl[0], self.fk_ctl[1], self.fk_ref, self.length0, self.length1, self.negate) pm.connectAttr(self.blend_att, o_node + ".blend") if self.negate: mulVal = -1 else: mulVal = 1 node.createMulNode(self.roll_att, mulVal, o_node + ".roll") # pm.connectAttr(self.roll_att, o_node+".roll") pm.connectAttr(self.scale_att, o_node + ".scaleA") pm.connectAttr(self.scale_att, o_node + ".scaleB") pm.connectAttr(self.maxstretch_att, o_node + ".maxstretch") pm.connectAttr(self.slide_att, o_node + ".slide") pm.connectAttr(self.softness_att, o_node + ".softness") pm.connectAttr(self.reverse_att, o_node + ".reverse") # Twist references --------------------------------- o_node = applyop.gear_mulmatrix_op( self.eff_loc.attr("worldMatrix"), self.root.attr("worldInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputTranslate", self.tws2_npo.attr("translate")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputRotate", self.tws2_npo.attr("rotate")) # spline IK for twist jnts self.ikhUpLegTwist, self.uplegTwistCrv = applyop.splineIK( self.getName("uplegTwist"), self.uplegTwistChain, parent=self.root, cParent=self.bone0) self.ikhLowLegTwist, self.lowlegTwistCrv = applyop.splineIK( self.getName("lowlegTwist"), self.lowlegTwistChain, parent=self.root, cParent=self.bone1) # references self.ikhUpLegRef, self.tmpCrv = applyop.splineIK( self.getName("uplegRollRef"), self.uplegRollRef, parent=self.root, cParent=self.bone0) self.ikhLowLegRef, self.tmpCrv = applyop.splineIK( self.getName("lowlegRollRef"), self.lowlegRollRef, parent=self.root, cParent=self.eff_loc) self.ikhAuxTwist, self.tmpCrv = applyop.splineIK( self.getName("auxTwist"), self.auxTwistChain, parent=self.root, cParent=self.eff_loc) # setting connexions for ikhUpLegTwist self.ikhUpLegTwist.attr("dTwistControlEnable").set(True) self.ikhUpLegTwist.attr("dWorldUpType").set(4) self.ikhUpLegTwist.attr("dWorldUpAxis").set(3) self.ikhUpLegTwist.attr("dWorldUpVectorZ").set(1.0) self.ikhUpLegTwist.attr("dWorldUpVectorY").set(0.0) self.ikhUpLegTwist.attr("dWorldUpVectorEndZ").set(1.0) self.ikhUpLegTwist.attr("dWorldUpVectorEndY").set(0.0) pm.connectAttr(self.uplegRollRef[0].attr("worldMatrix[0]"), self.ikhUpLegTwist.attr("dWorldUpMatrix")) pm.connectAttr(self.bone0.attr("worldMatrix[0]"), self.ikhUpLegTwist.attr("dWorldUpMatrixEnd")) # setting connexions for ikhAuxTwist self.ikhAuxTwist.attr("dTwistControlEnable").set(True) self.ikhAuxTwist.attr("dWorldUpType").set(4) self.ikhAuxTwist.attr("dWorldUpAxis").set(3) self.ikhAuxTwist.attr("dWorldUpVectorZ").set(1.0) self.ikhAuxTwist.attr("dWorldUpVectorY").set(0.0) self.ikhAuxTwist.attr("dWorldUpVectorEndZ").set(1.0) self.ikhAuxTwist.attr("dWorldUpVectorEndY").set(0.0) pm.connectAttr(self.lowlegRollRef[0].attr("worldMatrix[0]"), self.ikhAuxTwist.attr("dWorldUpMatrix")) pm.connectAttr(self.tws_ref.attr("worldMatrix[0]"), self.ikhAuxTwist.attr("dWorldUpMatrixEnd")) pm.connectAttr(self.auxTwistChain[1].attr("rx"), self.ikhLowLegTwist.attr("twist")) pm.parentConstraint(self.bone1, self.aux_npo, maintainOffset=True) # scale arm length for twist chain (not the squash and stretch) arclen_node = pm.arclen(self.uplegTwistCrv, ch=True) alAttrUpLeg = arclen_node.attr("arcLength") muldiv_nodeArm = pm.createNode("multiplyDivide") pm.connectAttr(arclen_node.attr("arcLength"), muldiv_nodeArm.attr("input1X")) muldiv_nodeArm.attr("input2X").set(alAttrUpLeg.get()) muldiv_nodeArm.attr("operation").set(2) for jnt in self.uplegTwistChain: pm.connectAttr(muldiv_nodeArm.attr("outputX"), jnt.attr("sx")) # scale forearm length for twist chain (not the squash and stretch) arclen_node = pm.arclen(self.lowlegTwistCrv, ch=True) alAttrLowLeg = arclen_node.attr("arcLength") muldiv_nodeLowLeg = pm.createNode("multiplyDivide") pm.connectAttr(arclen_node.attr("arcLength"), muldiv_nodeLowLeg.attr("input1X")) muldiv_nodeLowLeg.attr("input2X").set(alAttrLowLeg.get()) muldiv_nodeLowLeg.attr("operation").set(2) for jnt in self.lowlegTwistChain: pm.connectAttr(muldiv_nodeLowLeg.attr("outputX"), jnt.attr("sx")) # scale compensation for the first twist join dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(self.root.attr("worldMatrix[0]"), dm_node.attr("inputMatrix")) pm.connectAttr(dm_node.attr("outputScale"), self.uplegTwistChain[0].attr("inverseScale")) pm.connectAttr(dm_node.attr("outputScale"), self.lowlegTwistChain[0].attr("inverseScale")) # tangent controls muldiv_node = pm.createNode("multiplyDivide") muldiv_node.attr("input2X").set(-1) pm.connectAttr(self.tws1A_npo.attr("rz"), muldiv_node.attr("input1X")) muldiv_nodeBias = pm.createNode("multiplyDivide") pm.connectAttr(muldiv_node.attr("outputX"), muldiv_nodeBias.attr("input1X")) pm.connectAttr(self.roundness_att, muldiv_nodeBias.attr("input2X")) pm.connectAttr(muldiv_nodeBias.attr("outputX"), self.tws1A_loc.attr("rz")) if self.negate: axis = "xz" else: axis = "-xz" applyop.aimCns(self.tws1A_npo, self.tws0_loc, axis=axis, wupType=2, wupVector=[0, 0, 1], wupObject=self.mid_ctl, maintainOffset=False) applyop.aimCns(self.lowlegTangentB_loc, self.lowlegTangentA_npo, axis=axis, wupType=2, wupVector=[0, 0, 1], wupObject=self.mid_ctl, maintainOffset=False) pm.pointConstraint(self.eff_loc, self.lowlegTangentB_loc) muldiv_node = pm.createNode("multiplyDivide") muldiv_node.attr("input2X").set(-1) pm.connectAttr(self.tws1B_npo.attr("rz"), muldiv_node.attr("input1X")) muldiv_nodeBias = pm.createNode("multiplyDivide") pm.connectAttr(muldiv_node.attr("outputX"), muldiv_nodeBias.attr("input1X")) pm.connectAttr(self.roundness_att, muldiv_nodeBias.attr("input2X")) pm.connectAttr(muldiv_nodeBias.attr("outputX"), self.tws1B_loc.attr("rz")) if self.negate: axis = "-xz" else: axis = "xz" applyop.aimCns(self.tws1B_npo, self.tws2_loc, axis=axis, wupType=2, wupVector=[0, 0, 1], wupObject=self.mid_ctl, maintainOffset=False) applyop.aimCns(self.uplegTangentA_loc, self.uplegTangentB_npo, axis=axis, wupType=2, wupVector=[0, 0, 1], wupObject=self.mid_ctl, maintainOffset=False) # Volume ------------------------------------------- distA_node = node.createDistNode(self.tws0_loc, self.tws1_loc) distB_node = node.createDistNode(self.tws1_loc, self.tws2_loc) add_node = node.createAddNode(distA_node + ".distance", distB_node + ".distance") div_node = node.createDivNode(add_node + ".output", self.root_ctl.attr("sx")) # comp scaling issue dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(self.root.attr("worldMatrix"), dm_node + ".inputMatrix") div_node2 = node.createDivNode(div_node + ".outputX", dm_node + ".outputScaleX") self.volDriver_att = div_node2 + ".outputX" # connecting tangent scaele compensation after volume to # avoid duplicate some nodes distA_node = node.createDistNode(self.tws0_loc, self.mid_ctl) distB_node = node.createDistNode(self.mid_ctl, self.tws2_loc) div_nodeUpLeg = node.createDivNode(distA_node + ".distance", dm_node.attr("outputScaleX")) div_node2 = node.createDivNode(div_nodeUpLeg + ".outputX", distA_node.attr("distance").get()) pm.connectAttr(div_node2.attr("outputX"), self.tws1A_loc.attr("sx")) pm.connectAttr(div_node2.attr("outputX"), self.uplegTangentA_loc.attr("sx")) div_nodeLowLeg = node.createDivNode(distB_node + ".distance", dm_node.attr("outputScaleX")) div_node2 = node.createDivNode(div_nodeLowLeg + ".outputX", distB_node.attr("distance").get()) pm.connectAttr(div_node2.attr("outputX"), self.tws1B_loc.attr("sx")) pm.connectAttr(div_node2.attr("outputX"), self.lowlegTangentB_loc.attr("sx")) # conection curve cnts = [ self.uplegTangentA_loc, self.uplegTangentA_ctl, self.uplegTangentB_ctl, self.kneeTangent_ctl ] applyop.gear_curvecns_op(self.uplegTwistCrv, cnts) cnts = [ self.kneeTangent_ctl, self.lowlegTangentA_ctl, self.lowlegTangentB_ctl, self.lowlegTangentB_loc ] applyop.gear_curvecns_op(self.lowlegTwistCrv, cnts) # Tangent controls vis for shp in self.uplegTangentA_ctl.getShapes(): pm.connectAttr(self.tangentVis_att, shp.attr("visibility")) for shp in self.uplegTangentB_ctl.getShapes(): pm.connectAttr(self.tangentVis_att, shp.attr("visibility")) for shp in self.lowlegTangentA_ctl.getShapes(): pm.connectAttr(self.tangentVis_att, shp.attr("visibility")) for shp in self.lowlegTangentB_ctl.getShapes(): pm.connectAttr(self.tangentVis_att, shp.attr("visibility")) for shp in self.kneeTangent_ctl.getShapes(): pm.connectAttr(self.tangentVis_att, shp.attr("visibility")) # Divisions ---------------------------------------- # at 0 or 1 the division will follow exactly the rotation of the # controler.. and we wont have this nice tangent + roll for i, div_cns in enumerate(self.div_cns): if i < (self.settings["div0"] + 2): mulmat_node = applyop.gear_mulmatrix_op( self.uplegTwistChain[i] + ".worldMatrix", div_cns + ".parentInverseMatrix") lastUpLegDiv = div_cns else: o_node = self.lowlegTwistChain[i - (self.settings["div0"] + 2)] mulmat_node = applyop.gear_mulmatrix_op( o_node + ".worldMatrix", div_cns + ".parentInverseMatrix") lastLowLegDiv = div_cns dm_node = node.createDecomposeMatrixNode(mulmat_node + ".output") pm.connectAttr(dm_node + ".outputTranslate", div_cns + ".t") pm.connectAttr(dm_node + ".outputRotate", div_cns + ".r") # Squash n Stretch o_node = applyop.gear_squashstretch2_op( div_cns, None, pm.getAttr(self.volDriver_att), "x") pm.connectAttr(self.volume_att, o_node + ".blend") pm.connectAttr(self.volDriver_att, o_node + ".driver") pm.connectAttr(self.st_att[i], o_node + ".stretch") pm.connectAttr(self.sq_att[i], o_node + ".squash") # force translation for last loc arm and foreamr applyop.gear_mulmatrix_op(self.kneeTangent_ctl.worldMatrix, lastUpLegDiv.parentInverseMatrix, lastUpLegDiv, "t") applyop.gear_mulmatrix_op(self.tws2_loc.worldMatrix, lastLowLegDiv.parentInverseMatrix, lastLowLegDiv, "t") # NOTE: next line fix the issue on meters. # This is special case becasuse the IK solver from mGear use the # scale as lenght and we have shear # TODO: check for a more clean and elegant solution instead of # re-match the world matrix again transform.matchWorldTransform(self.fk_ctl[0], self.match_fk0_off) transform.matchWorldTransform(self.fk_ctl[1], self.match_fk1_off) transform.matchWorldTransform(self.fk_ctl[0], self.match_fk0) transform.matchWorldTransform(self.fk_ctl[1], self.match_fk1) # match IK/FK ref pm.parentConstraint(self.bone0, self.match_fk0_off, mo=True) pm.parentConstraint(self.bone1, self.match_fk1_off, mo=True) return
def addJoint(self, obj, name, newActiveJnt=None, UniScale=False, segComp=0, gearMulMatrix=True): """Add joint as child of the active joint or under driver object. Args: obj (dagNode): The input driver object for the joint. name (str): The joint name. newActiveJnt (bool or dagNode): If a joint is pass, this joint will be the active joint and parent of the newly created joint. UniScale (bool): Connects the joint scale with the Z axis for a unifor scalin, if set Falsewill connect with each axis separated. segComp (bool): Set True or False the segment compensation in the joint.. gearMulMatrix (bool): Use the custom gear_multiply matrix node, if False will use Maya's default mulMatrix node. Returns: dagNode: The newly created joint. """ customName = self.getCustomJointName(len(self.jointList)) if self.options["joint_rig"]: if newActiveJnt: self.active_jnt = newActiveJnt jnt = primitive.addJoint(self.active_jnt, customName or self.getName(str(name) + "_jnt"), transform.getTransform(obj)) # Disconnect inversScale for better preformance if isinstance(self.active_jnt, pm.nodetypes.Joint): try: pm.disconnectAttr(self.active_jnt.scale, jnt.inverseScale) except RuntimeError: # This handle the situation where we have in between joints # transformation due a negative scaling pm.ungroup(jnt.getParent()) # All new jnts are the active by default self.active_jnt = jnt if gearMulMatrix: mulmat_node = applyop.gear_mulmatrix_op( obj + ".worldMatrix", jnt + ".parentInverseMatrix") dm_node = node.createDecomposeMatrixNode( mulmat_node + ".output") m = mulmat_node.attr('output').get() else: mulmat_node = node.createMultMatrixNode( obj + ".worldMatrix", jnt + ".parentInverseMatrix") dm_node = node.createDecomposeMatrixNode( mulmat_node + ".matrixSum") m = mulmat_node.attr('matrixSum').get() pm.connectAttr(dm_node + ".outputTranslate", jnt + ".t") pm.connectAttr(dm_node + ".outputRotate", jnt + ".r") # TODO: fix squash stretch solver to scale the joint uniform # the next line cheat the uniform scaling only fo X or Y axis # oriented joints if self.options["force_uniScale"]: UniScale = True # invert negative scaling in Joints. We only inver Z axis, so is # the only axis that we are checking if dm_node.attr("outputScaleZ").get() < 0: mul_nod_invert = node.createMulNode( dm_node.attr("outputScaleZ"), -1) out_val = mul_nod_invert.attr("outputX") else: out_val = dm_node.attr("outputScaleZ") # connect scaling if UniScale: pm.connectAttr(out_val, jnt + ".sx") pm.connectAttr(out_val, jnt + ".sy") pm.connectAttr(out_val, jnt + ".sz") else: pm.connectAttr(dm_node.attr("outputScaleX"), jnt + ".sx") pm.connectAttr(dm_node.attr("outputScaleY"), jnt + ".sy") pm.connectAttr(out_val, jnt + ".sz") pm.connectAttr(dm_node + ".outputShear", jnt + ".shear") # Segment scale compensate Off to avoid issues with the global # scale jnt.setAttr("segmentScaleCompensate", segComp) jnt.setAttr("jointOrient", 0, 0, 0) # setting the joint orient compensation in order to have clean # rotation channels jnt.attr("jointOrientX").set(jnt.attr("rx").get()) jnt.attr("jointOrientY").set(jnt.attr("ry").get()) jnt.attr("jointOrientZ").set(jnt.attr("rz").get()) im = m.inverse() if gearMulMatrix: mul_nod = applyop.gear_mulmatrix_op( mulmat_node.attr('output'), im, jnt, 'r') dm_node2 = mul_nod.output.listConnections()[0] else: mul_nod = node.createMultMatrixNode( mulmat_node.attr('matrixSum'), im, jnt, 'r') dm_node2 = mul_nod.matrixSum.listConnections()[0] # if jnt.attr("sz").get() < 0: if dm_node.attr("outputScaleZ").get() < 0: # if negative scaling we have to negate some axis for rotation neg_rot_node = pm.createNode("multiplyDivide") pm.setAttr(neg_rot_node + ".operation", 1) pm.connectAttr(dm_node2.outputRotate, neg_rot_node + ".input1", f=True) for v, axis in zip([-1, -1, 1], "XYZ"): pm.setAttr(neg_rot_node + ".input2" + axis, v) pm.connectAttr(neg_rot_node + ".output", jnt + ".r", f=True) # set not keyable attribute.setNotKeyableAttributes(jnt) else: jnt = primitive.addJoint(obj, customName or self.getName(str(name) + "_jnt"), transform.getTransform(obj)) pm.connectAttr(self.rig.jntVis_att, jnt.attr("visibility")) attribute.lockAttribute(jnt) self.addToGroup(jnt, "deformers") # This is a workaround due the evaluation problem with compound attr # TODO: This workaround, should be removed onces the evaluation issue # is fixed # github issue: Shifter: Joint connection: Maya evaluation Bug #210 dm = jnt.r.listConnections(p=True, type="decomposeMatrix") if dm: at = dm[0] dm_node = at.node() pm.disconnectAttr(at, jnt.r) pm.connectAttr(dm_node.outputRotateX, jnt.rx) pm.connectAttr(dm_node.outputRotateY, jnt.ry) pm.connectAttr(dm_node.outputRotateZ, jnt.rz) dm = jnt.t.listConnections(p=True, type="decomposeMatrix") if dm: at = dm[0] dm_node = at.node() pm.disconnectAttr(at, jnt.t) pm.connectAttr(dm_node.outputTranslateX, jnt.tx) pm.connectAttr(dm_node.outputTranslateY, jnt.ty) pm.connectAttr(dm_node.outputTranslateZ, jnt.tz) # dm = jnt.s.listConnections(p=True, type="decomposeMatrix") # if dm: # at = dm[0] # dm_node = at.node() # pm.disconnectAttr(at, jnt.s) # pm.connectAttr(dm_node.outputScaleX, jnt.sx) # pm.connectAttr(dm_node.outputScaleY, jnt.sy) # pm.connectAttr(dm_node.outputScaleZ, jnt.sz) return jnt
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. """ # 1 bone chain Upv ref ============================================== self.ikHandleUpvRef = primitive.addIkHandle( self.root, self.getName("ikHandleArmChainUpvRef"), self.armChainUpvRef, "ikSCsolver") pm.pointConstraint(self.ik_ctl, self.ikHandleUpvRef) pm.parentConstraint(self.armChainUpvRef[0], self.upv_cns, mo=True) # Visibilities ------------------------------------- # fk fkvis_node = node.createReverseNode(self.blend_att) for shp in self.fk0_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) for shp in self.fk1_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) for shp in self.fk2_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) # ik for shp in self.upv_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ikcns_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ik_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.line_ref.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) if self.settings["ikTR"]: for shp in self.ikRot_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.roll_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) # Controls ROT order ----------------------------------- attribute.setRotOrder(self.fk0_ctl, "XZY") attribute.setRotOrder(self.fk1_ctl, "XYZ") attribute.setRotOrder(self.fk2_ctl, "YZX") attribute.setRotOrder(self.ik_ctl, "XYZ") # IK Solver ----------------------------------------- out = [self.bone0, self.bone1, self.ctrn_loc, self.eff_loc] o_node = applyop.gear_ikfk2bone_op(out, self.root, self.ik_ref, self.upv_ctl, self.fk_ctl[0], self.fk_ctl[1], self.fk_ref, self.length0, self.length1, self.negate) # NOTE: Ideally we should not change hierarchy or move object after # object generation method. But is much easier this way since every # part is in the final and correct position # after the ctrn_loc is in the correct position with the ikfk2bone op # point constrain tip reference pm.pointConstraint(self.ik_ctl, self.tip_ref, mo=False) # interpolate transform mid point locator int_matrix = applyop.gear_intmatrix_op( self.armChainUpvRef[0].attr("worldMatrix"), self.tip_ref.attr("worldMatrix"), .5) applyop.gear_mulmatrix_op( int_matrix.attr("output"), self.interpolate_lvl.attr("parentInverseMatrix[0]"), self.interpolate_lvl) # match roll ctl npo to ctrn_loc current transform (so correct orient) transform.matchWorldTransform(self.ctrn_loc, self.roll_ctl_npo) # match roll ctl npo to interpolate transform current position pos = self.interpolate_lvl.getTranslation(space="world") self.roll_ctl_npo.setTranslation(pos, space="world") # parent constraint roll control npo to interpolate trans pm.parentConstraint(self.interpolate_lvl, self.roll_ctl_npo, mo=True) if self.settings["ikTR"]: # connect the control inputs outEff_dm = o_node.listConnections(c=True)[-1][1] inAttr = self.ikRot_npo.attr("translate") outEff_dm.attr("outputTranslate") >> inAttr outEff_dm.attr("outputScale") >> self.ikRot_npo.attr("scale") dm_node = node.createDecomposeMatrixNode(o_node.attr("outB")) dm_node.attr("outputRotate") >> self.ikRot_npo.attr("rotate") # rotation mulM_node = applyop.gear_mulmatrix_op( self.ikRot_ctl.attr("worldMatrix"), self.eff_loc.attr("parentInverseMatrix")) intM_node = applyop.gear_intmatrix_op(o_node.attr("outEff"), mulM_node.attr("output"), o_node.attr("blend")) dm_node = node.createDecomposeMatrixNode(intM_node.attr("output")) dm_node.attr("outputRotate") >> self.eff_loc.attr("rotate") transform.matchWorldTransform(self.fk2_ctl, self.ikRot_cns) # scale: this fix the scalin popping issue intM_node = applyop.gear_intmatrix_op( self.fk2_ctl.attr("worldMatrix"), self.ik_ctl_ref.attr("worldMatrix"), o_node.attr("blend")) mulM_node = applyop.gear_mulmatrix_op( intM_node.attr("output"), self.eff_loc.attr("parentInverseMatrix")) dm_node = node.createDecomposeMatrixNode(mulM_node.attr("output")) dm_node.attr("outputScale") >> self.eff_loc.attr("scale") pm.connectAttr(self.blend_att, o_node + ".blend") if self.negate: mulVal = -1 rollMulVal = 1 else: mulVal = 1 rollMulVal = -1 roll_m_node = node.createMulNode(self.roll_att, mulVal) roll_m_node2 = node.createMulNode(self.roll_ctl.attr("rx"), rollMulVal) node.createPlusMinusAverage1D( [roll_m_node.outputX, roll_m_node2.outputX], operation=1, output=o_node + ".roll") pm.connectAttr(self.scale_att, o_node + ".scaleA") pm.connectAttr(self.scale_att, o_node + ".scaleB") pm.connectAttr(self.maxstretch_att, o_node + ".maxstretch") pm.connectAttr(self.slide_att, o_node + ".slide") pm.connectAttr(self.softness_att, o_node + ".softness") pm.connectAttr(self.reverse_att, o_node + ".reverse") # Twist references --------------------------------- pm.pointConstraint(self.mid_ctl_twst_ref, self.tws1_npo, maintainOffset=False) pm.connectAttr(self.mid_ctl.scaleX, self.tws1_loc.scaleX) pm.connectAttr(self.mid_ctl.scaleX, self.tws1B_loc.scaleX) pm.orientConstraint(self.mid_ctl_twst_ref, self.tws1_npo, maintainOffset=False) applyop.oriCns(self.mid_ctl, self.tws1_rot, maintainOffset=False) applyop.oriCns(self.mid_ctl, self.tws1B_rot, maintainOffset=False) if self.negate: axis = "xz" axisb = "-xz" else: axis = "-xz" axisb = "xz" applyop.aimCns(self.tws1_loc, self.root, axis=axis, wupType=4, wupVector=[0, 0, 1], wupObject=self.mid_ctl, maintainOffset=False) applyop.aimCns(self.tws1B_loc, self.eff_loc, axis=axisb, wupType=4, wupVector=[0, 0, 1], wupObject=self.mid_ctl, maintainOffset=False) pm.pointConstraint(self.thick_ctl, self.tws1B_loc, maintainOffset=False) o_node = applyop.gear_mulmatrix_op( self.eff_loc.attr("worldMatrix"), self.root.attr("worldInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputTranslate", self.tws2_npo.attr("translate")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputRotate", self.tws2_npo.attr("rotate")) o_node = applyop.gear_mulmatrix_op( self.eff_loc.attr("worldMatrix"), self.tws2_rot.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") attribute.setRotOrder(self.tws2_rot, "XYZ") pm.connectAttr(dm_node + ".outputRotate", self.tws2_rot + ".rotate") self.tws0_rot.setAttr("sx", .001) self.tws2_rot.setAttr("sx", .001) add_node = node.createAddNode(self.roundness_att, .001) pm.connectAttr(add_node + ".output", self.tws1_rot.attr("sx")) pm.connectAttr(add_node + ".output", self.tws1B_rot.attr("sx")) pm.connectAttr(self.armpit_roll_att, self.tws0_rot + ".rotateX") # Roll Shoulder applyop.splineIK(self.getName("rollRef"), self.rollRef, parent=self.root, cParent=self.bone0) # Volume ------------------------------------------- distA_node = node.createDistNode(self.tws0_loc, self.tws1_loc) distB_node = node.createDistNode(self.tws1_loc, self.tws2_loc) add_node = node.createAddNode(distA_node + ".distance", distB_node + ".distance") div_node = node.createDivNode(add_node + ".output", self.root.attr("sx")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(self.root.attr("worldMatrix"), dm_node + ".inputMatrix") div_node2 = node.createDivNode(div_node + ".outputX", dm_node + ".outputScaleX") self.volDriver_att = div_node2 + ".outputX" if self.settings["extraTweak"]: for tweak_ctl in self.tweak_ctl: for shp in tweak_ctl.getShapes(): pm.connectAttr(self.tweakVis_att, shp.attr("visibility")) # Divisions ---------------------------------------- # at 0 or 1 the division will follow exactly the rotation of the # controler.. and we wont have this nice tangent + roll b_twist = False for i, div_cns in enumerate(self.div_cns): if self.settings["supportJoints"]: if i < (self.settings["div0"] + 1): perc = i * .5 / (self.settings["div0"] + 1.0) elif i < (self.settings["div0"] + 2): perc = .49 elif i < (self.settings["div0"] + 3): perc = .50 elif i < (self.settings["div0"] + 4): b_twist = True perc = .51 else: perc = .5 + \ (i - self.settings["div0"] - 3.0) * .5 / \ (self.settings["div1"] + 1.0) else: if i < (self.settings["div0"] + 1): perc = i * .5 / (self.settings["div0"] + 1.0) elif i < (self.settings["div0"] + 2): b_twist = True perc = .501 else: perc = .5 + \ (i - self.settings["div0"] - 1.0) * .5 / \ (self.settings["div1"] + 1.0) perc = max(.001, min(.990, perc)) # mid twist distribution if b_twist: mid_twist = self.tws1B_rot else: mid_twist = self.tws1_rot # Roll if self.negate: o_node = applyop.gear_rollsplinekine_op( div_cns, [self.tws2_rot, mid_twist, self.tws0_rot], 1.0 - perc, 40) else: o_node = applyop.gear_rollsplinekine_op( div_cns, [self.tws0_rot, mid_twist, self.tws2_rot], perc, 40) pm.connectAttr(self.resample_att, o_node + ".resample") pm.connectAttr(self.absolute_att, o_node + ".absolute") # Squash n Stretch o_node = applyop.gear_squashstretch2_op( div_cns, None, pm.getAttr(self.volDriver_att), "x") pm.connectAttr(self.volume_att, o_node + ".blend") pm.connectAttr(self.volDriver_att, o_node + ".driver") pm.connectAttr(self.st_att[i], o_node + ".stretch") pm.connectAttr(self.sq_att[i], o_node + ".squash") # match IK/FK ref pm.parentConstraint(self.bone0, self.match_fk0_off, mo=True) pm.parentConstraint(self.bone1, self.match_fk1_off, mo=True) if self.settings["ikTR"]: transform.matchWorldTransform(self.ikRot_ctl, self.match_ikRot) transform.matchWorldTransform(self.fk_ctl[2], self.match_fk2) # connect_reader pm.parentConstraint(self.bone0, self.readerA, mo=True) pm.parentConstraint(self.bone1, self.readerB, mo=True) # connect auto thickness if self.negate and not self.settings["mirrorMid"]: d_val = 180 / self.length1 else: d_val = -180 / self.length1 div_thick_node = node.createDivNode(self.elbow_thickness_att, d_val) node.createMulNode(div_thick_node.outputX, self.readerB.ry, self.thick_lvl.tx) return
def _createSoftModTweak(baseCtl, tweakCtl, name, targets, nameExt="softMod", is_asset=False): sm = pm.softMod(targets, wn=[tweakCtl, tweakCtl]) pm.rename(sm[0], "{}_{}".format(name, nameExt)) # disconnect default connection plugs = sm[0].softModXforms.listConnections(p=True) for p in plugs: pm.disconnectAttr(p, sm[0].softModXforms) pm.delete(p.node()) dm_node = node.createDecomposeMatrixNode(baseCtl.worldMatrix[0]) pm.connectAttr(dm_node.outputTranslate, sm[0].falloffCenter) mul_node = node.createMulNode(dm_node.outputScaleX, tweakCtl.attr("falloff")) pm.connectAttr(mul_node.outputX, sm[0].falloffRadius) pm.connectAttr(tweakCtl.attr("surfaceMode"), sm[0].falloffMode) mulMatrix_node = applyop.gear_mulmatrix_op(tweakCtl.worldMatrix[0], tweakCtl.parentInverseMatrix[0]) pm.connectAttr(mulMatrix_node.output, sm[0].weightedMatrix) pm.connectAttr(baseCtl.worldInverseMatrix[0], sm[0].postMatrix) pm.connectAttr(baseCtl.worldMatrix[0], sm[0].preMatrix) if is_asset: tag_name = ASSET_TAG else: tag_name = SHOT_TAG attribute.addAttribute(sm[0], tag_name, "bool", False, keyable=False) sm[0].addAttr("ctlRoot", at='message', m=False) sm[0].addAttr("ctlBase", at='message', m=False) sm[0].addAttr("ctlTweak", at='message', m=False) pm.connectAttr(baseCtl.getParent().attr("message"), sm[0].attr("ctlRoot")) pm.connectAttr(baseCtl.attr("message"), sm[0].attr("ctlBase")) pm.connectAttr(tweakCtl.attr("message"), sm[0].attr("ctlTweak")) # This connection allow the softTweak to work if we apply the skin # precision fix. # TODO: By default only apply to a non asset tweaks. if skin.getSkinCluster(targets[0]) and not is_asset: skin_cls = skin.getSkinCluster(targets[0]) cnxs = skin_cls.matrix[0].listConnections() if (cnxs and cnxs[0].type() == "mgear_mulMatrix" and not sm[0].hasAttr("_fixedSkinFix")): # tag the softmod as fixed attribute.addAttribute(sm[0], "_fixedSkinFix", "bool") # original connections matrix_cnx = sm[0].matrix.listConnections(p=True)[0] preMatrix_cnx = sm[0].preMatrix.listConnections(p=True)[0] wgtMatrix_cnx = sm[0].weightedMatrix.listConnections(p=True)[0] postMatrix_cnx = sm[0].postMatrix.listConnections(p=True)[0] # pre existing node operators mulMtx_node = wgtMatrix_cnx.node() dcMtx_node = sm[0].falloffCenter.listConnections(p=True)[0].node() # geo offset connnections geo_root = targets[0].getParent() gr_W = geo_root.worldMatrix[0] gr_WI = geo_root.worldInverseMatrix[0] # new offset operators mmm1 = applyop.gear_mulmatrix_op(preMatrix_cnx, gr_WI) mmm2 = applyop.gear_mulmatrix_op(matrix_cnx, gr_WI) mmm3 = applyop.gear_mulmatrix_op(gr_W, postMatrix_cnx) # re-wire connections pm.connectAttr(mmm1.output, dcMtx_node.inputMatrix, f=True) pm.connectAttr(mmm1.output, sm[0].preMatrix, f=True) pm.connectAttr(mmm2.output, sm[0].matrix, f=True) pm.connectAttr(mmm2.output, mulMtx_node.matrixA, f=True) pm.connectAttr(mmm3.output, mulMtx_node.matrixB, f=True) pm.connectAttr(mmm3.output, sm[0].postMatrix, f=True) _neutra_geomMatrix(sm[0]) return sm[0]
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. """ # Tangent position --------------------------------- # common part d = vector.getDistance(self.guide.pos["root"], self.guide.pos["neck"]) dist_node = node.createDistNode(self.root, self.ik_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_loc.getAttr("ty")) res_node = node.createMulNode(mul_node + ".outputX", div_node + ".outputX") pm.connectAttr(res_node + ".outputX", self.tan0_loc + ".ty") # tan1 mul_node = node.createMulNode(self.tan1_att, self.tan1_loc.getAttr("ty")) res_node = node.createMulNode(mul_node + ".outputX", div_node + ".outputX") pm.connectAttr(res_node + ".outputX", self.tan1_loc.attr("ty")) # Curves ------------------------------------------- op = applyop.gear_curveslide2_op(self.slv_crv, self.mst_crv, 0, 1.5, 0.5, 0.5) 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 ----------------------------------------- for i in range(self.divisions): # References u = i / (self.divisions - 1.0) cns = applyop.pathCns(self.div_cns[i], self.slv_crv, False, u, True) cns.setAttr("frontAxis", 1) # front axis is 'Y' cns.setAttr("upAxis", 2) # front axis is 'Z' # Roll intMatrix = applyop.gear_intmatrix_op( self.intMRef + ".worldMatrix", self.ik_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") # Squash n Stretch op = applyop.gear_squashstretch2_op(self.fk_npo[i], self.root, pm.arclen(self.slv_crv), "y") 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") op.setAttr("driver_min", 0.1) # scl compas if i != 0: div_node = node.createDivNode( [1, 1, 1], [ self.fk_npo[i - 1] + ".sx", self.fk_npo[i - 1] + ".sy", self.fk_npo[i - 1] + ".sz", ], ) pm.connectAttr(div_node + ".output", self.scl_npo[i] + ".scale") # Controlers if i == 0: mulmat_node = applyop.gear_mulmatrix_op( self.div_cns[i].attr("worldMatrix"), self.root.attr("worldInverseMatrix"), ) 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") pm.connectAttr(dm_node + ".outputTranslate", self.fk_npo[i].attr("t")) pm.connectAttr(dm_node + ".outputRotate", self.fk_npo[i].attr("r")) # Orientation Lock if i == self.divisions - 1: dm_node = node.createDecomposeMatrixNode(self.ik_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_ori_att, ) self.div_cns[i].attr("rotate").disconnect() pm.connectAttr(blend_node + ".output", self.div_cns[i] + ".rotate") # Head --------------------------------------------- self.fk_ctl[-1].addChild(self.head_cns) # scale compensation dm_node = node.createDecomposeMatrixNode(self.scl_npo[0] + ".parentInverseMatrix") pm.connectAttr(dm_node + ".outputScale", self.scl_npo[0] + ".scale")
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. """ # Tangent position --------------------------------- # common part d = vector.getDistance(self.guide.apos[0], self.guide.apos[1]) 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 ----------------------------------------- for i in range(self.settings["division"]): # References u = i / (self.settings["division"] - 1.0) cns = applyop.pathCns(self.div_cns[i], self.slv_crv, False, u, 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") # Squash n Stretch op = applyop.gear_squashstretch2_op(self.scl_transforms[i], self.root, pm.arclen(self.slv_crv), "y") 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") # Connections (Hooks) ------------------------------ pm.pointConstraint(self.scl_transforms[0], self.cnx0) pm.scaleConstraint(self.scl_transforms[0], self.cnx0) pm.orientConstraint(self.ik0_ctl, self.cnx0) pm.pointConstraint(self.scl_transforms[-1], self.cnx1) pm.scaleConstraint(self.scl_transforms[-1], self.cnx1) pm.orientConstraint(self.ik1_ctl, self.cnx1)
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. """ # 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.lenght_att, op + ".maxstretch") op = applyop.gear_curveslide2_op( self.slv_upv_crv, self.upv_crv, 0, 1.5, .5, .5) pm.connectAttr(self.position_att, op + ".position") pm.connectAttr(self.lenght_att, op + ".maxstretch") for tang in self.tangentsCtl: for shp in tang.getShapes(): pm.connectAttr(self.tangentsVis_att, shp.attr("visibility")) for twnpo, fkctl in zip(self.tweak_npo, self.fk_ctl): intMatrix = applyop.gear_intmatrix_op( fkctl.attr("worldMatrix"), fkctl.getParent().attr("worldMatrix"), .5) applyop.gear_mulmatrix_op(intMatrix.attr("output"), twnpo.attr("parentInverseMatrix[0]"), twnpo) dm_node_scl = node.createDecomposeMatrixNode(self.root.worldMatrix) if self.settings["keepLength"]: arclen_node = pm.arclen(self.slv_crv, ch=True) alAttr = pm.getAttr(arclen_node + ".arcLength") pm.addAttr(self.slv_crv, ln="length_ratio", k=True, w=True) node.createDivNode(arclen_node.arcLength, alAttr, self.slv_crv.length_ratio) div_node_scl = node.createDivNode(self.slv_crv.length_ratio, dm_node_scl.outputScaleX) step = 1.000 / (self.def_number - 1) u = 0.000 for i in range(self.def_number): mult_node = node.createMulNode(u, self.lenght_att) cnsUpv = applyop.pathCns(self.upv_cns[i], self.slv_upv_crv, cnsType=False, u=u, tangent=False) pm.connectAttr(mult_node.outputX, cnsUpv.uValue) cns = applyop.pathCns( self.div_cns[i], self.slv_crv, False, u, True) pm.connectAttr(mult_node.outputX, cns.uValue) # Connectiong the scale for scaling compensation for axis, AX in zip("xyz", "XYZ"): pm.connectAttr(dm_node_scl.attr("outputScale{}".format(AX)), self.div_cns[i].attr("s{}".format(axis))) if self.settings["keepLength"]: div_node2 = node.createDivNode(u, div_node_scl.outputX) cond_node = node.createConditionNode(div_node2.input1X, div_node2.outputX, 4, div_node2.input1X, div_node2.outputX) # pm.connectAttr(cond_node + ".outColorR", # cnsUpv + ".uValue") # pm.connectAttr(cond_node + ".outColorR", # cns + ".uValue") pm.connectAttr(cond_node + ".outColorR", mult_node + ".input1X", f=True) # Connect the scaling for self.Extra_tweak_npo et_npo = self.Extra_tweak_npo[i] pm.connectAttr(self.spin_att, et_npo + ".rz") base_node = node.createMulNode(self.baseSize_att, 1.00000 - u, output=None) tip_node = node.createMulNode(self.tipSize_att, u, output=None) sum_node = node.createPlusMinusAverage1D([base_node.outputX, tip_node.outputX]) # print et_npo pm.connectAttr(sum_node.output1D, et_npo.scaleX, f=True) pm.connectAttr(sum_node.output1D, et_npo.scaleY, f=True) pm.connectAttr(sum_node.output1D, et_npo.scaleZ, f=True) cns.setAttr("worldUpType", 1) cns.setAttr("frontAxis", 0) cns.setAttr("upAxis", 1) pm.connectAttr(self.upv_cns[i].attr("worldMatrix[0]"), cns.attr("worldUpMatrix")) u += step for et in self.Extra_tweak_ctl: for shp in et.getShapes(): pm.connectAttr(self.tweakVis_att, shp.attr("visibility")) if self.settings["keepLength"]: # add the safty distance offset self.tweakTip_npo.attr("tx").set(self.off_dist) # connect vis line ref for shp in self.line_ref.getShapes(): pm.connectAttr(self.ikVis_att, shp.attr("visibility")) for ctl in self.tweak_ctl: for shp in ctl.getShapes(): pm.connectAttr(self.ikVis_att, shp.attr("visibility")) for ctl in self.fk_ctl: for shp in ctl.getShapes(): pm.connectAttr(self.fkVis_att, shp.attr("visibility"))
def addFkOperator(self, i, rootWorld_node, crv_node): fk_local_npo_xfoms = [] if i not in [len(self.guide.apos), 0]: xform = getTransform(self.fk_local_npo[i]) fk_local_npo_xfoms.append(xform) # break FK hierarchical orient if i not in [len(self.guide.apos), 0]: s = self.fk_ctl[i - 1] s2 = self.fk_npo[i] d = self.fk_local_npo[i] mulmat_node = applyop.gear_mulmatrix_op(s2.attr("matrix"), s.attr("matrix")) mulmat_node2 = applyop.gear_mulmatrix_op(mulmat_node.attr("output"), s2.attr("inverseMatrix")) dm_node = node.createDecomposeMatrixNode(mulmat_node2 + ".output") pm.connectAttr(dm_node + ".outputTranslate", d.attr("t")) check_list = (pm.Attribute, unicode, str) # noqa cond = pm.createNode("condition") pm.setAttr(cond + ".operation", 4) # greater attribute.connectSet(self.fk_collapsed_att, cond + ".secondTerm", check_list) attribute.connectSet(dm_node + ".outputRotate", cond + ".colorIfTrue", check_list) pm.setAttr(cond + ".colorIfFalseR", 0.) pm.setAttr(cond + ".colorIfFalseG", 0.) pm.setAttr(cond + ".colorIfFalseB", 0.) pm.connectAttr(cond + ".outColor", d.attr("r")) # References if i == 0: # we add extra 10% to the first position u = (1.0 / (len(self.guide.apos) - 1.0)) / 10000 else: u = getCurveUAtPoint(self.slv_crv, self.guide.apos[i]) tmp_div_npo_transform = getTransform(self.div_cns_npo[i]) # to fix mismatch before/after later cns = applyop.pathCns(self.div_cns[i], self.slv_crv, False, u, True) cns.setAttr("frontAxis", 1) # front axis is 'Y' cns.setAttr("upAxis", 0) # front axis is 'X' # Roll # choose ik_ctls for _i, uv in enumerate(self.ik_uv_param): if u < uv: ik_a = self.ik_ctl[_i - 1] ik_b = self.ik_ctl[_i] roll_a = self.ik_decompose_rot[_i - 1] roll_b = self.ik_decompose_rot[_i] ratio = (uv - u) * (self.settings["ikNb"] - 1) break else: ik_a = self.ik_ctl[-2] ik_b = self.ik_ctl[-1] roll_a = self.ik_decompose_rot[-2] roll_b = self.ik_decompose_rot[-1] ratio = 1. intMatrix = applyop.gear_intmatrix_op( ik_a + ".worldMatrix", ik_b + ".worldMatrix", ratio) 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") self.div_cns_npo[i].setMatrix(tmp_div_npo_transform, worldSpace=True) # rotationdriver roll_ratio = (i + 1.00) / len(self.fk_ctl) mul1 = pm.createNode("multDoubleLinear") pm.connectAttr(roll_a.attr("outRoll"), mul1.attr("input1")) pm.setAttr(mul1.attr("input2"), ratio) mul2 = pm.createNode("multDoubleLinear") pm.connectAttr(roll_b.attr("outRoll"), mul2.attr("input1")) pm.setAttr(mul2.attr("input2"), (1. - ratio)) add = pm.createNode("addDoubleLinear") pm.connectAttr(mul1.attr("output"), add.attr("input1")) pm.connectAttr(mul2.attr("output"), add.attr("input2")) compose_rot = pm.createNode("composeRotate") pm.setAttr(compose_rot.attr("axisOrientX"), 90.0) pm.setAttr(compose_rot.attr("axisOrientZ"), 90.0) pm.connectAttr(add.attr("output"), compose_rot.attr("roll")) pm.connectAttr(compose_rot.attr("outRotate"), self.div_roll_npo[i].attr("rotate")) # 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 tmp_local_npo_transform = getTransform(self.fk_local_npo[i]) # to fix mismatch before/after later if i == 0: mulmat_node = applyop.gear_mulmatrix_op( self.div_roll_npo[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")) elif i != len(self.guide.apos) - 1: mulmat_node = applyop.gear_mulmatrix_op( self.div_roll_npo[i].attr("worldMatrix"), self.div_roll_npo[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")) else: pass if i == len(self.guide.apos) - 1: # pm.connectAttr(dm_node + ".outputRotate", self.fk_local_npo2.attr("r")) _ = pm.parentConstraint(self.ik_ctl[-1], self.fk_local_npo2, skipTranslate=("x", "y", "z"), maintainOffset=True) else: pm.connectAttr(dm_node + ".outputRotate", self.fk_npo[i].attr("r")) # self.addOperatorsOrientationLock(i, cns) self.fk_local_npo[i].setMatrix(tmp_local_npo_transform, worldSpace=True) # References if i < (len(self.fk_ctl) - 1): if self.negate: aim = (0., 1., 0.) upv = (0., 0., 1.) else: aim = (0., -1., 0.) upv = (0., 0., -1.) pm.aimConstraint(self.div_cns_npo[i + 1], self.div_cns_npo[i], mo=True, worldUpType="object", worldUpObject=self.fk_upvectors[i], worldUpVector=(0., 1., 0.), aimVector=aim, upVector=upv, )
def slice(parent=False, oSel=False, *args): """Create a proxy geometry from a skinned object""" startTime = datetime.datetime.now() print oSel if not oSel: oSel = pm.selected()[0] print "----" print oSel oColl = pm.skinCluster(oSel, query=True, influence=True) oFaces = oSel.faces nFaces = oSel.numFaces() faceGroups = [] for x in oColl: faceGroups.append([]) sCluster = pm.listConnections(oSel.getShape(), type="skinCluster") print sCluster sCName = sCluster[0].name() for iFace in range(nFaces): faceVtx = oFaces[iFace].getVertices() oSum = False for iVtx in faceVtx: values = pm.skinPercent(sCName, oSel.vtx[iVtx], q=True, v=True) if oSum: oSum = [L + l for L, l in zip(oSum, values)] else: oSum = values print "adding face: " \ + str(iFace) \ + " to group in: " \ + str(oColl[oSum.index(max(oSum))]) faceGroups[oSum.index(max(oSum))].append(iFace) original = oSel if not parent: try: parentGroup = pm.PyNode("ProxyGeo") except TypeError: parentGroup = pm.createNode("transform", n="ProxyGeo") try: proxySet = pm.PyNode("rig_proxyGeo_grp") except TypeError: proxySet = pm.sets(name="rig_proxyGeo_grp", em=True) for boneList in faceGroups: if len(boneList): newObj = pm.duplicate( original, rr=True, name=oColl[faceGroups.index(boneList)] + "_Proxy") for trans in ["tx", "ty", "tz", "rx", "ry", "rz", "sx", "sy", "sz"]: pm.setAttr(newObj[0].name() + "." + trans, lock=0) c = list(newObj[0].faces) for index in reversed(boneList): c.pop(index) pm.delete(c) if parent: pm.parent(newObj, pm.PyNode(oColl[faceGroups.index(boneList)]), a=True) else: pm.parent(newObj, parentGroup, a=True) dummyCopy = pm.duplicate(newObj[0])[0] pm.delete(newObj[0].listRelatives(c=True)) transform.matchWorldTransform( pm.PyNode(oColl[faceGroups.index(boneList)]), newObj[0]) pm.parent(dummyCopy.listRelatives(c=True)[0], newObj[0], shape=True) pm.delete(dummyCopy) pm.rename(newObj[0].listRelatives(c=True)[0], newObj[0].name() + "_offset") o_multiplayer = pm.PyNode(oColl[faceGroups.index(boneList)]) mulmat_node = applyop.gear_mulmatrix_op( o_multiplayer.name() + ".worldMatrix", newObj[0].name() + ".parentInverseMatrix") outPlug = mulmat_node + ".output" dm_node = node.createDecomposeMatrixNode(outPlug) pm.connectAttr(dm_node + ".outputTranslate", newObj[0].name() + ".t") pm.connectAttr(dm_node + ".outputRotate", newObj[0].name() + ".r") pm.connectAttr(dm_node + ".outputScale", newObj[0].name() + ".s") print "Creating proxy for: {}".format( str(oColl[faceGroups.index(boneList)])) pm.sets(proxySet, add=newObj) endTime = datetime.datetime.now() finalTime = endTime - startTime mgear.log("=============== Slicing for: %s finish ======= [ %s ] ===" "===" % (oSel.name(), str(finalTime)))
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. """ # Visibilities ------------------------------------- if self.isFkIk: # fk fkvis_node = node.createReverseNode(self.blend_att) for fk_ctl in self.fk_ctl: for shp in fk_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) # ik for shp in self.upv_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ikcns_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ik_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) # FK Chain ----------------------------------------- if self.isFk: for off, ref in zip(self.fk_off[1:], self.fk_ref): applyop.gear_mulmatrix_op( ref.worldMatrix, off.parentInverseMatrix, off, "rt") # IK Chain ----------------------------------------- if self.isIk: self.ikh = primitive.addIkHandle( self.root, self.getName("ikh"), self.chain) self.ikh.attr("visibility").set(False) # Constraint and up vector pm.pointConstraint(self.ik_ctl, self.ikh, maintainOffset=False) pm.poleVectorConstraint(self.upv_ctl, self.ikh) # TwistTest o_list = [round(elem, 4) for elem in transform.getTranslation(self.chain[1])] \ != [round(elem, 4) for elem in self.guide.apos[1]] if o_list: add_nodeTwist = node.createAddNode(180.0, self.roll_att) pm.connectAttr(add_nodeTwist + ".output", self.ikh.attr("twist")) else: pm.connectAttr(self.roll_att, self.ikh.attr("twist")) # Chain of deformers ------------------------------- for i, loc in enumerate(self.loc): if self.settings["mode"] == 0: # fk only pm.parentConstraint(self.fk_ctl[i], loc, maintainOffset=False) pm.connectAttr(self.fk_ctl[i] + ".scale", loc + ".scale") elif self.settings["mode"] == 1: # ik only pm.parentConstraint(self.chain[i], loc, maintainOffset=False) elif self.settings["mode"] == 2: # fk/ik rev_node = node.createReverseNode(self.blend_att) # orientation cns = pm.parentConstraint( self.fk_ctl[i], self.chain[i], loc, maintainOffset=False) cns.interpType.set(0) weight_att = pm.parentConstraint( cns, query=True, weightAliasList=True) pm.connectAttr(rev_node + ".outputX", weight_att[0]) pm.connectAttr(self.blend_att, weight_att[1]) # scaling blend_node = pm.createNode("blendColors") pm.connectAttr(self.chain[i].attr("scale"), blend_node + ".color1") pm.connectAttr(self.fk_ctl[i].attr("scale"), blend_node + ".color2") pm.connectAttr(self.blend_att, blend_node + ".blender") pm.connectAttr(blend_node + ".output", loc + ".scale")
def createRivetTweak(mesh, edgePair, name, parent=None, ctlParent=None, jntParent=None, color=[0, 0, 0], size=.04, defSet=None, ctlSet=None, side=None, gearMulMatrix=True, attach_rot=False, inputMesh=None): """Create a tweak joint attached to the mesh using a rivet Args: mesh (mesh): The object to add the tweak edgePair (pair list): The edge pair to create the rivet name (str): The name for the tweak parent (None or dagNode, optional): The parent for the tweak jntParent (None or dagNode, optional): The parent for the joints ctlParent (None or dagNode, optional): The parent for the tweak control color (list, optional): The color for the control size (float, optional): Size of the control defSet (None or set, optional): Deformer set to add the joints ctlSet (None or set, optional): the set to add the controls side (None, str): String to set the side. Valid values are L, R or C. If the side is not set or the value is not valid, the side will be set automatically based on the world position gearMulMatrix (bool, optional): If False will use Maya default multiply matrix node Returns: PyNode: The tweak control """ blendShape = blendShapes.getBlendShape(mesh) if not inputMesh: inputMesh = blendShape.listConnections(sh=True, t="shape", d=False)[0] oRivet = rivet.rivet() base = oRivet.create(inputMesh, edgePair[0], edgePair[1], parent) # get side if not side or side not in ["L", "R", "C"]: if base.getTranslation(space='world')[0] < -0.01: side = "R" elif base.getTranslation(space='world')[0] > 0.01: side = "L" else: side = "C" nameSide = name + "_tweak_" + side pm.rename(base, nameSide) if not ctlParent: ctlParent = base ctl_parent_tag = None else: ctl_parent_tag = ctlParent # Joints NPO npo = pm.PyNode(pm.createNode("transform", n=nameSide + "_npo", p=ctlParent, ss=True)) if attach_rot: # npo.setTranslation(base.getTranslation(space="world"), space="world") pm.parentConstraint(base, npo, mo=False) else: pm.pointConstraint(base, npo, mo=False) # create joints if not jntParent: jntParent = npo matrix_cnx = False else: # need extra connection to ensure is moving with th npo, even is # not child of npo matrix_cnx = True jointBase = primitive.addJoint(jntParent, nameSide + "_jnt_lvl") joint = primitive.addJoint(jointBase, nameSide + "_jnt") # reset axis and invert behaviour for axis in "XYZ": pm.setAttr(jointBase + ".jointOrient" + axis, 0) pm.setAttr(npo + ".translate" + axis, 0) # pm.setAttr(jointBase + ".translate" + axis, 0) pp = npo.getParent() pm.parent(npo, w=True) for axis in "xyz": npo.attr("r" + axis).set(0) if side == "R": npo.attr("ry").set(180) npo.attr("sz").set(-1) pm.parent(npo, pp) dm_node = None if matrix_cnx: mulmat_node = applyop.gear_mulmatrix_op( npo + ".worldMatrix", jointBase + ".parentInverseMatrix") dm_node = node.createDecomposeMatrixNode( mulmat_node + ".output") m = mulmat_node.attr('output').get() pm.connectAttr(dm_node + ".outputTranslate", jointBase + ".t") pm.connectAttr(dm_node + ".outputRotate", jointBase + ".r") # invert negative scaling in Joints. We only inver Z axis, so is # the only axis that we are checking print(dm_node.attr("outputScaleZ").get()) if dm_node.attr("outputScaleZ").get() < 0: mul_nod_invert = node.createMulNode( dm_node.attr("outputScaleZ"), -1) out_val = mul_nod_invert.attr("outputX") else: out_val = dm_node.attr("outputScaleZ") pm.connectAttr(dm_node.attr("outputScaleX"), jointBase + ".sx") pm.connectAttr(dm_node.attr("outputScaleY"), jointBase + ".sy") pm.connectAttr(out_val, jointBase + ".sz") pm.connectAttr(dm_node + ".outputShear", jointBase + ".shear") # Segment scale compensate Off to avoid issues with the global # scale jointBase.setAttr("segmentScaleCompensate", 0) joint.setAttr("segmentScaleCompensate", 0) jointBase.setAttr("jointOrient", 0, 0, 0) # setting the joint orient compensation in order to have clean # rotation channels jointBase.attr("jointOrientX").set(jointBase.attr("rx").get()) jointBase.attr("jointOrientY").set(jointBase.attr("ry").get()) jointBase.attr("jointOrientZ").set(jointBase.attr("rz").get()) im = m.inverse() if gearMulMatrix: mul_nod = applyop.gear_mulmatrix_op( mulmat_node.attr('output'), im, jointBase, 'r') dm_node2 = mul_nod.output.listConnections()[0] else: mul_nod = node.createMultMatrixNode( mulmat_node.attr('matrixSum'), im, jointBase, 'r') dm_node2 = mul_nod.matrixSum.listConnections()[0] if dm_node.attr("outputScaleZ").get() < 0: negateTransformConnection(dm_node2.outputRotate, jointBase.rotate) else: resetJntLocalSRT(jointBase) # hidding joint base by changing the draw mode pm.setAttr(jointBase + ".drawStyle", 2) if not defSet: try: defSet = pm.PyNode("rig_deformers_grp") except TypeError: pm.sets(n="rig_deformers_grp", empty=True) defSet = pm.PyNode("rig_deformers_grp") pm.sets(defSet, add=joint) controlType = "sphere" o_icon = icon.create(npo, nameSide + "_ctl", datatypes.Matrix(), color, controlType, w=size) attribute.addAttribute(o_icon, "isCtl", "bool", keyable=False) transform.resetTransform(o_icon) if dm_node and dm_node.attr("outputScaleZ").get() < 0: pm.connectAttr(o_icon.scale, joint.scale) negateTransformConnection(o_icon.rotate, joint.rotate) negateTransformConnection(o_icon.translate, joint.translate, [1, 1, -1]) else: for t in [".translate", ".scale", ".rotate"]: pm.connectAttr(o_icon + t, joint + t) # create the attributes to handlde mirror and symetrical pose attribute.addAttribute( o_icon, "invTx", "bool", 0, keyable=False, niceName="Invert Mirror TX") attribute.addAttribute( o_icon, "invTy", "bool", 0, keyable=False, niceName="Invert Mirror TY") attribute.addAttribute( o_icon, "invTz", "bool", 0, keyable=False, niceName="Invert Mirror TZ") attribute.addAttribute( o_icon, "invRx", "bool", 0, keyable=False, niceName="Invert Mirror RX") attribute.addAttribute( o_icon, "invRy", "bool", 0, keyable=False, niceName="Invert Mirror RY") attribute.addAttribute( o_icon, "invRz", "bool", 0, keyable=False, niceName="Invert Mirror RZ") attribute.addAttribute( o_icon, "invSx", "bool", 0, keyable=False, niceName="Invert Mirror SX") attribute.addAttribute( o_icon, "invSy", "bool", 0, keyable=False, niceName="Invert Mirror SY") attribute.addAttribute( o_icon, "invSz", "bool", 0, keyable=False, niceName="Invert Mirror SZ") # magic of doritos connection pre_bind_matrix_connect(mesh, joint, jointBase) # add control tag node.add_controller_tag(o_icon, ctl_parent_tag) if not ctlSet: try: ctlSet = pm.PyNode("rig_controllers_grp") except TypeError: pm.sets(n="rig_controllers_grp", empty=True) ctlSet = pm.PyNode("rig_controllers_grp") pm.sets(ctlSet, add=o_icon) return o_icon
def 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. """ # 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") # Division ----------------------------------------- rootWorld_node = node.createDecomposeMatrixNode( self.root.attr("worldMatrix")) for i in range(self.settings["fkNb"]): # References u = i / (self.settings["fkNb"] - 1.0) if i == 0: # we add extra 10% to the first position u = (1.0 / (self.settings["fkNb"] - 1.0)) / 10 cns = applyop.pathCns(self.div_cns[i], self.slv_crv, False, u, True) cns.setAttr("frontAxis", 0) # front axis is 'X' cns.setAttr("upAxis", 2) # front axis is 'Z' # Roll intMatrix = applyop.gear_intmatrix_op( self.ik_ctl[0] + ".worldMatrix", self.ik_ctl[-1] + ".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" ]) # 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.ik_ctl[0] + ".worldMatrix") blend_node = node.createBlendNode( [dm_node + ".outputRotate%s" % s for s in "XYZ"], [cns + ".rotate%s" % s for s in "XYZ"], 0) self.div_cns[i].attr("rotate").disconnect() pm.connectAttr(blend_node + ".output", self.div_cns[i] + ".rotate") elif i == self.settings["fkNb"] - 1: dm_node = node.createDecomposeMatrixNode(self.ik_ctl[-1] + ".worldMatrix") blend_node = node.createBlendNode( [dm_node + ".outputRotate%s" % s for s in "XYZ"], [cns + ".rotate%s" % s for s in "XYZ"], 0) self.div_cns[i].attr("rotate").disconnect() pm.connectAttr(blend_node + ".output", self.div_cns[i] + ".rotate")
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. """ # Visibilities ------------------------------------- # fk fkvis_node = node.createReverseNode(self.blend_att) for shp in self.fk0_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) for shp in self.fk0_roll_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) for shp in self.fk1_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) for shp in self.fk1_roll_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) fkvis2_node = node.createReverseNode(self.blend2_att) for shp in self.fk2_ctl.getShapes(): pm.connectAttr(fkvis2_node + ".outputX", shp.attr("visibility")) # ik for shp in self.upv_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ikcns_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ik_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.line_ref.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) # jnt ctl for ctl in (self.div_ctls): for shp in ctl.getShapes(): pm.connectAttr(self.jntctl_vis_att, shp.attr("visibility")) # Controls ROT order ----------------------------------- attribute.setRotOrder(self.fk0_ctl, "YZX") attribute.setRotOrder(self.fk1_ctl, "XYZ") attribute.setRotOrder(self.fk2_ctl, "YZX") attribute.setRotOrder(self.ik_ctl, "XYZ") # IK Solver ----------------------------------------- out = [self.bone0, self.bone1, self.ctrn_loc, self.eff_npo] o_node = applyop.gear_ikfk2bone_op(out, self.root, self.ik_ref, self.upv_ctl, self.fk0_mtx, self.fk1_mtx, self.fk2_mtx, self.length0, self.length1, self.negate) pm.connectAttr(self.blend_att, o_node + ".blend") pm.connectAttr(self.roll_att, o_node + ".roll") pm.connectAttr(self.scale_att, o_node + ".scaleA") pm.connectAttr(self.scale_att, o_node + ".scaleB") pm.connectAttr(self.maxstretch_att, o_node + ".maxstretch") pm.connectAttr(self.slide_att, o_node + ".slide") pm.connectAttr(self.softness_att, o_node + ".softness") pm.connectAttr(self.reverse_att, o_node + ".reverse") # update issue on effector scale interpol, disconnect for stability pm.disconnectAttr(self.eff_npo.scale) # auto upvector ------------------------------------- if self.negate: o_node = applyop.aimCns(self.upv_auv, self.ik_ctl, axis="-xy", wupType=4, wupVector=[0, 1, 0], wupObject=self.upv_auv, maintainOffset=False) else: o_node = applyop.aimCns(self.upv_auv, self.ik_ctl, axis="xy", wupType=4, wupVector=[0, 1, 0], wupObject=self.upv_auv, maintainOffset=False) o_node = applyop.gear_mulmatrix_op( self.upv_auv.attr("worldMatrix"), self.upv_mtx.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") pb_node = pm.createNode("pairBlend") pb_node.attr("rotInterpolation").set(1) pm.connectAttr(dm_node + ".outputTranslate", pb_node + ".inTranslate2") pm.connectAttr(dm_node + ".outputRotate", pb_node + ".inRotate2") pm.connectAttr(pb_node + ".outRotate", self.upv_mtx.attr("rotate")) pm.connectAttr(pb_node + ".outTranslate", self.upv_mtx.attr("translate")) pm.connectAttr(self.auv_att, pb_node + ".weight") # fk0 mtx connection o_node = applyop.gear_mulmatrix_op( self.fk0_roll_ctl.attr("worldMatrix"), self.fk0_mtx.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputTranslate", self.fk0_mtx.attr("translate")) pm.connectAttr(dm_node + ".outputRotate", self.fk0_mtx.attr("rotate")) # fk1 loc connect to fk1 ref @ pos and rot, not scl to avoid shearing o_node = applyop.gear_mulmatrix_op( self.fk1_ref.attr("worldMatrix"), self.fk1_loc.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputTranslate", self.fk1_loc.attr("translate")) pm.connectAttr(dm_node + ".outputRotate", self.fk1_loc.attr("rotate")) # fk1 mtx orient cns to fk1 roll pm.connectAttr(self.fk1_roll_ctl.attr("rotate"), self.fk1_mtx.attr("rotate")) # fk2_loc position constraint to effector------------------------ o_node = applyop.gear_mulmatrix_op( self.eff_npo.attr("worldMatrix"), self.fk2_loc.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputTranslate", self.fk2_loc.attr("translate")) # fk2_loc rotation constraint to bone1 (bugfixed) -------------- o_node = applyop.gear_mulmatrix_op( self.bone1.attr("worldMatrix"), self.fk2_loc.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputRotate", self.fk2_loc.attr("rotate")) # hand ikfk blending from fk ref to ik ref (serious bugfix)-------- o_node = applyop.gear_mulmatrix_op( self.fk_ref.attr("worldMatrix"), self.eff_loc.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pb_node = pm.createNode("pairBlend") pb_node.attr("rotInterpolation").set(1) pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputRotate", pb_node + ".inRotate1") pm.connectAttr(self.blend2_att, pb_node + ".weight") pm.connectAttr(pb_node + ".outRotate", self.eff_loc.attr("rotate")) o_node = applyop.gear_mulmatrix_op( self.ik_ref.attr("worldMatrix"), self.eff_loc.attr("parentInverseMatrix")) dm_node1 = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node1 + ".inputMatrix") pm.connectAttr(dm_node1 + ".outputRotate", pb_node + ".inRotate2") # use blendcolors to blend scale bc_node = pm.createNode("blendColors") pm.connectAttr(self.blend_att, bc_node + ".blender") pm.connectAttr(dm_node + ".outputScale", bc_node + ".color2") pm.connectAttr(dm_node1 + ".outputScale", bc_node + ".color1") pm.connectAttr(bc_node + ".output", self.eff_loc.attr("scale")) # Twist references --------------------------------- pm.connectAttr(self.mid_ctl.attr("translate"), self.tws1_npo.attr("translate")) pm.connectAttr(self.mid_ctl.attr("rotate"), self.tws1_npo.attr("rotate")) pm.connectAttr(self.mid_ctl.attr("scale"), self.tws1_npo.attr("scale")) o_node = applyop.gear_mulmatrix_op( self.eff_loc.attr("worldMatrix"), self.tws3_npo.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputTranslate", self.tws3_npo.attr("translate")) pm.connectAttr(dm_node + ".outputRotate", self.tws3_npo.attr("rotate")) attribute.setRotOrder(self.tws3_rot, "XYZ") # elbow thickness connection if self.negate: o_node = node.createMulNode( [self.elbow_thickness_att, self.elbow_thickness_att], [0.5, -0.5, 0], [self.tws1_loc + ".translateX", self.tws2_loc + ".translateX"]) else: o_node = node.createMulNode( [self.elbow_thickness_att, self.elbow_thickness_att], [-0.5, 0.5, 0], [self.tws1_loc + ".translateX", self.tws2_loc + ".translateX"]) # connect both tws1 and tws2 (mid tws) self.tws0_rot.setAttr("sx", .001) self.tws3_rot.setAttr("sx", .001) add_node = node.createAddNode(self.roundness0_att, .001) pm.connectAttr(add_node + ".output", self.tws1_rot.attr("sx")) add_node = node.createAddNode(self.roundness1_att, .001) pm.connectAttr(add_node + ".output", self.tws2_rot.attr("sx")) pm.connectAttr(self.armpit_roll_att, self.tws0_rot + ".rotateX") # Roll Shoulder--use aimconstraint withour uovwctor to solve # the stable twist if self.negate: o_node = applyop.aimCns(self.tws0_loc, self.mid_ctl, axis="-xy", wupType=4, wupVector=[0, 1, 0], wupObject=self.tws0_npo, maintainOffset=False) else: o_node = applyop.aimCns(self.tws0_loc, self.mid_ctl, axis="xy", wupType=4, wupVector=[0, 1, 0], wupObject=self.tws0_npo, maintainOffset=False) # Volume ------------------------------------------- distA_node = node.createDistNode(self.tws0_loc, self.tws1_npo) distB_node = node.createDistNode(self.tws1_npo, self.tws3_loc) add_node = node.createAddNode(distA_node + ".distance", distB_node + ".distance") div_node = node.createDivNode(add_node + ".output", self.root.attr("sx")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(self.root.attr("worldMatrix"), dm_node + ".inputMatrix") div_node2 = node.createDivNode(div_node + ".outputX", dm_node + ".outputScaleX") self.volDriver_att = div_node2 + ".outputX" # Divisions ---------------------------------------- # div mid constraint to mid ctl o_node = applyop.gear_mulmatrix_op( self.mid_ctl.attr("worldMatrix"), self.div_mid.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputTranslate", self.div_mid.attr("translate")) pm.connectAttr(dm_node + ".outputRotate", self.div_mid.attr("rotate")) # at 0 or 1 the division will follow exactly the rotation of the # controler.. and we wont have this nice tangent + roll # linear scaling percentage (1) to effector (2) to elbow scl_1_perc = [] scl_2_perc = [] for i, div_cnsUp in enumerate(self.div_cnsUp): if i < (self.settings["div0"] + 1): perc = i / (self.settings["div0"] + 1.0) elif i < (self.settings["div0"] + 2): perc = .95 perc = max(.001, min(.99, perc)) # Roll if self.negate: o_node = applyop.gear_rollsplinekine_op( div_cnsUp, [self.tws1_rot, self.tws0_rot], 1 - perc, 20) else: o_node = applyop.gear_rollsplinekine_op( div_cnsUp, [self.tws0_rot, self.tws1_rot], perc, 20) pm.connectAttr(self.resample_att, o_node + ".resample") pm.connectAttr(self.absolute_att, o_node + ".absolute") scl_1_perc.append(perc / 2) scl_2_perc.append(perc) scl_1_perc.append(0.5) scl_2_perc.append(1) for i, div_cnsDn in enumerate(self.div_cnsDn): if i == (0): perc = .05 elif i < (self.settings["div1"] + 1): perc = i / (self.settings["div1"] + 1.0) elif i < (self.settings["div1"] + 2): perc = .95 perc = max(.001, min(.990, perc)) # Roll if self.negate: o_node = applyop.gear_rollsplinekine_op( div_cnsDn, [self.tws3_rot, self.tws2_rot], 1 - perc, 20) else: o_node = applyop.gear_rollsplinekine_op( div_cnsDn, [self.tws2_rot, self.tws3_rot], perc, 20) pm.connectAttr(self.resample_att, o_node + ".resample") pm.connectAttr(self.absolute_att, o_node + ".absolute") scl_1_perc.append(perc / 2 + 0.5) scl_2_perc.append(1 - perc) # Squash n Stretch for i, div_cns in enumerate(self.div_cns): o_node = applyop.gear_squashstretch2_op( div_cns, None, pm.getAttr(self.volDriver_att), "x") pm.connectAttr(self.volume_att, o_node + ".blend") pm.connectAttr(self.volDriver_att, o_node + ".driver") pm.connectAttr(self.st_att[i], o_node + ".stretch") pm.connectAttr(self.sq_att[i], o_node + ".squash") # get the first mult_node after sq op mult_node = pm.listHistory(o_node, future=True)[1] # linear blend effector scale bc_node = pm.createNode("blendColors") bc_node.setAttr("color2R", 1) bc_node.setAttr("color2G", 1) bc_node.setAttr("blender", scl_1_perc[i]) pm.connectAttr(self.eff_loc.attr("scale"), bc_node + ".color1") # linear blend mid scale bc_node2 = pm.createNode("blendColors") bc_node2.setAttr("color2R", 1) bc_node2.setAttr("color2G", 1) bc_node2.setAttr("blender", scl_2_perc[i]) pm.connectAttr(self.mid_ctl.attr("scale"), bc_node2 + ".color1") # mid_ctl scale * effector scale mult_node2 = pm.createNode("multiplyDivide") pm.connectAttr(bc_node2 + ".output", mult_node2 + ".input1") pm.connectAttr(bc_node + ".output", mult_node2 + ".input2") # plug to sq scale pm.connectAttr(mult_node2 + ".output", mult_node + ".input2") # match IK/FK ref pm.connectAttr(self.bone0.attr("rotate"), self.match_fk0.attr("rotate")) pm.connectAttr(self.bone0.attr("translate"), self.match_fk0.attr("translate")) pm.connectAttr(self.bone1.attr("rotate"), self.match_fk1.attr("rotate")) pm.connectAttr(self.bone1.attr("translate"), self.match_fk1.attr("translate")) return
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. """ # 1 bone chain Upv ref ============================================== self.ikHandleUpvRef = primitive.addIkHandle( self.root, self.getName("ikHandleArmChainUpvRef"), self.armChainUpvRef, "ikSCsolver") pm.pointConstraint(self.ik_ctl, self.ikHandleUpvRef) pm.parentConstraint(self.armChainUpvRef[0], self.upv_cns, mo=True) # Visibilities ------------------------------------- # fk fkvis_node = node.createReverseNode(self.blend_att) for shp in self.fk0_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) for shp in self.fk1_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) for shp in self.fk2_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) # ik for shp in self.upv_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ikcns_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ik_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.line_ref.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) if self.settings["ikTR"]: for shp in self.ikRot_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) # Controls ROT order ----------------------------------- attribute.setRotOrder(self.fk0_ctl, "XZY") attribute.setRotOrder(self.fk1_ctl, "XYZ") attribute.setRotOrder(self.fk2_ctl, "YZX") attribute.setRotOrder(self.ik_ctl, "XYZ") # IK Solver ----------------------------------------- out = [self.bone0, self.bone1, self.ctrn_loc, self.eff_loc] o_node = applyop.gear_ikfk2bone_op(out, self.root, self.ik_ref, self.upv_ctl, self.fk_ctl[0], self.fk_ctl[1], self.fk_ref, self.length0, self.length1, self.negate) if self.settings["ikTR"]: # connect the control inputs outEff_dm = o_node.listConnections(c=True)[-1][1] inAttr = self.ikRot_npo.attr("translate") outEff_dm.attr("outputTranslate") >> inAttr outEff_dm.attr("outputScale") >> self.ikRot_npo.attr("scale") dm_node = node.createDecomposeMatrixNode(o_node.attr("outB")) dm_node.attr("outputRotate") >> self.ikRot_npo.attr("rotate") # rotation mulM_node = applyop.gear_mulmatrix_op( self.ikRot_ctl.attr("worldMatrix"), self.eff_loc.attr("parentInverseMatrix")) intM_node = applyop.gear_intmatrix_op(o_node.attr("outEff"), mulM_node.attr("output"), o_node.attr("blend")) dm_node = node.createDecomposeMatrixNode(intM_node.attr("output")) dm_node.attr("outputRotate") >> self.eff_loc.attr("rotate") transform.matchWorldTransform(self.fk2_ctl, self.ikRot_cns) # scale: this fix the scalin popping issue intM_node = applyop.gear_intmatrix_op( self.fk2_ctl.attr("worldMatrix"), self.ik_ctl_ref.attr("worldMatrix"), o_node.attr("blend")) mulM_node = applyop.gear_mulmatrix_op( intM_node.attr("output"), self.eff_loc.attr("parentInverseMatrix")) dm_node = node.createDecomposeMatrixNode(mulM_node.attr("output")) dm_node.attr("outputScale") >> self.eff_loc.attr("scale") pm.connectAttr(self.blend_att, o_node + ".blend") if self.negate: mulVal = -1 else: mulVal = 1 node.createMulNode(self.roll_att, mulVal, o_node + ".roll") pm.connectAttr(self.scale_att, o_node + ".scaleA") pm.connectAttr(self.scale_att, o_node + ".scaleB") pm.connectAttr(self.maxstretch_att, o_node + ".maxstretch") pm.connectAttr(self.slide_att, o_node + ".slide") pm.connectAttr(self.softness_att, o_node + ".softness") pm.connectAttr(self.reverse_att, o_node + ".reverse") # Twist references --------------------------------- pm.pointConstraint(self.mid_ctl_twst_ref, self.tws1_npo, maintainOffset=False) pm.connectAttr(self.mid_ctl.scaleX, self.tws1_loc.scaleX) pm.orientConstraint(self.mid_ctl_twst_ref, self.tws1_npo, maintainOffset=False) o_node = applyop.gear_mulmatrix_op( self.eff_loc.attr("worldMatrix"), self.root.attr("worldInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputTranslate", self.tws2_npo.attr("translate")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputRotate", self.tws2_npo.attr("rotate")) o_node = applyop.gear_mulmatrix_op( self.eff_loc.attr("worldMatrix"), self.tws2_rot.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") attribute.setRotOrder(self.tws2_rot, "XYZ") pm.connectAttr(dm_node + ".outputRotate", self.tws2_rot + ".rotate") self.tws0_rot.setAttr("sx", .001) self.tws2_rot.setAttr("sx", .001) add_node = node.createAddNode(self.roundness_att, .001) pm.connectAttr(add_node + ".output", self.tws1_rot.attr("sx")) pm.connectAttr(self.armpit_roll_att, self.tws0_rot + ".rotateX") # Roll Shoulder applyop.splineIK(self.getName("rollRef"), self.rollRef, parent=self.root, cParent=self.bone0) # Volume ------------------------------------------- distA_node = node.createDistNode(self.tws0_loc, self.tws1_loc) distB_node = node.createDistNode(self.tws1_loc, self.tws2_loc) add_node = node.createAddNode(distA_node + ".distance", distB_node + ".distance") div_node = node.createDivNode(add_node + ".output", self.root.attr("sx")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(self.root.attr("worldMatrix"), dm_node + ".inputMatrix") div_node2 = node.createDivNode(div_node + ".outputX", dm_node + ".outputScaleX") self.volDriver_att = div_node2 + ".outputX" if self.settings["extraTweak"]: for tweak_ctl in self.tweak_ctl: for shp in tweak_ctl.getShapes(): pm.connectAttr(self.tweakVis_att, shp.attr("visibility")) # Divisions ---------------------------------------- # at 0 or 1 the division will follow exactly the rotation of the # controler.. and we wont have this nice tangent + roll for i, div_cns in enumerate(self.div_cns): if self.settings["supportJoints"]: if i < (self.settings["div0"] + 1): perc = i * .5 / (self.settings["div0"] + 1.0) elif i < (self.settings["div0"] + 2): perc = .49 elif i < (self.settings["div0"] + 3): perc = .50 elif i < (self.settings["div0"] + 4): perc = .51 else: perc = .5 + \ (i - self.settings["div0"] - 3.0) * .5 / \ (self.settings["div1"] + 1.0) else: if i < (self.settings["div0"] + 1): perc = i * .5 / (self.settings["div0"] + 1.0) elif i < (self.settings["div0"] + 2): perc = .501 else: perc = .5 + \ (i - self.settings["div0"] - 1.0) * .5 / \ (self.settings["div1"] + 1.0) perc = max(.001, min(.990, perc)) # Roll if self.negate: o_node = applyop.gear_rollsplinekine_op( div_cns, [self.tws2_rot, self.tws1_rot, self.tws0_rot], 1.0 - perc, 40) else: o_node = applyop.gear_rollsplinekine_op( div_cns, [self.tws0_rot, self.tws1_rot, self.tws2_rot], perc, 40) pm.connectAttr(self.resample_att, o_node + ".resample") pm.connectAttr(self.absolute_att, o_node + ".absolute") # Squash n Stretch o_node = applyop.gear_squashstretch2_op( div_cns, None, pm.getAttr(self.volDriver_att), "x") pm.connectAttr(self.volume_att, o_node + ".blend") pm.connectAttr(self.volDriver_att, o_node + ".driver") pm.connectAttr(self.st_att[i], o_node + ".stretch") pm.connectAttr(self.sq_att[i], o_node + ".squash") # match IK/FK ref pm.parentConstraint(self.bone0, self.match_fk0_off, mo=True) pm.parentConstraint(self.bone1, self.match_fk1_off, mo=True) if self.settings["ikTR"]: transform.matchWorldTransform(self.ikRot_ctl, self.match_ikRot) transform.matchWorldTransform(self.fk_ctl[2], self.match_fk2) return
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[0], self.guide.apos[-1]) 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 ----------------------------------------- for i in range(self.settings["division"]): # References u = i / (self.settings["division"] - 1.0) if i == 0: # we add extra 10% to the first vertebra u = (1.0 / (self.settings["division"] - 1.0)) / 10 cns = applyop.pathCns(self.div_cns[i], self.slv_crv, False, u, 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") # Connections (Hooks) ------------------------------ pm.parentConstraint(self.hip_lvl, self.cnx0) pm.scaleConstraint(self.hip_lvl, self.cnx0) pm.parentConstraint(self.scl_transforms[-1], self.cnx1) pm.scaleConstraint(self.scl_transforms[-1], self.cnx1)
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)