def spaceJump(ref=None, space=None, *args): """ 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 = pri.addTransform(ref, ref.name()+"_SPACE_"+space.name(), space.getMatrix(worldSpace=True)) spaceLocal = pri.addTransform(space, ref.name()+"_JUMP_"+space.name(), space.getMatrix(worldSpace=True)) aop.gear_mulmatrix_op(refLocal.attr("worldMatrix"), spaceLocal.attr("parentInverseMatrix[0]"), spaceLocal) pm.displayInfo("Jump Space for local space: " + space.name() + "created") return spaceLocal
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 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 = aop.gear_intmatrix_op(refA.attr("worldMatrix"), refB.attr("worldMatrix"), blend) intTrans = pri.addTransform(refA, refA.name()+"_INTER_"+refB.name(), dt.Matrix()) aop.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 addOperators(self): aim_base = aop.aimCns(self.ref_base, self.tip_ctl, axis="yx", wupType=2, wupVector=[1, 0, 0], wupObject=self.ctl, maintainOffset=False) aim_tip = aop.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 = aop.gear_intmatrix_op( self.ref_base.attr("worldMatrix"), self.ref_tip.attr("worldMatrix"), blend) aop.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. """ 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/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 _createSoftModTweak(baseCtl, tweakCtl, name, targets): sm = pm.softMod(targets, wn=[tweakCtl, tweakCtl]) pm.rename(sm[0], "{}_softMod".format(name)) # 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) 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) attribute.addAttribute(sm[0], "_isSoftTweak", "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")) return sm[0]
def addOperators(self): if self.negate: node = aop.aimCns(self.mtx, self.end, axis="-xy", wupType=4, wupVector=[0, 1, 0], wupObject=self.mtx, maintainOffset=False) else: node = aop.aimCns(self.mtx, self.end, axis="xy", wupType=4, wupVector=[0, 1, 0], wupObject=self.mtx, maintainOffset=False) # position constrint loc to ref node = aop.gear_mulmatrix_op(self.end.attr("worldMatrix"), self.loc.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(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")) 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. """ 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 addOperators(self): aop.aimCns(self.ref_base, self.squash_ctl, axis="yx", wupType=2, wupVector=[1, 0, 0], wupObject=self.ctl, maintainOffset=False) aop.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 = aop.gear_intmatrix_op( self.ref_base.attr("worldMatrix"), self.ref_squash.attr("worldMatrix"), blend) aop.gear_mulmatrix_op(intMatrix.attr("output"), div_cns.attr("parentInverseMatrix[0]"), div_cns) blend = blend + bIncrement d = vec.getDistance(self.guide.apos[0], self.guide.apos[1]) dist_node = nod.createDistNode(self.squash_ctl, self.ctl) rootWorld_node = nod.createDecomposeMatrixNode( self.ctl.attr("worldMatrix")) div_node = nod.createDivNode(dist_node + ".distance", rootWorld_node + ".outputScaleY") div_node = nod.createDivNode(div_node + ".outputX", d) rev_node = nod.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 createInterpolateTransform(*args): """ Create space locator and apply gear_intmatrix_op, to interpolate the his pose between 2 selected objects. """ if len(pm.selected()) == 2: refA = pm.selected()[0] refB = pm.selected()[1] intMatrix = aop.gear_intmatrix_op(refA.attr("worldMatrix"), refB.attr("worldMatrix"), .5) intTrans = pri.addTransform(refA, refA.name() + "_INTER_" + refB.name(), dt.Matrix()) aop.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. ")
def addShadow(self, obj, name): if self.options["shadow_rig"]: shd = pri.addJoint(self.shd_org, self.getName(str(name)+"_shd"), tra.getTransform(obj)) shd.setAttr("jointOrient", 0, 0, 0) # parentConstraint(obj, shd, maintainOffset=False) # scaleConstraint(obj, shd, maintainOffset=False) mulmat_node = aop.gear_mulmatrix_op(obj+".worldMatrix", shd+".parentInverseMatrix") dm_node = nod.createDecomposeMatrixNode(mulmat_node+".output") connectAttr(dm_node+".outputTranslate", shd+".t") connectAttr(dm_node+".outputRotate", shd+".r") connectAttr(dm_node+".outputScale", shd+".s") self.shd_org = shd else: shd = pri.addJoint(obj, self.getName(str(name)+"_shd"), tra.getTransform(obj)) shd.setAttr("jointOrient", 0, 0, 0) shd.setAttr("rotate", 0, 0, 0) connectAttr(self.rig.shdVis_att, shd.attr("visibility")) self.addToGroup(shd, "deformers") return shd
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")) 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 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) 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 - 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): # Visibilities ------------------------------------- # fk fkvis_node = nod.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")) fkvis2_node = nod.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")) # Controls ROT order ----------------------------------- att.setRotOrder(self.fk0_ctl, "YZX") att.setRotOrder(self.fk0_roll_ctl, "YZX") att.setRotOrder(self.fk1_ctl, "XYZ") att.setRotOrder(self.fk2_ctl, "YZX") # att.setRotOrder(self.ik_ctl, "ZYX") att.setRotOrder(self.ik_ctl, "XYZ") # IK Solver ----------------------------------------- out = [self.bone0, self.bone1, self.ctrn_loc, self.eff_npo] #self.fk_ctl = [self.fk0_roll_ctl, self.fk1_ctl, self.fk2_mtx] node = aop.gear_ikfk2bone_op(out, self.root, self.ik_ref, self.upv_ctl, self.fk_ctl[0], self.fk_ctl[1], self.fk2_mtx, self.length0, self.length1, self.negate) pm.connectAttr(self.blend_att, node + ".blend") pm.connectAttr(self.roll_att, node + ".roll") pm.connectAttr(self.scale_att, node + ".scaleA") pm.connectAttr(self.scale_att, node + ".scaleB") pm.connectAttr(self.maxstretch_att, node + ".maxstretch") pm.connectAttr(self.slide_att, node + ".slide") pm.connectAttr(self.softness_att, node + ".softness") pm.connectAttr(self.reverse_att, node + ".reverse") # auto upvector ------------------------------------- if self.negate: node = aop.aimCns(self.upv_auv, self.ik_ctl, axis="-xy", wupType=4, wupVector=[0, 1, 0], wupObject=self.upv_auv, maintainOffset=False) else: node = aop.aimCns(self.upv_auv, self.ik_ctl, axis="xy", wupType=4, wupVector=[0, 1, 0], wupObject=self.upv_auv, maintainOffset=False) pb_node = pm.createNode("pairBlend") pb_node.attr("rotInterpolation").set(1) pm.connectAttr(self.upv_auv.attr("rotate"), pb_node + ".inRotate2") pm.connectAttr(pb_node + ".outRotate", self.upv_mtx.attr("rotate")) pm.connectAttr(self.auv_att, pb_node + ".weight") # fk2_npo position constraint to effector------------------------ node = aop.gear_mulmatrix_op(self.eff_npo.attr("worldMatrix"), self.fk2_npo.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputTranslate", self.fk2_npo.attr("translate")) # fk2_npo rotation constraint to bone1 (bugfixed) ------------------------ node = aop.gear_mulmatrix_op(self.bone1.attr("worldMatrix"), self.fk2_npo.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputRotate", self.fk2_npo.attr("rotate")) # hand ikfk blending from fk ref to ik ref (serious bugfix)-------------------------------- node = aop.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(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")) node = aop.gear_mulmatrix_op(self.ik_ref.attr("worldMatrix"), self.eff_loc.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputRotate", pb_node + ".inRotate2") # Twist references --------------------------------- node = aop.gear_mulmatrix_op(self.mid_ctl.attr("worldMatrix"), self.tws1_npo.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputTranslate", self.tws1_npo.attr("translate")) pm.connectAttr(dm_node + ".outputRotate", self.tws1_npo.attr("rotate")) pm.connectAttr(dm_node + ".outputScale", self.tws1_npo.attr("scale")) node = aop.gear_mulmatrix_op(self.eff_loc.attr("worldMatrix"), self.tws2_npo.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputTranslate", self.tws2_npo.attr("translate")) pm.connectAttr(dm_node + ".outputRotate", self.tws2_npo.attr("rotate")) # orientConstraint(self.eff_loc, self.tws2_rot, maintainOffset=False) node = aop.gear_mulmatrix_op(self.eff_loc.attr("worldMatrix"), self.tws2_rot.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(node + ".output", dm_node + ".inputMatrix") att.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 = nod.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--use aimconstraint withour uovwctor to solve the stable twist if self.negate: node = aop.aimCns(self.tws0_loc, self.mid_ctl, axis="-xy", wupType=4, wupVector=[0, 1, 0], wupObject=self.tws0_npo, maintainOffset=False) else: node = aop.aimCns(self.tws0_loc, self.mid_ctl, axis="xy", wupType=4, wupVector=[0, 1, 0], wupObject=self.tws0_npo, maintainOffset=False) # Volume ------------------------------------------- distA_node = nod.createDistNode(self.tws0_loc, self.tws1_loc) distB_node = nod.createDistNode(self.tws1_loc, self.tws2_loc) add_node = nod.createAddNode(distA_node + ".distance", distB_node + ".distance") div_node = nod.createDivNode(add_node + ".output", self.root.attr("sx")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(self.root.attr("worldMatrix"), dm_node + ".inputMatrix") div_node2 = nod.createDivNode(div_node + ".outputX", dm_node + ".outputScaleX") self.volDriver_att = div_node2 + ".outputX" # 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"] + 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) perc = max(.001, min(.990, perc)) # Roll if self.negate: node = aop.gear_rollsplinekine_op( div_cns, [self.tws2_rot, self.tws1_rot, self.tws0_rot], 1 - perc, 40) else: node = aop.gear_rollsplinekine_op( div_cns, [self.tws0_rot, self.tws1_rot, self.tws2_rot], perc, 40) pm.connectAttr(self.resample_att, node + ".resample") pm.connectAttr(self.absolute_att, node + ".absolute") # Squash n Stretch node = aop.gear_squashstretch2_op(div_cns, None, pm.getAttr(self.volDriver_att), "x") pm.connectAttr(self.volume_att, node + ".blend") pm.connectAttr(self.volDriver_att, node + ".driver") pm.connectAttr(self.st_att[i], node + ".stretch") pm.connectAttr(self.sq_att[i], 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) 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. """ # 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")) # 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 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. """ if self.options["joint_rig"]: if newActiveJnt: self.active_jnt = newActiveJnt jnt = primitive.addJoint(self.active_jnt, self.getName(str(name) + "_jnt"), transform.getTransform(obj)) # TODO: Set the joint to have always positive scaling # jnt.scale.set([1, 1, 1]) # 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 UniScale: pm.connectAttr(dm_node + ".outputScaleZ", jnt + ".sx") pm.connectAttr(dm_node + ".outputScaleZ", jnt + ".sy") pm.connectAttr(dm_node + ".outputScaleZ", jnt + ".sz") else: pm.connectAttr(dm_node + ".outputScale", jnt + ".s") 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 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, 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. """ # 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) 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.scl_transforms[0], self.cnx0) pm.scaleConstraint(self.scl_transforms[0], self.cnx0) pm.parentConstraint(self.scl_transforms[-1], self.cnx1) pm.scaleConstraint(self.scl_transforms[-1], self.cnx1)
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: parentGroup = pm.createNode("transform", n="ProxyGeo") try: proxySet = pm.PyNode("rig_proxyGeo_grp") except: 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)) tra.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") mulmat_node = aop.gear_mulmatrix_op( pm.PyNode(oColl[faceGroups.index(boneList)]).name() + ".worldMatrix", newObj[0].name() + ".parentInverseMatrix") dm_node = nod.createDecomposeMatrixNode(mulmat_node + ".output") 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: " + 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 _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) 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): # Visibilities ------------------------------------- # fk fkvis_node = nod.createReverseNode(self.blend_att) for shp in self.fk0_ctl.getShapes(): connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) for shp in self.fk1_ctl.getShapes(): connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) for shp in self.fk2_ctl.getShapes(): connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) # ik for shp in self.upv_ctl.getShapes(): connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ikcns_ctl.getShapes(): connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ik_ctl.getShapes(): connectAttr(self.blend_att, shp.attr("visibility")) # IK Solver ----------------------------------------- out = [self.bone0, self.bone1, self.ctrn_loc, self.eff_loc] node = aop.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) connectAttr(self.blend_att, node + ".blend") connectAttr(self.roll_att, node + ".roll") connectAttr(self.scale_att, node + ".scaleA") connectAttr(self.scale_att, node + ".scaleB") connectAttr(self.maxstretch_att, node + ".maxstretch") connectAttr(self.slide_att, node + ".slide") connectAttr(self.softness_att, node + ".softness") connectAttr(self.reverse_att, node + ".reverse") # Twist references --------------------------------- pointConstraint(self.root, self.tws0_loc, maintainOffset=True) aop.aimCns(self.tws0_loc, self.mid_ctl, self.n_sign + "xz", 2, [0, 1, 0], self.root, False) pointConstraint(self.mid_ctl, self.tws1_loc, maintainOffset=False) scaleConstraint(self.mid_ctl, self.tws1_loc, maintainOffset=False) orientConstraint(self.mid_ctl, self.tws1_rot, maintainOffset=False) pointConstraint(self.eff_loc, self.tws2_loc, maintainOffset=False) scaleConstraint(self.eff_loc, self.tws2_loc, maintainOffset=False) orientConstraint(self.bone1, self.tws2_loc, maintainOffset=False) # orientConstraint(self.eff_loc, self.tws2_rot, maintainOffset=False) node = aop.gear_mulmatrix_op(self.eff_loc.attr("worldMatrix"), self.tws2_rot.attr("parentInverseMatrix")) dm_node = createNode("decomposeMatrix") connectAttr(node + ".output", dm_node + ".inputMatrix") connectAttr(dm_node + ".outputRotate", self.tws2_rot + ".rotate") # att.setRotOrder(self.tws2_rot, "YZX") self.tws0_loc.setAttr("sx", .001) self.tws2_loc.setAttr("sx", .001) add_node = nod.createAddNode(self.roundness_att, .001) connectAttr(add_node + ".output", self.tws1_rot.attr("sx")) # Volume ------------------------------------------- distA_node = nod.createDistNode(self.tws0_loc, self.tws1_loc) distB_node = nod.createDistNode(self.tws1_loc, self.tws2_loc) add_node = nod.createAddNode(distA_node + ".distance", distB_node + ".distance") div_node = nod.createDivNode(add_node + ".output", self.root.attr("sx")) self.volDriver_att = div_node + ".outputX" # 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"] + 1): perc = i * .5 / (self.settings["div0"] + 1.0) else: perc = .5 + (i - self.settings["div0"] - 1.0) * .5 / (self.settings["div1"] + 1.0) perc = max(.001, min(.999, perc)) # Roll if self.negate: node = aop.gear_rollsplinekine_op( div_cns, [self.tws2_rot, self.tws1_rot, self.tws0_rot], 1 - perc) else: node = aop.gear_rollsplinekine_op( div_cns, [self.tws0_rot, self.tws1_rot, self.tws2_rot], perc) connectAttr(self.resample_att, node + ".resample") connectAttr(self.absolute_att, node + ".absolute") # Squash n Stretch node = aop.gear_squashstretch2_op(div_cns, None, getAttr(self.volDriver_att), "x") connectAttr(self.volume_att, node + ".blend") connectAttr(self.volDriver_att, node + ".driver") connectAttr(self.st_att[i], node + ".stretch") connectAttr(self.sq_att[i], node + ".squash") return
def addOperators(self): # Tangent position --------------------------------- # common part d = vec.getDistance(self.guide.apos[0], self.guide.apos[1]) dist_node = nod.createDistNode(self.ik0_ctl, self.ik1_ctl) rootWorld_node = nod.createDecomposeMatrixNode(self.root.attr("worldMatrix")) div_node = nod.createDivNode(dist_node+".distance", rootWorld_node+".outputScaleX") div_node = nod.createDivNode(div_node+".outputX", d) # tan0 mul_node = nod.createMulNode(self.tan0_att, self.tan0_npo.getAttr("ty")) res_node = nod.createMulNode(mul_node+".outputX", div_node+".outputX") pm.connectAttr( res_node+".outputX", self.tan0_npo.attr("ty")) # tan1 mul_node = nod.createMulNode(self.tan1_att, self.tan1_npo.getAttr("ty")) res_node = nod.createMulNode(mul_node+".outputX", div_node+".outputX") pm.connectAttr( res_node+".outputX", self.tan1_npo.attr("ty")) # Curves ------------------------------------------- op = aop.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 = nod.createCurveInfoNode(self.slv_crv) # Division ----------------------------------------- for i in range(self.settings["division"]): # References u = i / (self.settings["division"] - 1.0) cns = aop.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 = aop.gear_intmatrix_op(self.ik0_ctl+".worldMatrix", self.ik1_ctl+".worldMatrix", u) dm_node = nod.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 = aop.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") # scl compensation if i == 0: dm_node = nod.createDecomposeMatrixNode(self.root+".worldMatrix") div_node = nod.createDivNode([1,1,1], [dm_node+".outputScaleX", dm_node+".outputScaleY", dm_node+".outputScaleZ"]) pm.connectAttr(div_node+".output", self.scl_npo[i]+".scale") elif i == 1: div_node = nod.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") else: div_node = nod.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 = aop.gear_mulmatrix_op(self.div_cns[i].attr("worldMatrix"), self.scl_npo[0].attr("worldInverseMatrix")) else: mulmat_node = aop.gear_mulmatrix_op(self.div_cns[i].attr("worldMatrix"), self.div_cns[i - 1].attr("worldInverseMatrix")) dm_node = nod.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 == 0 : dm_node = nod.createDecomposeMatrixNode(self.ik0_ctl+".worldMatrix") blend_node = nod.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 = nod.createDecomposeMatrixNode(self.ik1_ctl+".worldMatrix") blend_node = nod.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.pointConstraint(self.div_cns[0], self.cnx0) pm.orientConstraint(self.div_cns[0], self.cnx0) pm.pointConstraint(self.fk_ctl[-1], self.cnx1) pm.orientConstraint(self.fk_ctl[-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. """ # 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 addJoint(self, obj, name, newActiveJnt=None, UniScale=True, 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 False will 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. """ if self.options["joint_rig"]: if newActiveJnt: self.active_jnt = newActiveJnt jnt = pri.addJoint(self.active_jnt, self.getName(str(name) + "_jnt"), tra.getTransform(obj)) #All new jnts are the active by default self.active_jnt = jnt if gearMulMatrix: mulmat_node = aop.gear_mulmatrix_op( obj + ".worldMatrix", jnt + ".parentInverseMatrix") dm_node = nod.createDecomposeMatrixNode(mulmat_node + ".output") m = mulmat_node.attr('output').get() else: mulmat_node = nod.createMultMatrixNode( obj + ".worldMatrix", jnt + ".parentInverseMatrix") dm_node = nod.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 UniScale: pm.connectAttr(dm_node + ".outputScaleZ", jnt + ".sx") pm.connectAttr(dm_node + ".outputScaleZ", jnt + ".sy") pm.connectAttr(dm_node + ".outputScaleZ", jnt + ".sz") else: pm.connectAttr(dm_node + ".outputScale", jnt + ".s") 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: aop.gear_mulmatrix_op(mulmat_node.attr('output'), im, jnt, 'r') else: nod.createMultMatrixNode(mulmat_node.attr('matrixSum'), im, jnt, 'r') else: jnt = pri.addJoint(obj, self.getName(str(name) + "_jnt"), tra.getTransform(obj)) pm.connectAttr(self.rig.jntVis_att, jnt.attr("visibility")) self.addToGroup(jnt, "deformers") return jnt
def addOperators(self): # Tangent position --------------------------------- # common part d = vec.getDistance(self.guide.pos["root"], self.guide.pos["neck"]) dist_node = nod.createDistNode(self.root, self.ik_ctl) rootWorld_node = nod.createDecomposeMatrixNode( self.root.attr("worldMatrix")) div_node = nod.createDivNode(dist_node + ".distance", rootWorld_node + ".outputScaleX") div_node = nod.createDivNode(div_node + ".outputX", d) # tan0 mul_node = nod.createMulNode(self.tan0_att, self.tan0_loc.getAttr("ty")) res_node = nod.createMulNode(mul_node + ".outputX", div_node + ".outputX") connectAttr(res_node + ".outputX", self.tan0_loc + ".ty") # tan1 mul_node = nod.createMulNode(self.tan1_att, self.tan1_loc.getAttr("ty")) res_node = nod.createMulNode(mul_node + ".outputX", div_node + ".outputX") connectAttr(res_node + ".outputX", self.tan1_loc.attr("ty")) # Curves ------------------------------------------- op = aop.gear_curveslide2_op(self.slv_crv, self.mst_crv, 0, 1.5, .5, .5) connectAttr(self.maxstretch_att, op + ".maxstretch") connectAttr(self.maxsquash_att, op + ".maxsquash") connectAttr(self.softness_att, op + ".softness") # Volume driver ------------------------------------ crv_node = nod.createCurveInfoNode(self.slv_crv) # Division ----------------------------------------- for i in range(self.settings["division"]): # References u = i / (self.settings["division"] - 1.0) cns = aop.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 aop.gear_spinePointAtOp(cns, self.root, self.ik_ctl, u, "Z") # Squash n Stretch op = aop.gear_squashstretch2_op(self.fk_npo[i], self.root, arclen(self.slv_crv), "y") connectAttr(self.volume_att, op + ".blend") connectAttr(crv_node + ".arcLength", op + ".driver") connectAttr(self.st_att[i], op + ".stretch") connectAttr(self.sq_att[i], op + ".squash") # scl compas if i != 0: div_node = nod.createDivNode([1, 1, 1], [ self.fk_npo[i - 1] + ".sx", self.fk_npo[i - 1] + ".sy", self.fk_npo[i - 1] + ".sz" ]) connectAttr(div_node + ".output", self.scl_npo[i] + ".scale") # Controlers if i == 0: mulmat_node = aop.gear_mulmatrix_op( self.div_cns[i].attr("worldMatrix"), self.root.attr("worldInverseMatrix")) else: mulmat_node = aop.gear_mulmatrix_op( self.div_cns[i].attr("worldMatrix"), self.div_cns[i - 1].attr("worldInverseMatrix")) dm_node = nod.createDecomposeMatrixNode(mulmat_node + ".output") connectAttr(dm_node + ".outputTranslate", self.fk_npo[i].attr("t")) connectAttr(dm_node + ".outputRotate", self.fk_npo[i].attr("r")) #connectAttr(dm_node+".outputScale", self.fk_npo[i].attr("s")) # Orientation Lock if i == self.settings["division"] - 1: dm_node = nod.createDecomposeMatrixNode(self.ik_ctl + ".worldMatrix") blend_node = nod.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() connectAttr(blend_node + ".output", self.div_cns[i] + ".rotate") # Head --------------------------------------------- self.fk_ctl[-1].addChild(self.head_cns)
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 addOperators(self): # 1 bone chain Upv ref ===================================================================================== self.ikHandleUpvRef = pri.addIkHandle( self.root, self.getName("ikHandleLegChainUpvRef"), self.armChainUpvRef, "ikSCsolver") pm.pointConstraint(self.ik_ctl, self.ikHandleUpvRef) pm.parentConstraint(self.armChainUpvRef[0], self.upv_cns, mo=True) # Visibilities ------------------------------------- # fk fkvis_node = nod.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")) if self.settings["ikTR"]: for shp in self.ikRot_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) # Controls ROT order ----------------------------------- att.setRotOrder(self.fk0_ctl, "XZY") att.setRotOrder(self.fk1_ctl, "XYZ") att.setRotOrder(self.fk2_ctl, "YZX") # att.setRotOrder(self.ik_ctl, "ZYX") att.setRotOrder(self.ik_ctl, "XYZ") # IK Solver ----------------------------------------- out = [self.bone0, self.bone1, self.ctrn_loc, self.eff_loc] node = aop.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 = node.listConnections(c=True)[-1][1] outEff_dm.attr("outputTranslate") >> self.ikRot_npo.attr( "translate") outEff_dm.attr("outputScale") >> self.ikRot_npo.attr("scale") dm_node = nod.createDecomposeMatrixNode(node.attr("outB")) dm_node.attr("outputRotate") >> self.ikRot_npo.attr("rotate") #rotation # intM_node = aop.gear_intmatrix_op(node.attr("outEff"), self.ikRot_ctl.attr("worldMatrix"), node.attr("blend")) # mulM_node = aop.gear_mulmatrix_op(intM_node.attr("output"), self.eff_loc.attr("parentInverseMatrix")) # dm_node = nod.createDecomposeMatrixNode(mulM_node.attr("output")) mulM_node = aop.gear_mulmatrix_op( self.ikRot_ctl.attr("worldMatrix"), self.eff_loc.attr("parentInverseMatrix")) intM_node = aop.gear_intmatrix_op(node.attr("outEff"), mulM_node.attr("output"), node.attr("blend")) dm_node = nod.createDecomposeMatrixNode(intM_node.attr("output")) dm_node.attr("outputRotate") >> self.eff_loc.attr("rotate") #scale: this fix the scalin popping issue intM_node = aop.gear_intmatrix_op(self.fk2_ctl.attr("worldMatrix"), self.ik_ctl.attr("worldMatrix"), node.attr("blend")) mulM_node = aop.gear_mulmatrix_op( intM_node.attr("output"), self.eff_loc.attr("parentInverseMatrix")) dm_node = nod.createDecomposeMatrixNode(mulM_node.attr("output")) dm_node.attr("outputScale") >> self.eff_loc.attr("scale") pm.connectAttr(self.blend_att, node + ".blend") pm.connectAttr(self.roll_att, node + ".roll") pm.connectAttr(self.scale_att, node + ".scaleA") pm.connectAttr(self.scale_att, node + ".scaleB") pm.connectAttr(self.maxstretch_att, node + ".maxstretch") pm.connectAttr(self.slide_att, node + ".slide") pm.connectAttr(self.softness_att, node + ".softness") pm.connectAttr(self.reverse_att, node + ".reverse") # Twist references --------------------------------- pm.pointConstraint(self.mid_ctl, self.tws1_npo, maintainOffset=False) pm.scaleConstraint(self.mid_ctl, self.tws1_npo, maintainOffset=False) pm.orientConstraint(self.mid_ctl, self.tws1_npo, maintainOffset=False) node = aop.gear_mulmatrix_op(self.eff_loc.attr("worldMatrix"), self.root.attr("worldInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputTranslate", self.tws2_npo.attr("translate")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputRotate", self.tws2_npo.attr("rotate")) node = aop.gear_mulmatrix_op(self.eff_loc.attr("worldMatrix"), self.tws2_rot.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(node + ".output", dm_node + ".inputMatrix") att.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 = nod.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 aop.splineIK(self.getName("rollRef"), self.rollRef, parent=self.root, cParent=self.bone0) # Volume ------------------------------------------- distA_node = nod.createDistNode(self.tws0_loc, self.tws1_loc) distB_node = nod.createDistNode(self.tws1_loc, self.tws2_loc) add_node = nod.createAddNode(distA_node + ".distance", distB_node + ".distance") div_node = nod.createDivNode(add_node + ".output", self.root.attr("sx")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(self.root.attr("worldMatrix"), dm_node + ".inputMatrix") div_node2 = nod.createDivNode(div_node + ".outputX", dm_node + ".outputScaleX") self.volDriver_att = div_node2 + ".outputX" # 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"] + 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) perc = max(.001, min(.990, perc)) # Roll if self.negate: node = aop.gear_rollsplinekine_op( div_cns, [self.tws2_rot, self.tws1_rot, self.tws0_rot], 1 - perc, 40) else: node = aop.gear_rollsplinekine_op( div_cns, [self.tws0_rot, self.tws1_rot, self.tws2_rot], perc, 40) pm.connectAttr(self.resample_att, node + ".resample") pm.connectAttr(self.absolute_att, node + ".absolute") # Squash n Stretch node = aop.gear_squashstretch2_op(div_cns, None, pm.getAttr(self.volDriver_att), "x") pm.connectAttr(self.volume_att, node + ".blend") pm.connectAttr(self.volDriver_att, node + ".driver") pm.connectAttr(self.st_att[i], node + ".stretch") pm.connectAttr(self.sq_att[i], 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) return
def addOperators(self): # Visibilities ------------------------------------- # fk fkvis_node = nod.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")) # Controls ROT order ----------------------------------- att.setRotOrder(self.fk0_ctl, "XZY") att.setRotOrder(self.fk1_ctl, "XYZ") att.setRotOrder(self.fk2_ctl, "YZX") att.setRotOrder(self.ik_ctl, "ZYX") # IK Solver ----------------------------------------- out = [self.bone0, self.bone1, self.ctrn_loc, self.eff_loc] node = aop.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) pm.connectAttr(self.blend_att, node + ".blend") pm.connectAttr(self.roll_att, node + ".roll") pm.connectAttr(self.scale_att, node + ".scaleA") pm.connectAttr(self.scale_att, node + ".scaleB") pm.connectAttr(self.maxstretch_att, node + ".maxstretch") pm.connectAttr(self.slide_att, node + ".slide") pm.connectAttr(self.softness_att, node + ".softness") pm.connectAttr(self.reverse_att, node + ".reverse") # Twist references --------------------------------- node = aop.gear_mulmatrix_op(self.eff_loc.attr("worldMatrix"), self.root.attr("worldInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputTranslate", self.tws2_npo.attr("translate")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputRotate", self.tws2_npo.attr("rotate")) #spline IK for twist jnts self.ikhArmTwist, self.armTwistCrv = aop.splineIK( self.getName("armTwist"), self.armTwistChain, parent=self.root, cParent=self.bone0) self.ikhForearmTwist, self.forearmTwistCrv = aop.splineIK( self.getName("forearmTwist"), self.forearmTwistChain, parent=self.root, cParent=self.bone1) #references self.ikhArmRef, self.tmpCrv = aop.splineIK(self.getName("armRollRef"), self.armRollRef, parent=self.root, cParent=self.bone0) self.ikhForearmRef, self.tmpCrv = aop.splineIK( self.getName("forearmRollRef"), self.forearmRollRef, parent=self.root, cParent=self.eff_loc) self.ikhAuxTwist, self.tmpCrv = aop.splineIK(self.getName("auxTwist"), self.auxTwistChain, parent=self.root, cParent=self.eff_loc) #setting connexions for ikhArmTwist self.ikhArmTwist.attr("dTwistControlEnable").set(True) self.ikhArmTwist.attr("dWorldUpType").set(4) self.ikhArmTwist.attr("dWorldUpAxis").set(3) self.ikhArmTwist.attr("dWorldUpVectorZ").set(1.0) self.ikhArmTwist.attr("dWorldUpVectorY").set(0.0) self.ikhArmTwist.attr("dWorldUpVectorEndZ").set(1.0) self.ikhArmTwist.attr("dWorldUpVectorEndY").set(0.0) pm.connectAttr(self.armRollRef[0].attr("worldMatrix[0]"), self.ikhArmTwist.attr("dWorldUpMatrix")) pm.connectAttr(self.bone0.attr("worldMatrix[0]"), self.ikhArmTwist.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.forearmRollRef[0].attr("worldMatrix[0]"), self.ikhAuxTwist.attr("dWorldUpMatrix")) pm.connectAttr(self.eff_loc.attr("worldMatrix[0]"), self.ikhAuxTwist.attr("dWorldUpMatrixEnd")) pm.connectAttr(self.auxTwistChain[1].attr("rx"), self.ikhForearmTwist.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.armTwistCrv, ch=True) alAttrArm = arclen_node.attr("arcLength") muldiv_nodeArm = pm.createNode("multiplyDivide") pm.connectAttr(arclen_node.attr("arcLength"), muldiv_nodeArm.attr("input1X")) muldiv_nodeArm.attr("input2X").set(alAttrArm.get()) muldiv_nodeArm.attr("operation").set(2) for jnt in self.armTwistChain: 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.forearmTwistCrv, ch=True) alAttrForearm = arclen_node.attr("arcLength") muldiv_nodeForearm = pm.createNode("multiplyDivide") pm.connectAttr(arclen_node.attr("arcLength"), muldiv_nodeForearm.attr("input1X")) muldiv_nodeForearm.attr("input2X").set(alAttrForearm.get()) muldiv_nodeForearm.attr("operation").set(2) for jnt in self.forearmTwistChain: pm.connectAttr(muldiv_nodeForearm.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.armTwistChain[0].attr("inverseScale")) pm.connectAttr(dm_node.attr("outputScale"), self.forearmTwistChain[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" aop.aimCns(self.tws1A_npo, self.tws0_loc, axis=axis, wupType=2, wupVector=[0, 0, 1], wupObject=self.mid_ctl, maintainOffset=False) aop.aimCns(self.forearmTangentB_loc, self.forearmTangentA_npo, axis=axis, wupType=2, wupVector=[0, 0, 1], wupObject=self.mid_ctl, maintainOffset=False) pm.pointConstraint(self.eff_loc, self.forearmTangentB_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" aop.aimCns(self.tws1B_npo, self.tws2_loc, axis=axis, wupType=2, wupVector=[0, 0, 1], wupObject=self.mid_ctl, maintainOffset=False) aop.aimCns(self.armTangentA_loc, self.armTangentB_npo, axis=axis, wupType=2, wupVector=[0, 0, 1], wupObject=self.mid_ctl, maintainOffset=False) # Volume ------------------------------------------- distA_node = nod.createDistNode(self.tws0_loc, self.tws1_loc) distB_node = nod.createDistNode(self.tws1_loc, self.tws2_loc) add_node = nod.createAddNode(distA_node + ".distance", distB_node + ".distance") div_node = nod.createDivNode(add_node + ".output", self.root.attr("sx")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(self.root.attr("worldMatrix"), dm_node + ".inputMatrix") div_node2 = nod.createDivNode(div_node + ".outputX", dm_node + ".outputScaleX") self.volDriver_att = div_node2 + ".outputX" # connecting tangent scaele compensation after volume to aboid duplicate some nodes ------------------------------ distA_node = nod.createDistNode(self.tws0_loc, self.mid_ctl) distB_node = nod.createDistNode(self.mid_ctl, self.tws2_loc) div_nodeArm = nod.createDivNode(distA_node + ".distance", dm_node.attr("outputScaleX")) div_node2 = nod.createDivNode(div_nodeArm + ".outputX", distA_node.attr("distance").get()) pm.connectAttr(div_node2.attr("outputX"), self.tws1A_loc.attr("sx")) pm.connectAttr(div_node2.attr("outputX"), self.armTangentA_loc.attr("sx")) div_nodeForearm = nod.createDivNode(distB_node + ".distance", dm_node.attr("outputScaleX")) div_node2 = nod.createDivNode(div_nodeForearm + ".outputX", distB_node.attr("distance").get()) pm.connectAttr(div_node2.attr("outputX"), self.tws1B_loc.attr("sx")) pm.connectAttr(div_node2.attr("outputX"), self.forearmTangentB_loc.attr("sx")) #conection curve aop.gear_curvecns_op(self.armTwistCrv, [ self.armTangentA_loc, self.armTangentA_ctl, self.armTangentB_ctl, self.elbowTangent_ctl ]) aop.gear_curvecns_op(self.forearmTwistCrv, [ self.elbowTangent_ctl, self.forearmTangentA_ctl, self.forearmTangentB_ctl, self.forearmTangentB_loc ]) #Tangent controls vis pm.connectAttr(self.tangentVis_att, self.armTangentA_ctl.attr("visibility")) pm.connectAttr(self.tangentVis_att, self.armTangentB_ctl.attr("visibility")) pm.connectAttr(self.tangentVis_att, self.forearmTangentA_ctl.attr("visibility")) pm.connectAttr(self.tangentVis_att, self.forearmTangentB_ctl.attr("visibility")) pm.connectAttr(self.tangentVis_att, self.elbowTangent_ctl.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 = aop.gear_mulmatrix_op( self.armTwistChain[i] + ".worldMatrix", div_cns + ".parentInverseMatrix") else: mulmat_node = aop.gear_mulmatrix_op( self.forearmTwistChain[i - (self.settings["div0"] + 2)] + ".worldMatrix", div_cns + ".parentInverseMatrix") dm_node = nod.createDecomposeMatrixNode(mulmat_node + ".output") pm.connectAttr(dm_node + ".outputTranslate", div_cns + ".t") pm.connectAttr(dm_node + ".outputRotate", div_cns + ".r") # Squash n Stretch node = aop.gear_squashstretch2_op(div_cns, None, pm.getAttr(self.volDriver_att), "x") pm.connectAttr(self.volume_att, node + ".blend") pm.connectAttr(self.volDriver_att, node + ".driver") pm.connectAttr(self.st_att[i], node + ".stretch") pm.connectAttr(self.sq_att[i], node + ".squash") # return # 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 tra.matchWorldTransform(self.fk_ctl[0], self.match_fk0_off) tra.matchWorldTransform(self.fk_ctl[1], self.match_fk1_off) tra.matchWorldTransform(self.fk_ctl[0], self.match_fk0) tra.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)
def addOperators(self): # Visibilities ------------------------------------- # fk fkvis_node = nod.createReverseNode(self.blend_att) for shp in self.fk0_ctl.getShapes(): connectAttr(fkvis_node+".outputX", shp.attr("visibility")) for shp in self.fk1_ctl.getShapes(): connectAttr(fkvis_node+".outputX", shp.attr("visibility")) for shp in self.fk2_ctl.getShapes(): connectAttr(fkvis_node+".outputX", shp.attr("visibility")) # ik for shp in self.upv_ctl.getShapes(): connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ikcns_ctl.getShapes(): connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ik_ctl.getShapes(): connectAttr(self.blend_att, shp.attr("visibility")) # IK Solver ----------------------------------------- out = [self.bone0, self.bone1, self.ctrn_loc, self.eff_loc] node = aop.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) connectAttr(self.blend_att, node+".blend") connectAttr(self.roll_att, node+".roll") connectAttr(self.scale_att, node+".scaleA") connectAttr(self.scale_att, node+".scaleB") connectAttr(self.maxstretch_att, node+".maxstretch") connectAttr(self.slide_att, node+".slide") connectAttr(self.softness_att, node+".softness") connectAttr(self.reverse_att, node+".reverse") # Twist references --------------------------------- pointConstraint(self.root, self.tws0_loc, maintainOffset=True) aop.aimCns(self.tws0_loc, self.mid_ctl, self.n_sign+"xz", 2, [0,1,0], self.root, False) pointConstraint(self.mid_ctl, self.tws1_loc, maintainOffset=False) scaleConstraint(self.mid_ctl, self.tws1_loc, maintainOffset=False) orientConstraint(self.mid_ctl, self.tws1_rot, maintainOffset=False) pointConstraint(self.eff_loc, self.tws2_loc, maintainOffset=False) scaleConstraint(self.eff_loc, self.tws2_loc, maintainOffset=False) orientConstraint(self.bone1, self.tws2_loc, maintainOffset=False) # orientConstraint(self.eff_loc, self.tws2_rot, maintainOffset=False) node = aop.gear_mulmatrix_op(self.eff_loc.attr("worldMatrix"), self.tws2_rot.attr("parentInverseMatrix")) dm_node = createNode("decomposeMatrix") connectAttr(node+".output", dm_node+".inputMatrix") connectAttr(dm_node+".outputRotate", self.tws2_rot+".rotate") # att.setRotOrder(self.tws2_rot, "YZX") self.tws0_loc.setAttr("sx", .001) self.tws2_loc.setAttr("sx", .001) add_node = nod.createAddNode(self.roundness_att, .001) connectAttr(add_node+".output", self.tws1_rot.attr("sx")) # Volume ------------------------------------------- distA_node = nod.createDistNode(self.tws0_loc, self.tws1_loc) distB_node = nod.createDistNode(self.tws1_loc, self.tws2_loc) add_node = nod.createAddNode(distA_node+".distance", distB_node+".distance") div_node = nod.createDivNode(add_node+".output", self.root.attr("sx")) self.volDriver_att = div_node+".outputX" # 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"]+1): perc = i*.5 / (self.settings["div0"]+1.0) else: perc = .5 + (i-self.settings["div0"]-1.0)*.5 / (self.settings["div1"]+1.0) perc = max(.001, min(.999, perc)) # Roll if self.negate: node = aop.gear_rollsplinekine_op(div_cns, [self.tws2_rot, self.tws1_rot, self.tws0_rot], 1-perc) else: node = aop.gear_rollsplinekine_op(div_cns, [self.tws0_rot, self.tws1_rot, self.tws2_rot], perc) connectAttr(self.resample_att, node+".resample") connectAttr(self.absolute_att, node+".absolute") # Squash n Stretch node = aop.gear_squashstretch2_op(div_cns, None, getAttr(self.volDriver_att), "x") connectAttr(self.volume_att, node+".blend") connectAttr(self.volDriver_att, node+".driver") connectAttr(self.st_att[i], node+".stretch") connectAttr(self.sq_att[i], node+".squash") 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. """ # 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, .5, .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.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", 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", .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.settings["division"] - 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): # Tangent position --------------------------------- # common part d = vec.getDistance(self.guide.pos["root"], self.guide.pos["neck"]) dist_node = nod.createDistNode(self.root, self.ik_ctl) rootWorld_node = nod.createDecomposeMatrixNode(self.root.attr("worldMatrix")) div_node = nod.createDivNode(dist_node+".distance", rootWorld_node+".outputScaleX") div_node = nod.createDivNode(div_node+".outputX", d) # tan0 mul_node = nod.createMulNode(self.tan0_att, self.tan0_loc.getAttr("ty")) res_node = nod.createMulNode(mul_node+".outputX", div_node+".outputX") connectAttr( res_node+".outputX", self.tan0_loc+".ty") # tan1 mul_node = nod.createMulNode(self.tan1_att, self.tan1_loc.getAttr("ty")) res_node = nod.createMulNode(mul_node+".outputX", div_node+".outputX") connectAttr( res_node+".outputX", self.tan1_loc.attr("ty")) # Curves ------------------------------------------- op = aop.gear_curveslide2_op(self.slv_crv, self.mst_crv, 0, 1.5, .5, .5) connectAttr(self.maxstretch_att, op+".maxstretch") connectAttr(self.maxsquash_att, op+".maxsquash") connectAttr(self.softness_att, op+".softness") # Volume driver ------------------------------------ crv_node = nod.createCurveInfoNode(self.slv_crv) # Division ----------------------------------------- for i in range(self.settings["division"]): # References u = i / (self.settings["division"] - 1.0) cns = aop.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 aop.gear_spinePointAtOp(cns, self.root, self.ik_ctl, u, "Z") # Squash n Stretch op = aop.gear_squashstretch2_op(self.fk_npo[i], self.root, arclen(self.slv_crv), "y") connectAttr(self.volume_att, op+".blend") connectAttr(crv_node+".arcLength", op+".driver") connectAttr(self.st_att[i], op+".stretch") connectAttr(self.sq_att[i], op+".squash") # scl compas if i != 0: div_node = nod.createDivNode([1,1,1], [self.fk_npo[i-1]+".sx", self.fk_npo[i-1]+".sy", self.fk_npo[i-1]+".sz"]) connectAttr(div_node+".output", self.scl_npo[i]+".scale") # Controlers if i == 0: mulmat_node = aop.gear_mulmatrix_op(self.div_cns[i].attr("worldMatrix"), self.root.attr("worldInverseMatrix")) else: mulmat_node = aop.gear_mulmatrix_op(self.div_cns[i].attr("worldMatrix"), self.div_cns[i-1].attr("worldInverseMatrix")) dm_node = nod.createDecomposeMatrixNode(mulmat_node+".output") connectAttr(dm_node+".outputTranslate", self.fk_npo[i].attr("t")) connectAttr(dm_node+".outputRotate", self.fk_npo[i].attr("r")) #connectAttr(dm_node+".outputScale", self.fk_npo[i].attr("s")) # Orientation Lock if i == self.settings["division"] - 1 : dm_node = nod.createDecomposeMatrixNode(self.ik_ctl+".worldMatrix") blend_node = nod.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() connectAttr(blend_node+".output", self.div_cns[i]+".rotate") # Head --------------------------------------------- self.fk_ctl[-1].addChild(self.head_cns)