def addOperatorsOrientationLock(self, i, cns):
        # Orientation Lock
        if i == 0:
            dm_node = node.createDecomposeMatrixNode(
                self.ik_ctl[0] + ".worldMatrix")

            blend_node = node.createBlendNode(
                [dm_node + ".outputRotate%s" % s for s in "XYZ"],
                [cns + ".rotate%s" % s for s in "XYZ"],
                self.lock_ori0_att)
            # 0)

            self.div_cns[i].attr("rotate").disconnect()
            pm.connectAttr(blend_node + ".output", self.div_cns[i] + ".rotate")

        elif i == len(self.fk_ctl) - 1:
            dm_node = node.createDecomposeMatrixNode(
                self.ik_ctl[-1] + ".worldMatrix")

            blend_node = node.createBlendNode(
                [dm_node + ".outputRotate%s" % s for s in "XYZ"],
                [cns + ".rotate%s" % s for s in "XYZ"],
                self.lock_ori1_att)
            # 1)

            self.div_cns[i].attr("rotate").disconnect()
            pm.connectAttr(blend_node + ".output", self.div_cns[i] + ".rotate")
Пример #2
0
    def addOperatorsIkRoll(self):

        for i in range(0, self.settings["ikNb"]):

            roll_ratio = (i + 0.0001) / (len(self.ik_ctl) - 1.)

            mul1 = pm.createNode("multDoubleLinear")
            pm.connectAttr(self.decomp_tip_ik_rot.attr("outRoll"), mul1.attr("input1"))
            pm.setAttr(mul1.attr("input2"), roll_ratio)
            compose_rot = pm.createNode("composeRotate")
            pm.setAttr(compose_rot.attr("axisOrientX"), 90.0)
            pm.setAttr(compose_rot.attr("axisOrientZ"), 90.0)
            pm.connectAttr(mul1.attr("output"), compose_rot.attr("roll"))
            pm.connectAttr(compose_rot.attr("outRotate"), self.ik_roll_npo[i].attr("rotate"))

            rot = pm.createNode("decomposeRotate")
            pm.setAttr(rot.attr("axisOrientX"), 90.0)
            pm.setAttr(rot.attr("axisOrientZ"), 90.0)

            if i != (len(self.ik_ctl) - 1):
                mul2 = applyop.gear_mulmatrix_op(self.ik_ctl[i].attr("matrix"), self.ik_roll_npo[i].attr("matrix"))
                dm_node = node.createDecomposeMatrixNode(mul2 + ".output")
                pm.connectAttr(dm_node.attr("outputRotate"), rot.attr("rotate"))
            else:
                pm.connectAttr(self.ik_roll_npo[i].attr("rotate"), rot.attr("rotate"))

            self.ik_decompose_rot.append(rot)
Пример #3
0
    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
Пример #4
0
def connectWorldTransform(source, target):
    """Connect the source world transform of one object to another object.

    Args:
        source (dagNode): Source dagNode.
        target (dagNode): target dagNode.
    """
    mulmat_node = node.createMultMatrixNode(source + ".worldMatrix",
                                            target + ".parentInverseMatrix")
    dm_node = node.createDecomposeMatrixNode(mulmat_node + ".matrixSum")
    pm.connectAttr(dm_node + ".outputTranslate", target + ".t")
    pm.connectAttr(dm_node + ".outputRotate", target + ".r")
    pm.connectAttr(dm_node + ".outputScale", target + ".s")
    def connect_blend(self, mm_node, blend_attr, output):
        dm_node = node.createDecomposeMatrixNode(mm_node.output)
        pb_rt = node.createPairBlend(blender=blend_attr)
        pm.connectAttr(dm_node.outputTranslate, pb_rt.inTranslate2)
        pm.connectAttr(dm_node.outputRotate, pb_rt.inRotate2)

        pb_s = node.createPairBlend(blender=blend_attr)
        pm.connectAttr(dm_node.outputScale, pb_s.inTranslate2)

        # connec output
        pm.connectAttr(pb_rt.outTranslate, output.attr("translate"), f=True)
        pm.connectAttr(pb_rt.outRotate, output.attr("rotate"), f=True)
        pm.connectAttr(pb_s.outTranslate, output.attr("scale"), f=True)
    def addOperatorsNotGlobalMaster(self):
        # 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)
        self.addOperatorsIkTwist()

        # Division -----------------------------------------
        rootWorld_node = node.createDecomposeMatrixNode(self.root.attr("worldMatrix"))
        for i in range(len(self.guide.apos)):
            self.addFkOperator(i, rootWorld_node, crv_node)

        # CONNECT STACK
        # master components
        mstr_global = self.settings["masterChainGlobal"]
        mstr_local = self.settings["masterChainLocal"]

        if mstr_global:
            mstr_global = self.rig.components[mstr_global]
        if mstr_local:
            mstr_local = self.rig.components[mstr_local]

        # connect  global IK
        if mstr_global:
            for e, _ in enumerate(self.ik_ctl):
                # connect in global
                self.connect_master(mstr_global.ik_global_out,
                                    self.ik_global_in,
                                    e,
                                    self.settings["cnxOffset"])

        # connect in local
        if mstr_local:
            for e, _ in enumerate(self.ik_ctl):
                self.connect_master(mstr_local.ik_ctl,
                                    self.ik_local_in,
                                    e,
                                    self.settings["cnxOffset"])

            for e, _ in enumerate(self.fk_ctl):
                self.connect_master(mstr_local.fk_ctl,
                                    self.fk_local_in,
                                    e,
                                    self.settings["cnxOffset"])
    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.

        """
        dm_node_scl = node.createDecomposeMatrixNode(self.root.worldMatrix)

        step = 1.000 / (self.settings["div"] - 1)
        u = 0.000
        for i in range(self.settings["div"]):
            applyop.pathCns(self.upv_cns[i],
                            self.upv_crv,
                            cnsType=False,
                            u=u,
                            tangent=False)

            cns = applyop.pathCns(self.div_cns[i], self.mst_crv, False, u,
                                  True)

            # Connectiong the scale for scaling compensation
            for axis, AX in zip("xyz", "XYZ"):
                pm.connectAttr(dm_node_scl.attr("outputScale{}".format(AX)),
                               self.div_cns[i].attr("s{}".format(axis)))

            cns.setAttr("worldUpType", 1)
            cns.setAttr("frontAxis", 0)
            cns.setAttr("upAxis", 1)

            pm.connectAttr(self.upv_cns[i].attr("worldMatrix[0]"),
                           cns.attr("worldUpMatrix"))
            u += step

        for ctl in [self.base_ctl, self.tan0_ctl, self.tan1_ctl, self.tip_ctl]:
            for shp in ctl.getShapes():
                pm.connectAttr(self.ctlVis_att, shp.attr("visibility"))

        for tweak_ctl in self.extratweak_ctl:
            for shp in tweak_ctl.getShapes():
                pm.connectAttr(self.tweakVis_att, shp.attr("visibility"))
Пример #8
0
    def connect_blended_orient(self):
        if not self.parent == self.root.getParent():
            self.parent.addChild(self.root)

        refArray = self.settings["orientrefarray"]
        print 'function called: CustomComponent.connect_blended_orient()'

        if refArray:
            print 'ref array: %s' % refArray
            ref_names = self.get_valid_ref_list(refArray.split(","))
            if len(ref_names) == 1:
                print 'RELOADED'
                ref = self.rig.findRelative(ref_names[0])
                self.staticOffsetMtx = matrix44FromMtxAttr(
                    (ref.worldMatrix[0].get() *
                     self.root.worldInverseMatrix[0].get()))
                self.targetMtx = node.createMultMatrixNode(
                    ref.worldMatrix[0], self.root.worldInverseMatrix[0])
                self.targetInverseMtx = pm.createNode('inverseMatrix')
                self.targetMtx.matrixSum.connect(
                    self.targetInverseMtx.inputMatrix)
                self.resultMtx = node.createMultMatrixNode(
                    self.staticOffsetMtx.output,
                    self.targetInverseMtx.outputMatrix)

                dm = node.createDecomposeMatrixNode(self.resultMtx.matrixSum)
                pb = pm.createNode('pairBlend')
                dm.outputRotate.connect(pb.inRotate1)
                pb.rotInterpolation.set(1)
                pb.weight.set(0.5)
                pb.outRotateZ.connect(self.ik_cns.rotateZ)
                '''
                Do not use world space align in component settings - then control will be built oriented the same as the guide
                Align root to ik_cns.
                Then add above systems to ik_cns - this will offset away from original orientation of guide
                Add a buffer between ik_cns and control to maintain original orientation from guide. Align this buffer back to root
                '''
            else:
                pass
    def connCenter(ctl, driver, ghost):
        # mul_node1 = pm.createNode("multMatrix")
        # mul_node2 = pm.createNode("multMatrix")

        down, _, up = ymt_util.findPathAtoB(ctl, driver)
        mult = pm.createNode("multMatrix")

        for i, d in enumerate(down):
            d.attr("matrix") >> mult.attr("matrixIn[{}]".format(i))

        for j, u in enumerate(up[:-1]):
            u.attr("inverseMatrix") >> mult.attr(
                "matrixIn[{}]".format(i + j + 1))

        decomp = pm.createNode("decomposeMatrix")

        dm_node = node.createDecomposeMatrixNode(mult.attr("matrixSum"))

        for attr in ["translate", "scale", "rotate"]:
            pm.connectAttr("{}.output{}".format(dm_node, attr.capitalize()),
                           "{}.{}".format(driver, attr))
            pm.disconnectAttr("{}.{}".format(ctl, attr),
                              "{}.{}".format(ghost, attr))
Пример #10
0
    def addOperators(self):
        """Create operators and set the relations for the component rig

        Apply operators, constraints, expressions to the hierarchy.
        In order to keep the code clean and easier to debug,
        we shouldn't create any new object in this method.

        """
        # setup out channels. This channels are pass through for stack
        node.createPlusMinusAverage1D(
            [self.mid_wide_att, self.mid_wide_in_att, -1.0], 1,
            self.mid_wide_out_att)
        node.createPlusMinusAverage1D(
            [self.mid_depth_att, self.mid_depth_in_att, -1.0], 1,
            self.mid_depth_out_att)

        node.createPlusMinusAverage1D(
            [self.tip_wide_att, self.tip_wide_in_att, -1.0], 1,
            self.tip_wide_out_att)
        node.createPlusMinusAverage1D(
            [self.tip_depth_att, self.tip_depth_in_att, -1.0], 1,
            self.tip_depth_out_att)

        node.createPlusMinusAverage1D(
            [self.mid_twist_att, self.mid_twist_in_att], 1,
            self.mid_twist_out_att)

        node.createPlusMinusAverage1D(
            [self.tip_twist_att, self.tip_twist_in_att], 1,
            self.tip_twist_out_att)

        if not self.settings["simpleFK"]:
            dm_node_scl = node.createDecomposeMatrixNode(self.root.worldMatrix)
            if self.settings["keepLength"]:
                arclen_node = pm.arclen(self.mst_crv, ch=True)
                alAttr = pm.getAttr(arclen_node + ".arcLength")
                ration_node = node.createMulNode(self.length_ratio_att, alAttr)

                pm.addAttr(self.mst_crv, ln="length_ratio", k=True, w=True)
                node.createDivNode(arclen_node.arcLength, ration_node.outputX,
                                   self.mst_crv.length_ratio)

                div_node_scl = node.createDivNode(self.mst_crv.length_ratio,
                                                  dm_node_scl.outputScaleX)

            step = 1.000 / (self.def_number - 1)
            step_mid = 1.000 / ((self.def_number - 1) / 2.0)
            u = 0.000
            u_mid = 0.000
            pass_mid = False
            for i in range(self.def_number):
                cnsUpv = applyop.pathCns(self.upv_cns[i],
                                         self.upv_crv,
                                         cnsType=False,
                                         u=u,
                                         tangent=False)

                cns = applyop.pathCns(self.div_cns[i], self.mst_crv, False, u,
                                      True)

                # Connecting the scale for scaling compensation
                # for axis, AX in zip("xyz", "XYZ"):
                for axis, AX in zip("x", "X"):
                    pm.connectAttr(
                        dm_node_scl.attr("outputScale{}".format(AX)),
                        self.div_cns[i].attr("s{}".format(axis)))

                if self.settings["keepLength"]:

                    div_node2 = node.createDivNode(u, div_node_scl.outputX)

                    cond_node = node.createConditionNode(
                        div_node2.input1X, div_node2.outputX, 4,
                        div_node2.input1X, div_node2.outputX)

                    pm.connectAttr(cond_node + ".outColorR",
                                   cnsUpv + ".uValue")
                    pm.connectAttr(cond_node + ".outColorR", cns + ".uValue")

                cns.setAttr("worldUpType", 1)
                cns.setAttr("frontAxis", 0)
                cns.setAttr("upAxis", 1)

                pm.connectAttr(self.upv_cns[i].attr("worldMatrix[0]"),
                               cns.attr("worldUpMatrix"))

                # Connect scale Wide and Depth
                # wide and Depth
                mid_mul_node = node.createMulNode(
                    [self.mid_wide_att, self.mid_depth_att],
                    [self.mid_wide_in_att, self.mid_depth_in_att])
                mid_mul_node2 = node.createMulNode(
                    [mid_mul_node.outputX, mid_mul_node.outputY],
                    [u_mid, u_mid])
                mid_mul_node3 = node.createMulNode(
                    [mid_mul_node2.outputX, mid_mul_node2.outputY], [
                        dm_node_scl.attr("outputScaleX"),
                        dm_node_scl.attr("outputScaleY")
                    ])
                tip_mul_node = node.createMulNode(
                    [self.tip_wide_att, self.tip_depth_att],
                    [self.tip_wide_in_att, self.tip_depth_in_att])
                tip_mul_node2 = node.createMulNode(
                    [tip_mul_node.outputX, tip_mul_node.outputY], [u, u])
                node.createPlusMinusAverage1D([
                    mid_mul_node3.outputX, 1.0 - u_mid, tip_mul_node2.outputX,
                    1.0 - u, -1.0
                ], 1, self.div_cns[i].attr("sy"))
                node.createPlusMinusAverage1D([
                    mid_mul_node3.outputY, 1.0 - u_mid, tip_mul_node2.outputY,
                    1.0 - u, -1.0
                ], 1, self.div_cns[i].attr("sz"))

                # Connect Twist "cns.frontTwist"
                twist_mul_node = node.createMulNode(
                    [self.mid_twist_att, self.tip_twist_att], [u_mid, u])
                twist_mul_node2 = node.createMulNode(
                    [self.mid_twist_in_att, self.tip_twist_in_att], [u_mid, u])
                node.createPlusMinusAverage1D([
                    twist_mul_node.outputX,
                    twist_mul_node.outputY,
                    twist_mul_node2.outputX,
                    twist_mul_node2.outputY,
                ], 1, cns.frontTwist)

                # u_mid calc
                if u_mid >= 1.0 or pass_mid:
                    u_mid -= step_mid
                    pass_mid = True
                else:
                    u_mid += step_mid

                if u_mid > 1.0:
                    u_mid = 1.0

                # ensure the tip is never affected byt the mid
                if i == (self.def_number - 1):
                    u_mid = 0.0
                u += step

            if self.settings["keepLength"]:
                # add the safty distance offset
                self.tweakTip_npo.attr("tx").set(self.off_dist)
                # connect vis line ref
                for shp in self.line_ref.getShapes():
                    pm.connectAttr(self.ikVis_att, shp.attr("visibility"))

        # CONNECT STACK
        # master components
        mstr_global = self.settings["masterChainGlobal"]
        mstr_local = self.settings["masterChainLocal"]
        if mstr_global:
            mstr_global = self.rig.components[mstr_global]
        if mstr_local:
            mstr_local = self.rig.components[mstr_local]

        # connect twist and scale
        if mstr_global and mstr_local:
            node.createPlusMinusAverage1D([
                mstr_global.root.mid_twist_out, mstr_local.root.mid_twist_out
            ], 1, self.mid_twist_in_att)
            node.createPlusMinusAverage1D([
                mstr_global.root.tip_twist_out, mstr_local.root.tip_twist_out
            ], 1, self.tip_twist_in_att)
            node.createPlusMinusAverage1D([
                mstr_global.root.mid_wide_out, mstr_local.root.mid_wide_out, -1
            ], 1, self.mid_wide_in_att)
            node.createPlusMinusAverage1D([
                mstr_global.root.tip_wide_out, mstr_local.root.tip_wide_out, -1
            ], 1, self.tip_wide_in_att)
            node.createPlusMinusAverage1D([
                mstr_global.root.mid_depth_out, mstr_local.root.mid_depth_out,
                -1
            ], 1, self.mid_depth_in_att)
            node.createPlusMinusAverage1D([
                mstr_global.root.tip_depth_out, mstr_local.root.tip_depth_out,
                -1
            ], 1, self.tip_depth_in_att)
        elif mstr_local or mstr_global:
            for master_chain in [mstr_local, mstr_global]:
                if master_chain:
                    pm.connectAttr(master_chain.root.mid_twist_out,
                                   self.mid_twist_in_att)
                    pm.connectAttr(master_chain.root.tip_twist_out,
                                   self.tip_twist_in_att)
                    pm.connectAttr(master_chain.root.mid_wide_out,
                                   self.mid_wide_in_att)
                    pm.connectAttr(master_chain.root.tip_wide_out,
                                   self.tip_wide_in_att)
                    pm.connectAttr(master_chain.root.mid_depth_out,
                                   self.mid_depth_in_att)
                    pm.connectAttr(master_chain.root.tip_depth_out,
                                   self.tip_depth_in_att)
        # connect the fk chain ctls
        for e, ctl in enumerate(self.fk_ctl):
            # connect out
            out_loc = self.fk_local_out[e]
            applyop.gear_mulmatrix_op(ctl.attr("worldMatrix"),
                                      out_loc.attr("parentInverseMatrix[0]"),
                                      out_loc)
            out_glob = self.fk_global_out[e]
            out_ref = self.fk_global_ref[e]
            applyop.gear_mulmatrix_op(out_ref.attr("worldMatrix"),
                                      out_glob.attr("parentInverseMatrix[0]"),
                                      out_glob)
            # connect in global
            if mstr_global:
                self.connect_master(mstr_global.fk_global_out,
                                    self.fk_global_in, e,
                                    self.settings["cnxOffset"])

            # connect in local
            if mstr_local:
                self.connect_master(mstr_local.fk_local_out, self.fk_local_in,
                                    e, self.settings["cnxOffset"])

            for shp in ctl.getShapes():
                pm.connectAttr(self.fkVis_att, shp.attr("visibility"))

        for ctl in self.tweak_ctl:
            for shp in ctl.getShapes():
                pm.connectAttr(self.ikVis_att, shp.attr("visibility"))

        if self.settings["extraTweak"]:
            for tweak_ctl in self.extratweak_ctl:
                for shp in tweak_ctl.getShapes():
                    pm.connectAttr(self.tweakVis_att, shp.attr("visibility"))
Пример #11
0
    def addOperators(self):
        """Create operators and set the relations for the component rig

        Apply operators, constraints, expressions to the hierarchy.
        In order to keep the code clean and easier to debug,
        we shouldn't create any new object in this method.

        """
        # Curves -------------------------------------------
        op = applyop.gear_curveslide2_op(self.slv_crv, self.mst_crv, 0, 1.5,
                                         .5, .5)

        pm.connectAttr(self.position_att, op + ".position")
        pm.connectAttr(self.maxstretch_att, op + ".maxstretch")
        pm.connectAttr(self.maxsquash_att, op + ".maxsquash")
        pm.connectAttr(self.softness_att, op + ".softness")

        # Division -----------------------------------------
        rootWorld_node = node.createDecomposeMatrixNode(
            self.root.attr("worldMatrix"))
        for i in range(self.settings["fkNb"]):

            # References
            u = i / (self.settings["fkNb"] - 1.0)
            if i == 0:  # we add extra 10% to the first position
                u = (1.0 / (self.settings["fkNb"] - 1.0)) / 10

            cns = applyop.pathCns(self.div_cns[i], self.slv_crv, False, u,
                                  True)

            cns.setAttr("frontAxis", 0)  # front axis is 'X'
            cns.setAttr("upAxis", 2)  # front axis is 'Z'

            # Roll
            intMatrix = applyop.gear_intmatrix_op(
                self.ik_ctl[0] + ".worldMatrix",
                self.ik_ctl[-1] + ".worldMatrix", u)

            dm_node = node.createDecomposeMatrixNode(intMatrix + ".output")
            pm.connectAttr(dm_node + ".outputRotate",
                           self.twister[i].attr("rotate"))

            pm.parentConstraint(self.twister[i],
                                self.ref_twist[i],
                                maintainOffset=True)

            pm.connectAttr(self.ref_twist[i] + ".translate",
                           cns + ".worldUpVector")

            # compensate scale reference
            div_node = node.createDivNode([1, 1, 1], [
                rootWorld_node + ".outputScaleX", rootWorld_node +
                ".outputScaleY", rootWorld_node + ".outputScaleZ"
            ])

            # Controlers
            if i == 0:
                mulmat_node = applyop.gear_mulmatrix_op(
                    self.div_cns[i].attr("worldMatrix"),
                    self.root.attr("worldInverseMatrix"))

                dm_node = node.createDecomposeMatrixNode(mulmat_node +
                                                         ".output")

                pm.connectAttr(dm_node + ".outputTranslate",
                               self.fk_npo[i].attr("t"))

            else:
                mulmat_node = applyop.gear_mulmatrix_op(
                    self.div_cns[i].attr("worldMatrix"),
                    self.div_cns[i - 1].attr("worldInverseMatrix"))

                dm_node = node.createDecomposeMatrixNode(mulmat_node +
                                                         ".output")

                mul_node = node.createMulNode(div_node + ".output",
                                              dm_node + ".outputTranslate")

                pm.connectAttr(mul_node + ".output", self.fk_npo[i].attr("t"))

            pm.connectAttr(dm_node + ".outputRotate", self.fk_npo[i].attr("r"))

            # Orientation Lock
            if i == 0:
                dm_node = node.createDecomposeMatrixNode(self.ik_ctl[0] +
                                                         ".worldMatrix")

                blend_node = node.createBlendNode(
                    [dm_node + ".outputRotate%s" % s for s in "XYZ"],
                    [cns + ".rotate%s" % s for s in "XYZ"], 0)

                self.div_cns[i].attr("rotate").disconnect()

                pm.connectAttr(blend_node + ".output",
                               self.div_cns[i] + ".rotate")

            elif i == self.settings["fkNb"] - 1:
                dm_node = node.createDecomposeMatrixNode(self.ik_ctl[-1] +
                                                         ".worldMatrix")

                blend_node = node.createBlendNode(
                    [dm_node + ".outputRotate%s" % s for s in "XYZ"],
                    [cns + ".rotate%s" % s for s in "XYZ"], 0)

                self.div_cns[i].attr("rotate").disconnect()
                pm.connectAttr(blend_node + ".output",
                               self.div_cns[i] + ".rotate")
    def addFkOperator(self, i, rootWorld_node, crv_node):

        if i == 0 and self.settings["isSplitHip"]:
            s = self.fk_hip_ctl
            d = self.fk_local_npo[0],
            # maintainOffset, skipRotate, skipTranslate
            _ = pm.parentConstraint(s, d, mo=True, sr=("x", "y", "z"), st=())

            s = self.ik_global_out[0]
            d = self.hip_fk_local_in,
            # maintainOffset, skipRotate, skipTranslate
            pm.parentConstraint(s, d, mo=True)

        # break FK hierarchical orient
        if i not in [len(self.guide.apos), 0]:
            s = self.fk_ctl[i - 1]
            s2 = self.fk_npo[i]
            d = self.fk_local_npo[i]

            mulmat_node = applyop.gear_mulmatrix_op(s2.attr("matrix"), s.attr("matrix"))
            mulmat_node2 = applyop.gear_mulmatrix_op(mulmat_node.attr("output"), s2.attr("inverseMatrix"))

            dm_node = node.createDecomposeMatrixNode(mulmat_node2 + ".output")
            pm.connectAttr(dm_node + ".outputTranslate", d.attr("t"))

            check_list = (pm.Attribute, unicode, str)  # noqa
            cond = pm.createNode("condition")
            pm.setAttr(cond + ".operation", 4)  # greater
            attribute.connectSet(self.fk_collapsed_att, cond + ".secondTerm", check_list)
            attribute.connectSet(dm_node + ".outputRotate", cond + ".colorIfTrue", check_list)
            pm.setAttr(cond + ".colorIfFalseR", 0.)
            pm.setAttr(cond + ".colorIfFalseG", 0.)
            pm.setAttr(cond + ".colorIfFalseB", 0.)
            pm.connectAttr(cond + ".outColor", d.attr("r"))

        # References
        if i == 0:  # we add extra 10% to the first position
            u = (1.0 / (len(self.guide.apos) - 1.0)) / 1000
        else:
            u = getCurveUAtPoint(self.slv_crv, self.guide.apos[i])

        tmp_div_npo_transform = getTransform(self.div_cns_npo[i])  # to fix mismatch before/after later
        cns = applyop.pathCns(self.div_cns[i], self.slv_crv, False, u, True)
        cns.setAttr("frontAxis", 1)  # front axis is 'Y'
        cns.setAttr("upAxis", 0)  # front axis is 'X'

        # Roll
        # choose ik_ctls
        for _i, uv in enumerate(self.ik_uv_param):
            if u < uv:

                ik_a = self.ik_ctl[_i - 1]
                ik_b = self.ik_ctl[_i]

                if self.settings["isSplitHip"] and i == 0:
                    u = (i + 1) / (len(self.guide.apos) - 1.0)
                    ratio = u / uv * .5

                else:
                    ratio = u / uv

                break

        else:
            ik_a = self.ik_ctl[-2]
            ik_b = self.ik_ctl[-1]
            ratio = 1.

        intMatrix = applyop.gear_intmatrix_op(
            ik_a + ".worldMatrix",
            ik_b + ".worldMatrix",
            ratio)

        dm_node = node.createDecomposeMatrixNode(intMatrix + ".output")
        pm.connectAttr(dm_node + ".outputRotate", self.twister[i].attr("rotate"))
        pm.parentConstraint(self.twister[i], self.ref_twist[i], maintainOffset=True)

        pm.connectAttr(self.ref_twist[i] + ".translate", cns + ".worldUpVector")
        self.div_cns_npo[i].setMatrix(tmp_div_npo_transform, worldSpace=True)

        # compensate scale reference
        div_node = node.createDivNode(
            [1, 1, 1],
            [rootWorld_node + ".outputScaleX",
             rootWorld_node + ".outputScaleY",
             rootWorld_node + ".outputScaleZ"])

        # Squash n Stretch
        op = applyop.gear_squashstretch2_op(self.scl_transforms[i],
                                            self.root,
                                            pm.arclen(self.slv_crv),
                                            "y",
                                            div_node + ".output")

        pm.connectAttr(self.volume_att, op + ".blend")
        pm.connectAttr(crv_node + ".arcLength", op + ".driver")
        pm.connectAttr(self.st_att[i], op + ".stretch")
        pm.connectAttr(self.sq_att[i], op + ".squash")

        # Controlers
        tmp_local_npo_transform = getTransform(self.fk_local_npo[i])  # to fix mismatch before/after later
        if i == 0:
            mulmat_node = applyop.gear_mulmatrix_op(
                self.div_cns_npo[i].attr("worldMatrix"),
                self.root.attr("worldInverseMatrix"))

            dm_node = node.createDecomposeMatrixNode(mulmat_node + ".output")
            pm.connectAttr(dm_node + ".outputTranslate", self.fk_npo[i].attr("t"))

        else:
            mulmat_node = applyop.gear_mulmatrix_op(
                self.div_cns_npo[i].attr("worldMatrix"),
                self.div_cns_npo[i - 1].attr("worldInverseMatrix"))

            dm_node = node.createDecomposeMatrixNode(mulmat_node + ".output")
            mul_node = node.createMulNode(div_node + ".output", dm_node + ".outputTranslate")
            pm.connectAttr(mul_node + ".output", self.fk_npo[i].attr("t"))

        pm.connectAttr(dm_node + ".outputRotate", self.fk_npo[i].attr("r"))
        self.addOperatorsOrientationLock(i, cns)
        self.fk_local_npo[i].setMatrix(tmp_local_npo_transform, worldSpace=True)

        # References
        if i < (len(self.fk_ctl) - 1):
            aim = pm.aimConstraint(self.div_cns_npo[i + 1], self.div_cns_npo[i], maintainOffset=False)
            pm.setAttr(aim + ".aimVectorX", 0)
            pm.setAttr(aim + ".aimVectorY", 1)
            pm.setAttr(aim + ".aimVectorZ", 0)
            pm.setAttr(aim + ".upVectorX", 0)
            pm.setAttr(aim + ".upVectorY", 1)
            pm.setAttr(aim + ".upVectorZ", 0)
Пример #13
0
    def addOperatorsNotGlobalMaster(self):
        # Curves -------------------------------------------
        op = applyop.gear_curveslide2_op(self.slv_crv, self.mst_crv, 0, 1.5, .5, .5)
        op.rename(self.getName("slideCurveOp"))

        # 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")
        self.slv_crv_op = op

        # Volume driver ------------------------------------
        crv_node = node.createCurveInfoNode(self.slv_crv)

        if not self.settings["isPlanetaryIkBindToGlobal"]:
            self.addOperatorsIkTwist()

        # ensure plugin loaded
        if 0 == cmds.pluginInfo("rotationDriver", query=True, loaded=True):
            cmds.loadPlugin("rotationDriver")

        self.decomp_tip_ik_rot = pm.createNode("decomposeRotate")
        # self.ik_decompose_rot.append(self.decomp_tip_ik_rot)
        pm.setAttr(self.decomp_tip_ik_rot.attr("axisOrientX"), 90.0)
        pm.setAttr(self.decomp_tip_ik_rot.attr("axisOrientZ"), 90.0)
        pm.connectAttr(self.ik_ctl[-1].rotate, self.decomp_tip_ik_rot.attr("rotate"))

        self.addOperatorsIkRoll()
        # Division -----------------------------------------
        rootWorld_node = node.createDecomposeMatrixNode(self.root.attr("worldMatrix"))
        for i in range(len(self.guide.apos)):
            self.addFkOperator(i, rootWorld_node, crv_node)

        # CONNECT STACK
        # master components
        mstr_global = self.settings["masterChainGlobal"]
        mstr_local = self.settings["masterChainLocal"]

        if mstr_global:
            mstr_global = self.rig.components[mstr_global]
        if mstr_local:
            mstr_local = self.rig.components[mstr_local]

        # connect  global IK
        if mstr_global:
            for e, _ in enumerate(self.ik_ctl):
                # connect in global
                self.connect_master(mstr_global.ik_global_out,
                                    self.ik_global_in,
                                    e,
                                    self.settings["cnxOffset"])

        # connect in local
        if mstr_local:
            for e, _ in enumerate(self.ik_ctl):
                self.connect_master(mstr_local.ik_ctl,
                                    self.ik_local_in,
                                    e,
                                    self.settings["cnxOffset"])

            for e, _ in enumerate(self.fk_ctl):
                self.connect_master(mstr_local.fk_ctl,
                                    self.fk_local_in,
                                    e,
                                    self.settings["cnxOffset"])
Пример #14
0
    def addOperators(self):
        """Create operators and set the relations for the component rig

        Apply operators, constraints, expressions to the hierarchy.
        In order to keep the code clean and easier to debug,
        we shouldn't create any new object in this method.

        """
        # Soft condition
        soft_cond_node = node.createConditionNode(
            self.soft_attr,
            0.0001,
            4,
            0.0001,
            self.soft_attr)
        self.soft_attr_cond = soft_cond_node.outColorR

        if self.settings["ikSolver"]:
            self.ikSolver = "ikRPsolver"
        else:
            pm.mel.eval("ikSpringSolver;")
            self.ikSolver = "ikSpringSolver"

        # 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.upv_cns, mo=True)

        # mid joints ================================================
        for xjnt, midJ in zip(self.legBones[1:3],
                              [self.mid1_jnt, self.mid2_jnt]):
            node.createPairBlend(None, xjnt, .5, 1, midJ)
            pm.connectAttr(xjnt + ".translate", midJ + ".translate", f=True)

        pm.parentConstraint(self.mid1_jnt, self.knee_lvl)
        pm.parentConstraint(self.mid2_jnt, self.ankle_lvl)

        # joint length multiply
        multJnt1_node = node.createMulNode(self.boneALenght_attr,
                                           self.boneALenghtMult_attr)
        multJnt2_node = node.createMulNode(self.boneBLenght_attr,
                                           self.boneBLenghtMult_attr)
        multJnt3_node = node.createMulNode(self.boneCLenght_attr,
                                           self.boneCLenghtMult_attr)

        # # IK 3 bones ===============================================

        self.ikHandle = primitive.addIkHandle(self.softblendLoc,
                                              self.getName("ik3BonesHandle"),
                                              self.chain3bones,
                                              self.ikSolver,
                                              self.upv_ctl)

        # TwistTest
        if [round(elem, 4)
                for elem in transform.getTranslation(self.chain3bones[1])] \
                != [round(elem, 4) for elem in self.guide.apos[1]]:
            add_nodeTwist = node.createAddNode(180.0, self.roll_att)
        else:
            add_nodeTwist = node.createAddNode(0, self.roll_att)
        if self.negate:
            mulVal = 1
        else:
            mulVal = -1
        node.createMulNode(
            add_nodeTwist + ".output", mulVal, self.ikHandle.attr("twist"))

        # stable spring solver doble rotation
        pm.pointConstraint(self.root_ctl, self.chain3bones[0])

        # softIK 3 bones operators
        applyop.aimCns(self.aim_tra,
                       self.ik_ref,
                       axis="zx",
                       wupType=4,
                       wupVector=[1, 0, 0],
                       wupObject=self.root_ctl,
                       maintainOffset=False)

        plusTotalLength_node = node.createPlusMinusAverage1D(
            [multJnt1_node.attr("outputX"),
             multJnt2_node.attr("outputX"),
             multJnt3_node.attr("outputX")])

        subtract1_node = node.createPlusMinusAverage1D(
            [plusTotalLength_node.attr("output1D"), self.soft_attr_cond], 2)

        distance1_node = node.createDistNode(self.ik_ref, self.aim_tra)
        div1_node = node.createDivNode(1.0, self.rig.global_ctl + ".sx")
        mult1_node = node.createMulNode(distance1_node + ".distance",
                                        div1_node + ".outputX")
        subtract2_node = node.createPlusMinusAverage1D(
            [mult1_node.attr("outputX"), subtract1_node.attr("output1D")], 2)
        div2_node = node.createDivNode(subtract2_node + ".output1D",
                                       self.soft_attr_cond)
        mult2_node = node.createMulNode(-1, div2_node + ".outputX")
        power_node = node.createPowNode(self.softSpeed_attr,
                                        mult2_node + ".outputX")
        mult3_node = node.createMulNode(self.soft_attr_cond,
                                        power_node + ".outputX")
        subtract3_node = node.createPlusMinusAverage1D(
            [plusTotalLength_node.attr("output1D"),
             mult3_node.attr("outputX")],
            2)

        cond1_node = node.createConditionNode(
            self.soft_attr_cond,
            0,
            2,
            subtract3_node + ".output1D",
            plusTotalLength_node + ".output1D")

        cond2_node = node.createConditionNode(mult1_node + ".outputX",
                                              subtract1_node + ".output1D",
                                              2, cond1_node + ".outColorR",
                                              mult1_node + ".outputX")

        pm.connectAttr(cond2_node + ".outColorR", self.wristSoftIK + ".tz")

        # soft blend
        pc_node = pm.pointConstraint(self.wristSoftIK,
                                     self.ik_ref,
                                     self.softblendLoc)
        node.createReverseNode(self.stretch_attr,
                               pc_node + ".target[0].targetWeight")
        pm.connectAttr(self.stretch_attr,
                       pc_node + ".target[1].targetWeight",
                       f=True)

        # Stretch
        distance2_node = node.createDistNode(self.softblendLoc,
                                             self.wristSoftIK)
        mult4_node = node.createMulNode(distance2_node + ".distance",
                                        div1_node + ".outputX")

        # bones
        for i, mulNode in enumerate([multJnt1_node,
                                     multJnt2_node,
                                     multJnt3_node]):

            div3_node = node.createDivNode(mulNode + ".outputX",
                                           plusTotalLength_node + ".output1D")

            mult5_node = node.createMulNode(mult4_node + ".outputX",
                                            div3_node + ".outputX")

            mult6_node = node.createMulNode(self.stretch_attr,
                                            mult5_node + ".outputX")

            node.createPlusMinusAverage1D(
                [mulNode.attr("outputX"), mult6_node.attr("outputX")],
                1,
                self.chain3bones[i + 1] + ".tx")

        # IK 2 bones ===============================================

        self.ikHandle2 = primitive.addIkHandle(self.softblendLoc2,
                                               self.getName("ik2BonesHandle"),
                                               self.chain2bones,
                                               self.ikSolver,
                                               self.upv_ctl)

        node.createMulNode(self.roll_att, mulVal, self.ikHandle2.attr("twist"))

        # stable spring solver doble rotation
        pm.pointConstraint(self.root_ctl, self.chain2bones[0])

        parentc_node = pm.parentConstraint(
            self.ik2b_ikCtl_ref, self.ik2b_bone_ref, self.ik2b_blend)

        node.createReverseNode(self.fullIK_attr,
                               parentc_node + ".target[0].targetWeight")

        pm.connectAttr(self.fullIK_attr,
                       parentc_node + ".target[1].targetWeight", f=True)

        # softIK 2 bones operators
        applyop.aimCns(self.aim_tra2,
                       self.ik2b_ik_ref,
                       axis="zx",
                       wupType=4,
                       wupVector=[1, 0, 0],
                       wupObject=self.root_ctl,
                       maintainOffset=False)

        plusTotalLength_node = node.createPlusMinusAverage1D(
            [multJnt1_node.attr("outputX"), multJnt2_node.attr("outputX")])

        subtract1_node = node.createPlusMinusAverage1D(
            [plusTotalLength_node.attr("output1D"), self.soft_attr_cond], 2)

        distance1_node = node.createDistNode(self.ik2b_ik_ref, self.aim_tra2)
        div1_node = node.createDivNode(1, self.rig.global_ctl + ".sx")

        mult1_node = node.createMulNode(distance1_node + ".distance",
                                        div1_node + ".outputX")

        subtract2_node = node.createPlusMinusAverage1D(
            [mult1_node.attr("outputX"), subtract1_node.attr("output1D")], 2)

        div2_node = node.createDivNode(subtract2_node + ".output1D",
                                       self.soft_attr_cond)

        mult2_node = node.createMulNode(-1, div2_node + ".outputX")

        power_node = node.createPowNode(self.softSpeed_attr,
                                        mult2_node + ".outputX")

        mult3_node = node.createMulNode(self.soft_attr_cond,
                                        power_node + ".outputX")

        subtract3_node = node.createPlusMinusAverage1D(
            [plusTotalLength_node.attr("output1D"),
             mult3_node.attr("outputX")],
            2)

        cond1_node = node.createConditionNode(
            self.soft_attr_cond,
            0,
            2,
            subtract3_node + ".output1D",
            plusTotalLength_node + ".output1D")

        cond2_node = node.createConditionNode(mult1_node + ".outputX",
                                              subtract1_node + ".output1D",
                                              2,
                                              cond1_node + ".outColorR",
                                              mult1_node + ".outputX")

        pm.connectAttr(cond2_node + ".outColorR", self.ankleSoftIK + ".tz")

        # soft blend
        pc_node = pm.pointConstraint(self.ankleSoftIK,
                                     self.ik2b_ik_ref,
                                     self.softblendLoc2)
        node.createReverseNode(self.stretch_attr,
                               pc_node + ".target[0].targetWeight")
        pm.connectAttr(self.stretch_attr,
                       pc_node + ".target[1].targetWeight",
                       f=True)

        # Stretch
        distance2_node = node.createDistNode(self.softblendLoc2,
                                             self.ankleSoftIK)

        mult4_node = node.createMulNode(distance2_node + ".distance",
                                        div1_node + ".outputX")

        for i, mulNode in enumerate([multJnt1_node, multJnt2_node]):
            div3_node = node.createDivNode(mulNode + ".outputX",
                                           plusTotalLength_node + ".output1D")

            mult5_node = node.createMulNode(mult4_node + ".outputX",
                                            div3_node + ".outputX")

            mult6_node = node.createMulNode(self.stretch_attr,
                                            mult5_node + ".outputX")

            node.createPlusMinusAverage1D([mulNode.attr("outputX"),
                                           mult6_node.attr("outputX")],
                                          1,
                                          self.chain2bones[i + 1] + ".tx")

        # IK/FK connections

        for i, x in enumerate(self.fk_ctl):
            pm.parentConstraint(x, self.legBonesFK[i], mo=True)

        for i, x in enumerate([self.chain2bones[0], self.chain2bones[1]]):
            pm.parentConstraint(x, self.legBonesIK[i], mo=True)

        pm.pointConstraint(self.ik2b_ik_ref, self.legBonesIK[2])
        applyop.aimCns(self.legBonesIK[2],
                       self.roll_ctl,
                       axis="xy",
                       wupType=4,
                       wupVector=[0, 1, 0],
                       wupObject=self.legBonesIK[1],
                       maintainOffset=False)

        pm.connectAttr(self.chain3bones[-1].attr("tx"),
                       self.legBonesIK[-1].attr("tx"))
        # foot twist roll
        pm.orientConstraint(self.ik_ref, self.legBonesIK[-1], mo=True)

        node.createMulNode(
            -1, self.chain3bones[-1].attr("tx"), self.ik2b_ik_ref.attr("tx"))

        for i, x in enumerate(self.legBones):
            node.createPairBlend(
                self.legBonesFK[i], self.legBonesIK[i], self.blend_att, 1, x)

        # Twist references ----------------------------------------

        self.ikhArmRef, self.tmpCrv = applyop.splineIK(
            self.getName("legRollRef"),
            self.rollRef,
            parent=self.root,
            cParent=self.legBones[0])

        initRound = .001
        multVal = 1

        multTangent_node = node.createMulNode(self.roundnessKnee_att, multVal)
        add_node = node.createAddNode(multTangent_node + ".outputX", initRound)
        pm.connectAttr(add_node + ".output", self.tws1_rot.attr("sx"))
        for x in ["translate"]:
            pm.connectAttr(self.knee_ctl.attr(x), self.tws1_loc.attr(x))
        for x in "xy":
            pm.connectAttr(self.knee_ctl.attr("r" + x),
                           self.tws1_loc.attr("r" + x))

        multTangent_node = node.createMulNode(self.roundnessAnkle_att, multVal)
        add_node = node.createAddNode(multTangent_node + ".outputX", initRound)
        pm.connectAttr(add_node + ".output", self.tws2_rot.attr("sx"))
        for x in ["translate"]:
            pm.connectAttr(self.ankle_ctl.attr(x), self.tws2_loc.attr(x))
        for x in "xy":
            pm.connectAttr(self.ankle_ctl.attr("r" + x),
                           self.tws2_loc.attr("r" + x))

        # Volume -------------------------------------------
        distA_node = node.createDistNode(self.tws0_loc, self.tws1_loc)
        distB_node = node.createDistNode(self.tws1_loc, self.tws2_loc)
        distC_node = node.createDistNode(self.tws2_loc, self.tws3_loc)
        add_node = node.createAddNode(distA_node + ".distance",
                                      distB_node + ".distance")
        add_node2 = node.createAddNode(distC_node + ".distance",
                                       add_node + ".output")
        div_node = node.createDivNode(add_node2 + ".output",
                                      self.root_ctl.attr("sx"))

        # comp scaling
        dm_node = node.createDecomposeMatrixNode(self.root.attr("worldMatrix"))

        div_node2 = node.createDivNode(div_node + ".outputX",
                                       dm_node + ".outputScaleX")

        self.volDriver_att = div_node2 + ".outputX"

        # Flip Offset ----------------------------------------
        pm.connectAttr(self.ankleFlipOffset_att, self.tws2_loc.attr("rz"))
        pm.connectAttr(self.kneeFlipOffset_att, self.tws1_loc.attr("rz"))
        # 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):
            subdiv = False
            if i == len(self.div_cns) - 1 or i == 0:
                subdiv = 45
            else:
                subdiv = 45

            if i < (self.settings["div0"] + 1):
                perc = i * .333 / (self.settings["div0"] + 1.0)

            elif i < (self.settings["div0"] + self.settings["div1"] + 2):
                perc = i * .333 / (self.settings["div0"] + 1.0)
            else:
                perc = (.5
                        + (i - self.settings["div0"] - 3.0)
                        * .5
                        / (self.settings["div1"] + 1.0))

            if i < (self.settings["div0"] + 2):
                perc = i * .333 / (self.settings["div0"] + 1.0)

            elif i < (self.settings["div0"] + self.settings["div1"] + 3):
                perc = (.333
                        + (i - self.settings["div0"] - 1)
                        * .333
                        / (self.settings["div1"] + 1.0))
            else:
                perc = (.666
                        + (i
                            - self.settings["div1"]
                            - self.settings["div0"]
                            - 2.0)
                        * .333
                        / (self.settings["div2"] + 1.0))

            # we neet to offset the ankle and knee point to force the bone
            # orientation to the nex bone span
            if perc == .333:
                perc = .3338
            elif perc == .666:
                perc = .6669

            perc = max(.001, min(.999, perc))

            # Roll
            cts = [self.tws0_rot, self.tws1_rot, self.tws2_rot, self.tws3_rot]
            o_node = applyop.gear_rollsplinekine_op(div_cns, cts, perc, subdiv)

            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")

        # Visibilities -------------------------------------
        # fk
        fkvis_node = node.createReverseNode(self.blend_att)
        for ctrl in self.fk_ctl:
            for shp in ctrl.getShapes():
                pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility"))
        # ik
        for ctrl in [self.ik_ctl, self.roll_ctl, self.upv_ctl, self.line_ref]:
            for shp in ctrl.getShapes():
                pm.connectAttr(self.blend_att, shp.attr("visibility"))

        # setup leg o_node scale compensate
        pm.connectAttr(self.rig.global_ctl + ".scale", self.setup + ".scale")

        # match IK/FK ref
        pm.parentConstraint(self.legBones[0], self.match_fk0_off, mo=True)
        pm.parentConstraint(self.legBones[1], self.match_fk1_off, mo=True)
        pm.parentConstraint(self.legBones[2], self.match_fk2_off, mo=True)

        return
Пример #15
0
    def addOperators(self):
        """Create operators and set the relations for the component rig

        Apply operators, constraints, expressions to the hierarchy.
        In order to keep the code clean and easier to debug,
        we shouldn't create any new object in this method.

        """
        # Tangent position ---------------------------------
        # common part
        d = vector.getDistance(self.guide.pos["root"], self.guide.pos["neck"])
        dist_node = node.createDistNode(self.root, self.ik_ctl)
        rootWorld_node = node.createDecomposeMatrixNode(
            self.root.attr("worldMatrix"))
        div_node = node.createDivNode(dist_node + ".distance",
                                      rootWorld_node + ".outputScaleX")
        div_node = node.createDivNode(div_node + ".outputX", d)

        # tan0
        mul_node = node.createMulNode(self.tan0_att,
                                      self.tan0_loc.getAttr("ty"))
        res_node = node.createMulNode(mul_node + ".outputX",
                                      div_node + ".outputX")
        pm.connectAttr(res_node + ".outputX", self.tan0_loc + ".ty")

        # tan1
        mul_node = node.createMulNode(self.tan1_att,
                                      self.tan1_loc.getAttr("ty"))
        res_node = node.createMulNode(mul_node + ".outputX",
                                      div_node + ".outputX")
        pm.connectAttr(res_node + ".outputX", self.tan1_loc.attr("ty"))

        # Curves -------------------------------------------
        op = applyop.gear_curveslide2_op(self.slv_crv, self.mst_crv, 0, 1.5,
                                         0.5, 0.5)
        pm.connectAttr(self.maxstretch_att, op + ".maxstretch")
        pm.connectAttr(self.maxsquash_att, op + ".maxsquash")
        pm.connectAttr(self.softness_att, op + ".softness")

        # Volume driver ------------------------------------
        crv_node = node.createCurveInfoNode(self.slv_crv)

        # Division -----------------------------------------
        for i in range(self.divisions):

            # References
            u = i / (self.divisions - 1.0)

            cns = applyop.pathCns(self.div_cns[i], self.slv_crv, False, u,
                                  True)
            cns.setAttr("frontAxis", 1)  # front axis is 'Y'
            cns.setAttr("upAxis", 2)  # front axis is 'Z'

            # Roll
            intMatrix = applyop.gear_intmatrix_op(
                self.intMRef + ".worldMatrix", self.ik_ctl + ".worldMatrix", u)
            dm_node = node.createDecomposeMatrixNode(intMatrix + ".output")
            pm.connectAttr(dm_node + ".outputRotate",
                           self.twister[i].attr("rotate"))

            pm.parentConstraint(self.twister[i],
                                self.ref_twist[i],
                                maintainOffset=True)

            pm.connectAttr(self.ref_twist[i] + ".translate",
                           cns + ".worldUpVector")

            # Squash n Stretch
            op = applyop.gear_squashstretch2_op(self.fk_npo[i], self.root,
                                                pm.arclen(self.slv_crv), "y")

            pm.connectAttr(self.volume_att, op + ".blend")
            pm.connectAttr(crv_node + ".arcLength", op + ".driver")
            pm.connectAttr(self.st_att[i], op + ".stretch")
            pm.connectAttr(self.sq_att[i], op + ".squash")
            op.setAttr("driver_min", 0.1)

            # scl compas
            if i != 0:
                div_node = node.createDivNode(
                    [1, 1, 1],
                    [
                        self.fk_npo[i - 1] + ".sx",
                        self.fk_npo[i - 1] + ".sy",
                        self.fk_npo[i - 1] + ".sz",
                    ],
                )

                pm.connectAttr(div_node + ".output",
                               self.scl_npo[i] + ".scale")

            # Controlers
            if i == 0:
                mulmat_node = applyop.gear_mulmatrix_op(
                    self.div_cns[i].attr("worldMatrix"),
                    self.root.attr("worldInverseMatrix"),
                )
            else:
                mulmat_node = applyop.gear_mulmatrix_op(
                    self.div_cns[i].attr("worldMatrix"),
                    self.div_cns[i - 1].attr("worldInverseMatrix"),
                )

            dm_node = node.createDecomposeMatrixNode(mulmat_node + ".output")
            pm.connectAttr(dm_node + ".outputTranslate",
                           self.fk_npo[i].attr("t"))
            pm.connectAttr(dm_node + ".outputRotate", self.fk_npo[i].attr("r"))

            # Orientation Lock
            if i == self.divisions - 1:
                dm_node = node.createDecomposeMatrixNode(self.ik_ctl +
                                                         ".worldMatrix")
                blend_node = node.createBlendNode(
                    [dm_node + ".outputRotate%s" % s for s in "XYZ"],
                    [cns + ".rotate%s" % s for s in "XYZ"],
                    self.lock_ori_att,
                )
                self.div_cns[i].attr("rotate").disconnect()

                pm.connectAttr(blend_node + ".output",
                               self.div_cns[i] + ".rotate")

        # Head ---------------------------------------------
        self.fk_ctl[-1].addChild(self.head_cns)

        # scale compensation
        dm_node = node.createDecomposeMatrixNode(self.scl_npo[0] +
                                                 ".parentInverseMatrix")

        pm.connectAttr(dm_node + ".outputScale", self.scl_npo[0] + ".scale")
Пример #16
0
    def addOperators(self):
        """Create operators and set the relations for the component rig

        Apply operators, constraints, expressions to the hierarchy.
        In order to keep the code clean and easier to debug,
        we shouldn't create any new object in this method.

        """
        # 1 bone chain Upv ref ==============================================
        self.ikHandleUpvRef = primitive.addIkHandle(
            self.root, self.getName("ikHandleArmChainUpvRef"),
            self.armChainUpvRef, "ikSCsolver")
        pm.pointConstraint(self.ik_ctl, self.ikHandleUpvRef)
        pm.parentConstraint(self.armChainUpvRef[0], self.upv_cns, mo=True)

        # Visibilities -------------------------------------
        # fk
        fkvis_node = node.createReverseNode(self.blend_att)

        for shp in self.fk0_ctl.getShapes():
            pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility"))
        for shp in self.fk1_ctl.getShapes():
            pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility"))
        for shp in self.fk2_ctl.getShapes():
            pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility"))

        # ik
        for shp in self.upv_ctl.getShapes():
            pm.connectAttr(self.blend_att, shp.attr("visibility"))
        for shp in self.ikcns_ctl.getShapes():
            pm.connectAttr(self.blend_att, shp.attr("visibility"))
        for shp in self.ik_ctl.getShapes():
            pm.connectAttr(self.blend_att, shp.attr("visibility"))
        for shp in self.line_ref.getShapes():
            pm.connectAttr(self.blend_att, shp.attr("visibility"))
        if self.settings["ikTR"]:
            for shp in self.ikRot_ctl.getShapes():
                pm.connectAttr(self.blend_att, shp.attr("visibility"))
        for shp in self.roll_ctl.getShapes():
            pm.connectAttr(self.blend_att, shp.attr("visibility"))

        # Controls ROT order -----------------------------------
        attribute.setRotOrder(self.fk0_ctl, "XZY")
        attribute.setRotOrder(self.fk1_ctl, "XYZ")
        attribute.setRotOrder(self.fk2_ctl, "YZX")
        attribute.setRotOrder(self.ik_ctl, "XYZ")

        # IK Solver -----------------------------------------
        out = [self.bone0, self.bone1, self.ctrn_loc, self.eff_loc]
        o_node = applyop.gear_ikfk2bone_op(out, self.root, self.ik_ref,
                                           self.upv_ctl, self.fk_ctl[0],
                                           self.fk_ctl[1], self.fk_ref,
                                           self.length0, self.length1,
                                           self.negate)

        # NOTE: Ideally we should not change hierarchy or move object after
        # object generation method. But is much easier this way since every
        # part is in the final and correct position
        # after the  ctrn_loc is in the correct position with the ikfk2bone op

        # point constrain tip reference
        pm.pointConstraint(self.ik_ctl, self.tip_ref, mo=False)

        # interpolate transform  mid point locator
        int_matrix = applyop.gear_intmatrix_op(
            self.armChainUpvRef[0].attr("worldMatrix"),
            self.tip_ref.attr("worldMatrix"), .5)
        applyop.gear_mulmatrix_op(
            int_matrix.attr("output"),
            self.interpolate_lvl.attr("parentInverseMatrix[0]"),
            self.interpolate_lvl)

        # match roll ctl npo to ctrn_loc current transform (so correct orient)
        transform.matchWorldTransform(self.ctrn_loc, self.roll_ctl_npo)

        # match roll ctl npo to interpolate transform current position
        pos = self.interpolate_lvl.getTranslation(space="world")
        self.roll_ctl_npo.setTranslation(pos, space="world")

        # parent constraint roll control npo to interpolate trans
        pm.parentConstraint(self.interpolate_lvl, self.roll_ctl_npo, mo=True)

        if self.settings["ikTR"]:
            # connect the control inputs
            outEff_dm = o_node.listConnections(c=True)[-1][1]

            inAttr = self.ikRot_npo.attr("translate")
            outEff_dm.attr("outputTranslate") >> inAttr

            outEff_dm.attr("outputScale") >> self.ikRot_npo.attr("scale")
            dm_node = node.createDecomposeMatrixNode(o_node.attr("outB"))
            dm_node.attr("outputRotate") >> self.ikRot_npo.attr("rotate")

            # rotation
            mulM_node = applyop.gear_mulmatrix_op(
                self.ikRot_ctl.attr("worldMatrix"),
                self.eff_loc.attr("parentInverseMatrix"))
            intM_node = applyop.gear_intmatrix_op(o_node.attr("outEff"),
                                                  mulM_node.attr("output"),
                                                  o_node.attr("blend"))
            dm_node = node.createDecomposeMatrixNode(intM_node.attr("output"))
            dm_node.attr("outputRotate") >> self.eff_loc.attr("rotate")
            transform.matchWorldTransform(self.fk2_ctl, self.ikRot_cns)

        # scale: this fix the scalin popping issue
        intM_node = applyop.gear_intmatrix_op(
            self.fk2_ctl.attr("worldMatrix"),
            self.ik_ctl_ref.attr("worldMatrix"), o_node.attr("blend"))
        mulM_node = applyop.gear_mulmatrix_op(
            intM_node.attr("output"), self.eff_loc.attr("parentInverseMatrix"))
        dm_node = node.createDecomposeMatrixNode(mulM_node.attr("output"))
        dm_node.attr("outputScale") >> self.eff_loc.attr("scale")

        pm.connectAttr(self.blend_att, o_node + ".blend")
        if self.negate:
            mulVal = -1
            rollMulVal = 1
        else:
            mulVal = 1
            rollMulVal = -1
        roll_m_node = node.createMulNode(self.roll_att, mulVal)
        roll_m_node2 = node.createMulNode(self.roll_ctl.attr("rx"), rollMulVal)
        node.createPlusMinusAverage1D(
            [roll_m_node.outputX, roll_m_node2.outputX],
            operation=1,
            output=o_node + ".roll")
        pm.connectAttr(self.scale_att, o_node + ".scaleA")
        pm.connectAttr(self.scale_att, o_node + ".scaleB")
        pm.connectAttr(self.maxstretch_att, o_node + ".maxstretch")
        pm.connectAttr(self.slide_att, o_node + ".slide")
        pm.connectAttr(self.softness_att, o_node + ".softness")
        pm.connectAttr(self.reverse_att, o_node + ".reverse")

        # Twist references ---------------------------------

        pm.pointConstraint(self.mid_ctl_twst_ref,
                           self.tws1_npo,
                           maintainOffset=False)
        pm.connectAttr(self.mid_ctl.scaleX, self.tws1_loc.scaleX)
        pm.connectAttr(self.mid_ctl.scaleX, self.tws1B_loc.scaleX)
        pm.orientConstraint(self.mid_ctl_twst_ref,
                            self.tws1_npo,
                            maintainOffset=False)
        applyop.oriCns(self.mid_ctl, self.tws1_rot, maintainOffset=False)
        applyop.oriCns(self.mid_ctl, self.tws1B_rot, maintainOffset=False)

        if self.negate:
            axis = "xz"
            axisb = "-xz"
        else:
            axis = "-xz"
            axisb = "xz"
        applyop.aimCns(self.tws1_loc,
                       self.root,
                       axis=axis,
                       wupType=4,
                       wupVector=[0, 0, 1],
                       wupObject=self.mid_ctl,
                       maintainOffset=False)

        applyop.aimCns(self.tws1B_loc,
                       self.eff_loc,
                       axis=axisb,
                       wupType=4,
                       wupVector=[0, 0, 1],
                       wupObject=self.mid_ctl,
                       maintainOffset=False)

        pm.pointConstraint(self.thick_ctl,
                           self.tws1B_loc,
                           maintainOffset=False)

        o_node = applyop.gear_mulmatrix_op(
            self.eff_loc.attr("worldMatrix"),
            self.root.attr("worldInverseMatrix"))
        dm_node = pm.createNode("decomposeMatrix")
        pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix")
        pm.connectAttr(dm_node + ".outputTranslate",
                       self.tws2_npo.attr("translate"))

        dm_node = pm.createNode("decomposeMatrix")
        pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix")
        pm.connectAttr(dm_node + ".outputRotate", self.tws2_npo.attr("rotate"))

        o_node = applyop.gear_mulmatrix_op(
            self.eff_loc.attr("worldMatrix"),
            self.tws2_rot.attr("parentInverseMatrix"))
        dm_node = pm.createNode("decomposeMatrix")
        pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix")
        attribute.setRotOrder(self.tws2_rot, "XYZ")
        pm.connectAttr(dm_node + ".outputRotate", self.tws2_rot + ".rotate")

        self.tws0_rot.setAttr("sx", .001)
        self.tws2_rot.setAttr("sx", .001)

        add_node = node.createAddNode(self.roundness_att, .001)
        pm.connectAttr(add_node + ".output", self.tws1_rot.attr("sx"))
        pm.connectAttr(add_node + ".output", self.tws1B_rot.attr("sx"))

        pm.connectAttr(self.armpit_roll_att, self.tws0_rot + ".rotateX")

        # Roll Shoulder
        applyop.splineIK(self.getName("rollRef"),
                         self.rollRef,
                         parent=self.root,
                         cParent=self.bone0)

        # Volume -------------------------------------------
        distA_node = node.createDistNode(self.tws0_loc, self.tws1_loc)
        distB_node = node.createDistNode(self.tws1_loc, self.tws2_loc)
        add_node = node.createAddNode(distA_node + ".distance",
                                      distB_node + ".distance")
        div_node = node.createDivNode(add_node + ".output",
                                      self.root.attr("sx"))

        dm_node = pm.createNode("decomposeMatrix")
        pm.connectAttr(self.root.attr("worldMatrix"), dm_node + ".inputMatrix")

        div_node2 = node.createDivNode(div_node + ".outputX",
                                       dm_node + ".outputScaleX")
        self.volDriver_att = div_node2 + ".outputX"

        if self.settings["extraTweak"]:
            for tweak_ctl in self.tweak_ctl:
                for shp in tweak_ctl.getShapes():
                    pm.connectAttr(self.tweakVis_att, shp.attr("visibility"))

        # Divisions ----------------------------------------
        # at 0 or 1 the division will follow exactly the rotation of the
        # controler.. and we wont have this nice tangent + roll
        b_twist = False
        for i, div_cns in enumerate(self.div_cns):

            if self.settings["supportJoints"]:
                if i < (self.settings["div0"] + 1):
                    perc = i * .5 / (self.settings["div0"] + 1.0)
                elif i < (self.settings["div0"] + 2):
                    perc = .49
                elif i < (self.settings["div0"] + 3):
                    perc = .50
                elif i < (self.settings["div0"] + 4):
                    b_twist = True
                    perc = .51

                else:
                    perc = .5 + \
                        (i - self.settings["div0"] - 3.0) * .5 / \
                        (self.settings["div1"] + 1.0)
            else:
                if i < (self.settings["div0"] + 1):
                    perc = i * .5 / (self.settings["div0"] + 1.0)
                elif i < (self.settings["div0"] + 2):
                    b_twist = True
                    perc = .501
                else:
                    perc = .5 + \
                        (i - self.settings["div0"] - 1.0) * .5 / \
                        (self.settings["div1"] + 1.0)

            perc = max(.001, min(.990, perc))

            # mid twist distribution
            if b_twist:
                mid_twist = self.tws1B_rot
            else:
                mid_twist = self.tws1_rot

            # Roll
            if self.negate:
                o_node = applyop.gear_rollsplinekine_op(
                    div_cns, [self.tws2_rot, mid_twist, self.tws0_rot],
                    1.0 - perc, 40)
            else:
                o_node = applyop.gear_rollsplinekine_op(
                    div_cns, [self.tws0_rot, mid_twist, self.tws2_rot], perc,
                    40)

            pm.connectAttr(self.resample_att, o_node + ".resample")
            pm.connectAttr(self.absolute_att, o_node + ".absolute")

            # Squash n Stretch
            o_node = applyop.gear_squashstretch2_op(
                div_cns, None, pm.getAttr(self.volDriver_att), "x")
            pm.connectAttr(self.volume_att, o_node + ".blend")
            pm.connectAttr(self.volDriver_att, o_node + ".driver")
            pm.connectAttr(self.st_att[i], o_node + ".stretch")
            pm.connectAttr(self.sq_att[i], o_node + ".squash")

        # match IK/FK ref
        pm.parentConstraint(self.bone0, self.match_fk0_off, mo=True)
        pm.parentConstraint(self.bone1, self.match_fk1_off, mo=True)
        if self.settings["ikTR"]:
            transform.matchWorldTransform(self.ikRot_ctl, self.match_ikRot)
            transform.matchWorldTransform(self.fk_ctl[2], self.match_fk2)

        # connect_reader
        pm.parentConstraint(self.bone0, self.readerA, mo=True)
        pm.parentConstraint(self.bone1, self.readerB, mo=True)

        # connect auto thickness
        if self.negate and not self.settings["mirrorMid"]:
            d_val = 180 / self.length1
        else:
            d_val = -180 / self.length1
        div_thick_node = node.createDivNode(self.elbow_thickness_att, d_val)
        node.createMulNode(div_thick_node.outputX, self.readerB.ry,
                           self.thick_lvl.tx)

        return
Пример #17
0
def _createSoftModTweak(baseCtl,
                        tweakCtl,
                        name,
                        targets,
                        nameExt="softMod",
                        is_asset=False):

    sm = pm.softMod(targets, wn=[tweakCtl, tweakCtl])
    pm.rename(sm[0], "{}_{}".format(name, nameExt))

    # disconnect default connection
    plugs = sm[0].softModXforms.listConnections(p=True)
    for p in plugs:
        pm.disconnectAttr(p, sm[0].softModXforms)
        pm.delete(p.node())

    dm_node = node.createDecomposeMatrixNode(baseCtl.worldMatrix[0])
    pm.connectAttr(dm_node.outputTranslate, sm[0].falloffCenter)
    mul_node = node.createMulNode(dm_node.outputScaleX,
                                  tweakCtl.attr("falloff"))
    pm.connectAttr(mul_node.outputX, sm[0].falloffRadius)
    pm.connectAttr(tweakCtl.attr("surfaceMode"), sm[0].falloffMode)
    mulMatrix_node = applyop.gear_mulmatrix_op(tweakCtl.worldMatrix[0],
                                               tweakCtl.parentInverseMatrix[0])
    pm.connectAttr(mulMatrix_node.output, sm[0].weightedMatrix)
    pm.connectAttr(baseCtl.worldInverseMatrix[0], sm[0].postMatrix)
    pm.connectAttr(baseCtl.worldMatrix[0], sm[0].preMatrix)
    if is_asset:
        tag_name = ASSET_TAG
    else:
        tag_name = SHOT_TAG

    attribute.addAttribute(sm[0], tag_name, "bool", False, keyable=False)

    sm[0].addAttr("ctlRoot", at='message', m=False)
    sm[0].addAttr("ctlBase", at='message', m=False)
    sm[0].addAttr("ctlTweak", at='message', m=False)
    pm.connectAttr(baseCtl.getParent().attr("message"), sm[0].attr("ctlRoot"))
    pm.connectAttr(baseCtl.attr("message"), sm[0].attr("ctlBase"))
    pm.connectAttr(tweakCtl.attr("message"), sm[0].attr("ctlTweak"))

    # This connection allow the softTweak to work if we apply the  skin
    # precision fix.
    # TODO: By default only apply to a non asset tweaks.
    if skin.getSkinCluster(targets[0]) and not is_asset:

        skin_cls = skin.getSkinCluster(targets[0])
        cnxs = skin_cls.matrix[0].listConnections()
        if (cnxs and cnxs[0].type() == "mgear_mulMatrix" and
                not sm[0].hasAttr("_fixedSkinFix")):

            # tag the softmod as fixed
            attribute.addAttribute(sm[0], "_fixedSkinFix", "bool")

            # original connections
            matrix_cnx = sm[0].matrix.listConnections(p=True)[0]
            preMatrix_cnx = sm[0].preMatrix.listConnections(p=True)[0]
            wgtMatrix_cnx = sm[0].weightedMatrix.listConnections(p=True)[0]
            postMatrix_cnx = sm[0].postMatrix.listConnections(p=True)[0]

            # pre existing node operators
            mulMtx_node = wgtMatrix_cnx.node()
            dcMtx_node = sm[0].falloffCenter.listConnections(p=True)[0].node()

            # geo offset connnections
            geo_root = targets[0].getParent()
            gr_W = geo_root.worldMatrix[0]
            gr_WI = geo_root.worldInverseMatrix[0]

            # new offset operators
            mmm1 = applyop.gear_mulmatrix_op(preMatrix_cnx, gr_WI)
            mmm2 = applyop.gear_mulmatrix_op(matrix_cnx, gr_WI)
            mmm3 = applyop.gear_mulmatrix_op(gr_W, postMatrix_cnx)

            # re-wire connections
            pm.connectAttr(mmm1.output, dcMtx_node.inputMatrix, f=True)
            pm.connectAttr(mmm1.output, sm[0].preMatrix, f=True)

            pm.connectAttr(mmm2.output, sm[0].matrix, f=True)
            pm.connectAttr(mmm2.output, mulMtx_node.matrixA, f=True)

            pm.connectAttr(mmm3.output, mulMtx_node.matrixB, f=True)
            pm.connectAttr(mmm3.output, sm[0].postMatrix, f=True)

            _neutra_geomMatrix(sm[0])

    return sm[0]
Пример #18
0
    def addOperators(self):
        """Create operators and set the relations for the component rig

        Apply operators, constraints, expressions to the hierarchy.
        In order to keep the code clean and easier to debug,
        we shouldn't create any new object in this method.

        """

        # 1 bone chain Upv ref ==============================
        self.ikHandleUpvRef = primitive.addIkHandle(
            self.root, self.getName("ikHandleLegChainUpvRef"),
            self.legChainUpvRef, "ikSCsolver")
        pm.pointConstraint(self.ik_ctl, self.ikHandleUpvRef)
        pm.parentConstraint(self.legChainUpvRef[0],
                            self.ik_ctl,
                            self.upv_cns,
                            mo=True)

        # Visibilities -------------------------------------
        # shape.dispGeometry
        # fk
        fkvis_node = node.createReverseNode(self.blend_att)

        for shp in self.fk0_ctl.getShapes():
            pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility"))
        for shp in self.fk1_ctl.getShapes():
            pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility"))
        for shp in self.fk2_ctl.getShapes():
            pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility"))

        # ik
        for shp in self.upv_ctl.getShapes():
            pm.connectAttr(self.blend_att, shp.attr("visibility"))
        for shp in self.ikcns_ctl.getShapes():
            pm.connectAttr(self.blend_att, shp.attr("visibility"))
        for shp in self.ik_ctl.getShapes():
            pm.connectAttr(self.blend_att, shp.attr("visibility"))
        for shp in self.line_ref.getShapes():
            pm.connectAttr(self.blend_att, shp.attr("visibility"))

        # IK Solver -----------------------------------------
        out = [self.bone0, self.bone1, self.ctrn_loc, self.eff_loc]
        o_node = applyop.gear_ikfk2bone_op(out, self.root_ctl, self.ik_ref,
                                           self.upv_ctl, self.fk_ctl[0],
                                           self.fk_ctl[1], self.fk_ref,
                                           self.length0, self.length1,
                                           self.negate)

        pm.connectAttr(self.blend_att, o_node + ".blend")
        if self.negate:
            mulVal = -1
        else:
            mulVal = 1
        node.createMulNode(self.roll_att, mulVal, o_node + ".roll")
        # pm.connectAttr(self.roll_att, o_node+".roll")
        pm.connectAttr(self.scale_att, o_node + ".scaleA")
        pm.connectAttr(self.scale_att, o_node + ".scaleB")
        pm.connectAttr(self.maxstretch_att, o_node + ".maxstretch")
        pm.connectAttr(self.slide_att, o_node + ".slide")
        pm.connectAttr(self.softness_att, o_node + ".softness")
        pm.connectAttr(self.reverse_att, o_node + ".reverse")

        # Twist references ---------------------------------
        o_node = applyop.gear_mulmatrix_op(
            self.eff_loc.attr("worldMatrix"),
            self.root.attr("worldInverseMatrix"))

        dm_node = pm.createNode("decomposeMatrix")
        pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix")
        pm.connectAttr(dm_node + ".outputTranslate",
                       self.tws2_npo.attr("translate"))

        dm_node = pm.createNode("decomposeMatrix")
        pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix")
        pm.connectAttr(dm_node + ".outputRotate", self.tws2_npo.attr("rotate"))

        # spline IK for  twist jnts
        self.ikhUpLegTwist, self.uplegTwistCrv = applyop.splineIK(
            self.getName("uplegTwist"),
            self.uplegTwistChain,
            parent=self.root,
            cParent=self.bone0)

        self.ikhLowLegTwist, self.lowlegTwistCrv = applyop.splineIK(
            self.getName("lowlegTwist"),
            self.lowlegTwistChain,
            parent=self.root,
            cParent=self.bone1)

        # references
        self.ikhUpLegRef, self.tmpCrv = applyop.splineIK(
            self.getName("uplegRollRef"),
            self.uplegRollRef,
            parent=self.root,
            cParent=self.bone0)

        self.ikhLowLegRef, self.tmpCrv = applyop.splineIK(
            self.getName("lowlegRollRef"),
            self.lowlegRollRef,
            parent=self.root,
            cParent=self.eff_loc)

        self.ikhAuxTwist, self.tmpCrv = applyop.splineIK(
            self.getName("auxTwist"),
            self.auxTwistChain,
            parent=self.root,
            cParent=self.eff_loc)

        # setting connexions for ikhUpLegTwist
        self.ikhUpLegTwist.attr("dTwistControlEnable").set(True)
        self.ikhUpLegTwist.attr("dWorldUpType").set(4)
        self.ikhUpLegTwist.attr("dWorldUpAxis").set(3)
        self.ikhUpLegTwist.attr("dWorldUpVectorZ").set(1.0)
        self.ikhUpLegTwist.attr("dWorldUpVectorY").set(0.0)
        self.ikhUpLegTwist.attr("dWorldUpVectorEndZ").set(1.0)
        self.ikhUpLegTwist.attr("dWorldUpVectorEndY").set(0.0)
        pm.connectAttr(self.uplegRollRef[0].attr("worldMatrix[0]"),
                       self.ikhUpLegTwist.attr("dWorldUpMatrix"))
        pm.connectAttr(self.bone0.attr("worldMatrix[0]"),
                       self.ikhUpLegTwist.attr("dWorldUpMatrixEnd"))

        # setting connexions for ikhAuxTwist
        self.ikhAuxTwist.attr("dTwistControlEnable").set(True)
        self.ikhAuxTwist.attr("dWorldUpType").set(4)
        self.ikhAuxTwist.attr("dWorldUpAxis").set(3)
        self.ikhAuxTwist.attr("dWorldUpVectorZ").set(1.0)
        self.ikhAuxTwist.attr("dWorldUpVectorY").set(0.0)
        self.ikhAuxTwist.attr("dWorldUpVectorEndZ").set(1.0)
        self.ikhAuxTwist.attr("dWorldUpVectorEndY").set(0.0)
        pm.connectAttr(self.lowlegRollRef[0].attr("worldMatrix[0]"),
                       self.ikhAuxTwist.attr("dWorldUpMatrix"))
        pm.connectAttr(self.tws_ref.attr("worldMatrix[0]"),
                       self.ikhAuxTwist.attr("dWorldUpMatrixEnd"))
        pm.connectAttr(self.auxTwistChain[1].attr("rx"),
                       self.ikhLowLegTwist.attr("twist"))

        pm.parentConstraint(self.bone1, self.aux_npo, maintainOffset=True)

        # scale arm length for twist chain (not the squash and stretch)
        arclen_node = pm.arclen(self.uplegTwistCrv, ch=True)
        alAttrUpLeg = arclen_node.attr("arcLength")
        muldiv_nodeArm = pm.createNode("multiplyDivide")
        pm.connectAttr(arclen_node.attr("arcLength"),
                       muldiv_nodeArm.attr("input1X"))
        muldiv_nodeArm.attr("input2X").set(alAttrUpLeg.get())
        muldiv_nodeArm.attr("operation").set(2)
        for jnt in self.uplegTwistChain:
            pm.connectAttr(muldiv_nodeArm.attr("outputX"), jnt.attr("sx"))

        # scale forearm length for twist chain (not the squash and stretch)
        arclen_node = pm.arclen(self.lowlegTwistCrv, ch=True)
        alAttrLowLeg = arclen_node.attr("arcLength")
        muldiv_nodeLowLeg = pm.createNode("multiplyDivide")
        pm.connectAttr(arclen_node.attr("arcLength"),
                       muldiv_nodeLowLeg.attr("input1X"))
        muldiv_nodeLowLeg.attr("input2X").set(alAttrLowLeg.get())
        muldiv_nodeLowLeg.attr("operation").set(2)
        for jnt in self.lowlegTwistChain:
            pm.connectAttr(muldiv_nodeLowLeg.attr("outputX"), jnt.attr("sx"))

        # scale compensation for the first  twist join
        dm_node = pm.createNode("decomposeMatrix")
        pm.connectAttr(self.root.attr("worldMatrix[0]"),
                       dm_node.attr("inputMatrix"))
        pm.connectAttr(dm_node.attr("outputScale"),
                       self.uplegTwistChain[0].attr("inverseScale"))
        pm.connectAttr(dm_node.attr("outputScale"),
                       self.lowlegTwistChain[0].attr("inverseScale"))

        # tangent controls
        muldiv_node = pm.createNode("multiplyDivide")
        muldiv_node.attr("input2X").set(-1)
        pm.connectAttr(self.tws1A_npo.attr("rz"), muldiv_node.attr("input1X"))
        muldiv_nodeBias = pm.createNode("multiplyDivide")
        pm.connectAttr(muldiv_node.attr("outputX"),
                       muldiv_nodeBias.attr("input1X"))
        pm.connectAttr(self.roundness_att, muldiv_nodeBias.attr("input2X"))
        pm.connectAttr(muldiv_nodeBias.attr("outputX"),
                       self.tws1A_loc.attr("rz"))
        if self.negate:
            axis = "xz"
        else:
            axis = "-xz"
        applyop.aimCns(self.tws1A_npo,
                       self.tws0_loc,
                       axis=axis,
                       wupType=2,
                       wupVector=[0, 0, 1],
                       wupObject=self.mid_ctl,
                       maintainOffset=False)

        applyop.aimCns(self.lowlegTangentB_loc,
                       self.lowlegTangentA_npo,
                       axis=axis,
                       wupType=2,
                       wupVector=[0, 0, 1],
                       wupObject=self.mid_ctl,
                       maintainOffset=False)

        pm.pointConstraint(self.eff_loc, self.lowlegTangentB_loc)

        muldiv_node = pm.createNode("multiplyDivide")
        muldiv_node.attr("input2X").set(-1)
        pm.connectAttr(self.tws1B_npo.attr("rz"), muldiv_node.attr("input1X"))
        muldiv_nodeBias = pm.createNode("multiplyDivide")
        pm.connectAttr(muldiv_node.attr("outputX"),
                       muldiv_nodeBias.attr("input1X"))
        pm.connectAttr(self.roundness_att, muldiv_nodeBias.attr("input2X"))
        pm.connectAttr(muldiv_nodeBias.attr("outputX"),
                       self.tws1B_loc.attr("rz"))
        if self.negate:
            axis = "-xz"
        else:
            axis = "xz"
        applyop.aimCns(self.tws1B_npo,
                       self.tws2_loc,
                       axis=axis,
                       wupType=2,
                       wupVector=[0, 0, 1],
                       wupObject=self.mid_ctl,
                       maintainOffset=False)

        applyop.aimCns(self.uplegTangentA_loc,
                       self.uplegTangentB_npo,
                       axis=axis,
                       wupType=2,
                       wupVector=[0, 0, 1],
                       wupObject=self.mid_ctl,
                       maintainOffset=False)

        # Volume -------------------------------------------
        distA_node = node.createDistNode(self.tws0_loc, self.tws1_loc)
        distB_node = node.createDistNode(self.tws1_loc, self.tws2_loc)
        add_node = node.createAddNode(distA_node + ".distance",
                                      distB_node + ".distance")
        div_node = node.createDivNode(add_node + ".output",
                                      self.root_ctl.attr("sx"))

        # comp scaling issue
        dm_node = pm.createNode("decomposeMatrix")
        pm.connectAttr(self.root.attr("worldMatrix"), dm_node + ".inputMatrix")

        div_node2 = node.createDivNode(div_node + ".outputX",
                                       dm_node + ".outputScaleX")

        self.volDriver_att = div_node2 + ".outputX"

        # connecting tangent scaele compensation after volume to
        # avoid duplicate some nodes
        distA_node = node.createDistNode(self.tws0_loc, self.mid_ctl)
        distB_node = node.createDistNode(self.mid_ctl, self.tws2_loc)

        div_nodeUpLeg = node.createDivNode(distA_node + ".distance",
                                           dm_node.attr("outputScaleX"))

        div_node2 = node.createDivNode(div_nodeUpLeg + ".outputX",
                                       distA_node.attr("distance").get())

        pm.connectAttr(div_node2.attr("outputX"), self.tws1A_loc.attr("sx"))

        pm.connectAttr(div_node2.attr("outputX"),
                       self.uplegTangentA_loc.attr("sx"))

        div_nodeLowLeg = node.createDivNode(distB_node + ".distance",
                                            dm_node.attr("outputScaleX"))
        div_node2 = node.createDivNode(div_nodeLowLeg + ".outputX",
                                       distB_node.attr("distance").get())

        pm.connectAttr(div_node2.attr("outputX"), self.tws1B_loc.attr("sx"))
        pm.connectAttr(div_node2.attr("outputX"),
                       self.lowlegTangentB_loc.attr("sx"))

        # conection curve
        cnts = [
            self.uplegTangentA_loc, self.uplegTangentA_ctl,
            self.uplegTangentB_ctl, self.kneeTangent_ctl
        ]
        applyop.gear_curvecns_op(self.uplegTwistCrv, cnts)

        cnts = [
            self.kneeTangent_ctl, self.lowlegTangentA_ctl,
            self.lowlegTangentB_ctl, self.lowlegTangentB_loc
        ]
        applyop.gear_curvecns_op(self.lowlegTwistCrv, cnts)

        # Tangent controls vis
        for shp in self.uplegTangentA_ctl.getShapes():
            pm.connectAttr(self.tangentVis_att, shp.attr("visibility"))
        for shp in self.uplegTangentB_ctl.getShapes():
            pm.connectAttr(self.tangentVis_att, shp.attr("visibility"))
        for shp in self.lowlegTangentA_ctl.getShapes():
            pm.connectAttr(self.tangentVis_att, shp.attr("visibility"))
        for shp in self.lowlegTangentB_ctl.getShapes():
            pm.connectAttr(self.tangentVis_att, shp.attr("visibility"))
        for shp in self.kneeTangent_ctl.getShapes():
            pm.connectAttr(self.tangentVis_att, shp.attr("visibility"))

        # Divisions ----------------------------------------
        # at 0 or 1 the division will follow exactly the rotation of the
        # controler.. and we wont have this nice tangent + roll
        for i, div_cns in enumerate(self.div_cns):
            if i < (self.settings["div0"] + 2):
                mulmat_node = applyop.gear_mulmatrix_op(
                    self.uplegTwistChain[i] + ".worldMatrix",
                    div_cns + ".parentInverseMatrix")
                lastUpLegDiv = div_cns
            else:
                o_node = self.lowlegTwistChain[i - (self.settings["div0"] + 2)]
                mulmat_node = applyop.gear_mulmatrix_op(
                    o_node + ".worldMatrix", div_cns + ".parentInverseMatrix")
                lastLowLegDiv = div_cns
            dm_node = node.createDecomposeMatrixNode(mulmat_node + ".output")
            pm.connectAttr(dm_node + ".outputTranslate", div_cns + ".t")
            pm.connectAttr(dm_node + ".outputRotate", div_cns + ".r")

            # Squash n Stretch
            o_node = applyop.gear_squashstretch2_op(
                div_cns, None, pm.getAttr(self.volDriver_att), "x")
            pm.connectAttr(self.volume_att, o_node + ".blend")
            pm.connectAttr(self.volDriver_att, o_node + ".driver")
            pm.connectAttr(self.st_att[i], o_node + ".stretch")
            pm.connectAttr(self.sq_att[i], o_node + ".squash")

        # force translation for last loc arm and foreamr
        applyop.gear_mulmatrix_op(self.kneeTangent_ctl.worldMatrix,
                                  lastUpLegDiv.parentInverseMatrix,
                                  lastUpLegDiv, "t")
        applyop.gear_mulmatrix_op(self.tws2_loc.worldMatrix,
                                  lastLowLegDiv.parentInverseMatrix,
                                  lastLowLegDiv, "t")

        # NOTE: next line fix the issue on meters.
        # This is special case becasuse the IK solver from mGear use the
        # scale as lenght and we have shear
        # TODO: check for a more clean and elegant solution instead of
        # re-match the world matrix again
        transform.matchWorldTransform(self.fk_ctl[0], self.match_fk0_off)
        transform.matchWorldTransform(self.fk_ctl[1], self.match_fk1_off)
        transform.matchWorldTransform(self.fk_ctl[0], self.match_fk0)
        transform.matchWorldTransform(self.fk_ctl[1], self.match_fk1)

        # match IK/FK ref
        pm.parentConstraint(self.bone0, self.match_fk0_off, mo=True)
        pm.parentConstraint(self.bone1, self.match_fk1_off, mo=True)

        return
Пример #19
0
    def addJoint(self,
                 obj,
                 name,
                 newActiveJnt=None,
                 UniScale=False,
                 segComp=0,
                 gearMulMatrix=True):
        """Add joint as child of the active joint or under driver object.

        Args:
            obj (dagNode): The input driver object for the joint.
            name (str): The joint name.
            newActiveJnt (bool or dagNode): If a joint is pass, this joint will
                be the active joint and parent of the newly created joint.
            UniScale (bool): Connects the joint scale with the Z axis for a
                unifor scalin, if set Falsewill connect with each axis
                separated.
            segComp (bool): Set True or False the segment compensation in the
                joint..
            gearMulMatrix (bool): Use the custom gear_multiply matrix node, if
                False will use Maya's default mulMatrix node.

        Returns:
            dagNode: The newly created joint.

        """

        customName = self.getCustomJointName(len(self.jointList))

        if self.options["joint_rig"]:
            if newActiveJnt:
                self.active_jnt = newActiveJnt

            jnt = primitive.addJoint(self.active_jnt, 
                customName or self.getName(str(name) + "_jnt"), 
                transform.getTransform(obj))

            # Disconnect inversScale for better preformance
            if isinstance(self.active_jnt, pm.nodetypes.Joint):
                try:
                    pm.disconnectAttr(self.active_jnt.scale, jnt.inverseScale)

                except RuntimeError:
                    # This handle the situation where we have in between joints
                    # transformation due a negative scaling
                    pm.ungroup(jnt.getParent())
            # All new jnts are the active by default
            self.active_jnt = jnt

            if gearMulMatrix:
                mulmat_node = applyop.gear_mulmatrix_op(
                    obj + ".worldMatrix", jnt + ".parentInverseMatrix")
                dm_node = node.createDecomposeMatrixNode(
                    mulmat_node + ".output")
                m = mulmat_node.attr('output').get()
            else:
                mulmat_node = node.createMultMatrixNode(
                    obj + ".worldMatrix", jnt + ".parentInverseMatrix")
                dm_node = node.createDecomposeMatrixNode(
                    mulmat_node + ".matrixSum")
                m = mulmat_node.attr('matrixSum').get()
            pm.connectAttr(dm_node + ".outputTranslate", jnt + ".t")
            pm.connectAttr(dm_node + ".outputRotate", jnt + ".r")
            # TODO: fix squash stretch solver to scale the joint uniform
            # the next line cheat the uniform scaling only fo X or Y axis
            # oriented joints
            if self.options["force_uniScale"]:
                UniScale = True

            # invert negative scaling in Joints. We only inver Z axis, so is
            # the only axis that we are checking
            if dm_node.attr("outputScaleZ").get() < 0:
                mul_nod_invert = node.createMulNode(
                    dm_node.attr("outputScaleZ"),
                    -1)
                out_val = mul_nod_invert.attr("outputX")
            else:
                out_val = dm_node.attr("outputScaleZ")

            # connect scaling
            if UniScale:
                pm.connectAttr(out_val, jnt + ".sx")
                pm.connectAttr(out_val, jnt + ".sy")
                pm.connectAttr(out_val, jnt + ".sz")
            else:
                pm.connectAttr(dm_node.attr("outputScaleX"), jnt + ".sx")
                pm.connectAttr(dm_node.attr("outputScaleY"), jnt + ".sy")
                pm.connectAttr(out_val, jnt + ".sz")
                pm.connectAttr(dm_node + ".outputShear", jnt + ".shear")

            # Segment scale compensate Off to avoid issues with the global
            # scale
            jnt.setAttr("segmentScaleCompensate", segComp)

            jnt.setAttr("jointOrient", 0, 0, 0)

            # setting the joint orient compensation in order to have clean
            # rotation channels
            jnt.attr("jointOrientX").set(jnt.attr("rx").get())
            jnt.attr("jointOrientY").set(jnt.attr("ry").get())
            jnt.attr("jointOrientZ").set(jnt.attr("rz").get())

            im = m.inverse()

            if gearMulMatrix:
                mul_nod = applyop.gear_mulmatrix_op(
                    mulmat_node.attr('output'), im, jnt, 'r')
                dm_node2 = mul_nod.output.listConnections()[0]
            else:
                mul_nod = node.createMultMatrixNode(
                    mulmat_node.attr('matrixSum'), im, jnt, 'r')
                dm_node2 = mul_nod.matrixSum.listConnections()[0]

            # if jnt.attr("sz").get() < 0:
            if dm_node.attr("outputScaleZ").get() < 0:
                # if negative scaling we have to negate some axis for rotation
                neg_rot_node = pm.createNode("multiplyDivide")
                pm.setAttr(neg_rot_node + ".operation", 1)
                pm.connectAttr(dm_node2.outputRotate,
                               neg_rot_node + ".input1",
                               f=True)
                for v, axis in zip([-1, -1, 1], "XYZ"):
                    pm.setAttr(neg_rot_node + ".input2" + axis, v)
                pm.connectAttr(neg_rot_node + ".output",
                               jnt + ".r",
                               f=True)

            # set not keyable
            attribute.setNotKeyableAttributes(jnt)

        else:
            jnt = primitive.addJoint(obj, 
                customName or self.getName(str(name) + "_jnt"), 
                transform.getTransform(obj))
            pm.connectAttr(self.rig.jntVis_att, jnt.attr("visibility"))
            attribute.lockAttribute(jnt)

        self.addToGroup(jnt, "deformers")

        # This is a workaround due the evaluation problem with compound attr
        # TODO: This workaround, should be removed onces the evaluation issue
        # is fixed
        # github issue: Shifter: Joint connection: Maya evaluation Bug #210
        dm = jnt.r.listConnections(p=True, type="decomposeMatrix")
        if dm:
            at = dm[0]
            dm_node = at.node()
            pm.disconnectAttr(at, jnt.r)
            pm.connectAttr(dm_node.outputRotateX, jnt.rx)
            pm.connectAttr(dm_node.outputRotateY, jnt.ry)
            pm.connectAttr(dm_node.outputRotateZ, jnt.rz)

        dm = jnt.t.listConnections(p=True, type="decomposeMatrix")
        if dm:
            at = dm[0]
            dm_node = at.node()
            pm.disconnectAttr(at, jnt.t)
            pm.connectAttr(dm_node.outputTranslateX, jnt.tx)
            pm.connectAttr(dm_node.outputTranslateY, jnt.ty)
            pm.connectAttr(dm_node.outputTranslateZ, jnt.tz)

        # dm = jnt.s.listConnections(p=True, type="decomposeMatrix")
        # if dm:
        #     at = dm[0]
        #     dm_node = at.node()
        #     pm.disconnectAttr(at, jnt.s)
        #     pm.connectAttr(dm_node.outputScaleX, jnt.sx)
        #     pm.connectAttr(dm_node.outputScaleY, jnt.sy)
        #     pm.connectAttr(dm_node.outputScaleZ, jnt.sz)

        return jnt
Пример #20
0
    def addOperators(self):
        """Create operators and set the relations for the component rig

        Apply operators, constraints, expressions to the hierarchy.
        In order to keep the code clean and easier to debug,
        we shouldn't create any new object in this method.

        """
        # 1 bone chain Upv ref ==============================================
        self.ikHandleUpvRef = primitive.addIkHandle(
            self.root, self.getName("ikHandleArmChainUpvRef"),
            self.armChainUpvRef, "ikSCsolver")
        pm.pointConstraint(self.ik_ctl, self.ikHandleUpvRef)
        pm.parentConstraint(self.armChainUpvRef[0], self.upv_cns, mo=True)

        # Visibilities -------------------------------------
        # fk
        fkvis_node = node.createReverseNode(self.blend_att)

        for shp in self.fk0_ctl.getShapes():
            pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility"))
        for shp in self.fk1_ctl.getShapes():
            pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility"))
        for shp in self.fk2_ctl.getShapes():
            pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility"))

        # ik
        for shp in self.upv_ctl.getShapes():
            pm.connectAttr(self.blend_att, shp.attr("visibility"))
        for shp in self.ikcns_ctl.getShapes():
            pm.connectAttr(self.blend_att, shp.attr("visibility"))
        for shp in self.ik_ctl.getShapes():
            pm.connectAttr(self.blend_att, shp.attr("visibility"))
        for shp in self.line_ref.getShapes():
            pm.connectAttr(self.blend_att, shp.attr("visibility"))
        if self.settings["ikTR"]:
            for shp in self.ikRot_ctl.getShapes():
                pm.connectAttr(self.blend_att, shp.attr("visibility"))

        # Controls ROT order -----------------------------------
        attribute.setRotOrder(self.fk0_ctl, "XZY")
        attribute.setRotOrder(self.fk1_ctl, "XYZ")
        attribute.setRotOrder(self.fk2_ctl, "YZX")
        attribute.setRotOrder(self.ik_ctl, "XYZ")

        # IK Solver -----------------------------------------
        out = [self.bone0, self.bone1, self.ctrn_loc, self.eff_loc]
        o_node = applyop.gear_ikfk2bone_op(out, self.root, self.ik_ref,
                                           self.upv_ctl, self.fk_ctl[0],
                                           self.fk_ctl[1], self.fk_ref,
                                           self.length0, self.length1,
                                           self.negate)

        if self.settings["ikTR"]:
            # connect the control inputs
            outEff_dm = o_node.listConnections(c=True)[-1][1]

            inAttr = self.ikRot_npo.attr("translate")
            outEff_dm.attr("outputTranslate") >> inAttr

            outEff_dm.attr("outputScale") >> self.ikRot_npo.attr("scale")
            dm_node = node.createDecomposeMatrixNode(o_node.attr("outB"))
            dm_node.attr("outputRotate") >> self.ikRot_npo.attr("rotate")

            # rotation
            mulM_node = applyop.gear_mulmatrix_op(
                self.ikRot_ctl.attr("worldMatrix"),
                self.eff_loc.attr("parentInverseMatrix"))
            intM_node = applyop.gear_intmatrix_op(o_node.attr("outEff"),
                                                  mulM_node.attr("output"),
                                                  o_node.attr("blend"))
            dm_node = node.createDecomposeMatrixNode(intM_node.attr("output"))
            dm_node.attr("outputRotate") >> self.eff_loc.attr("rotate")
            transform.matchWorldTransform(self.fk2_ctl, self.ikRot_cns)

        # scale: this fix the scalin popping issue
        intM_node = applyop.gear_intmatrix_op(
            self.fk2_ctl.attr("worldMatrix"),
            self.ik_ctl_ref.attr("worldMatrix"), o_node.attr("blend"))
        mulM_node = applyop.gear_mulmatrix_op(
            intM_node.attr("output"), self.eff_loc.attr("parentInverseMatrix"))
        dm_node = node.createDecomposeMatrixNode(mulM_node.attr("output"))
        dm_node.attr("outputScale") >> self.eff_loc.attr("scale")

        pm.connectAttr(self.blend_att, o_node + ".blend")
        if self.negate:
            mulVal = -1
        else:
            mulVal = 1
        node.createMulNode(self.roll_att, mulVal, o_node + ".roll")
        pm.connectAttr(self.scale_att, o_node + ".scaleA")
        pm.connectAttr(self.scale_att, o_node + ".scaleB")
        pm.connectAttr(self.maxstretch_att, o_node + ".maxstretch")
        pm.connectAttr(self.slide_att, o_node + ".slide")
        pm.connectAttr(self.softness_att, o_node + ".softness")
        pm.connectAttr(self.reverse_att, o_node + ".reverse")

        # Twist references ---------------------------------

        pm.pointConstraint(self.mid_ctl_twst_ref,
                           self.tws1_npo,
                           maintainOffset=False)
        pm.connectAttr(self.mid_ctl.scaleX, self.tws1_loc.scaleX)
        pm.orientConstraint(self.mid_ctl_twst_ref,
                            self.tws1_npo,
                            maintainOffset=False)

        o_node = applyop.gear_mulmatrix_op(
            self.eff_loc.attr("worldMatrix"),
            self.root.attr("worldInverseMatrix"))
        dm_node = pm.createNode("decomposeMatrix")
        pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix")
        pm.connectAttr(dm_node + ".outputTranslate",
                       self.tws2_npo.attr("translate"))

        dm_node = pm.createNode("decomposeMatrix")
        pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix")
        pm.connectAttr(dm_node + ".outputRotate", self.tws2_npo.attr("rotate"))

        o_node = applyop.gear_mulmatrix_op(
            self.eff_loc.attr("worldMatrix"),
            self.tws2_rot.attr("parentInverseMatrix"))
        dm_node = pm.createNode("decomposeMatrix")
        pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix")
        attribute.setRotOrder(self.tws2_rot, "XYZ")
        pm.connectAttr(dm_node + ".outputRotate", self.tws2_rot + ".rotate")

        self.tws0_rot.setAttr("sx", .001)
        self.tws2_rot.setAttr("sx", .001)

        add_node = node.createAddNode(self.roundness_att, .001)
        pm.connectAttr(add_node + ".output", self.tws1_rot.attr("sx"))

        pm.connectAttr(self.armpit_roll_att, self.tws0_rot + ".rotateX")

        # Roll Shoulder
        applyop.splineIK(self.getName("rollRef"),
                         self.rollRef,
                         parent=self.root,
                         cParent=self.bone0)

        # Volume -------------------------------------------
        distA_node = node.createDistNode(self.tws0_loc, self.tws1_loc)
        distB_node = node.createDistNode(self.tws1_loc, self.tws2_loc)
        add_node = node.createAddNode(distA_node + ".distance",
                                      distB_node + ".distance")
        div_node = node.createDivNode(add_node + ".output",
                                      self.root.attr("sx"))

        dm_node = pm.createNode("decomposeMatrix")
        pm.connectAttr(self.root.attr("worldMatrix"), dm_node + ".inputMatrix")

        div_node2 = node.createDivNode(div_node + ".outputX",
                                       dm_node + ".outputScaleX")
        self.volDriver_att = div_node2 + ".outputX"

        if self.settings["extraTweak"]:
            for tweak_ctl in self.tweak_ctl:
                for shp in tweak_ctl.getShapes():
                    pm.connectAttr(self.tweakVis_att, shp.attr("visibility"))

        # Divisions ----------------------------------------
        # at 0 or 1 the division will follow exactly the rotation of the
        # controler.. and we wont have this nice tangent + roll
        for i, div_cns in enumerate(self.div_cns):

            if self.settings["supportJoints"]:
                if i < (self.settings["div0"] + 1):
                    perc = i * .5 / (self.settings["div0"] + 1.0)
                elif i < (self.settings["div0"] + 2):
                    perc = .49
                elif i < (self.settings["div0"] + 3):
                    perc = .50
                elif i < (self.settings["div0"] + 4):
                    perc = .51

                else:
                    perc = .5 + \
                        (i - self.settings["div0"] - 3.0) * .5 / \
                        (self.settings["div1"] + 1.0)
            else:
                if i < (self.settings["div0"] + 1):
                    perc = i * .5 / (self.settings["div0"] + 1.0)
                elif i < (self.settings["div0"] + 2):
                    perc = .501
                else:
                    perc = .5 + \
                        (i - self.settings["div0"] - 1.0) * .5 / \
                        (self.settings["div1"] + 1.0)

            perc = max(.001, min(.990, perc))

            # Roll
            if self.negate:
                o_node = applyop.gear_rollsplinekine_op(
                    div_cns, [self.tws2_rot, self.tws1_rot, self.tws0_rot],
                    1.0 - perc, 40)
            else:
                o_node = applyop.gear_rollsplinekine_op(
                    div_cns, [self.tws0_rot, self.tws1_rot, self.tws2_rot],
                    perc, 40)

            pm.connectAttr(self.resample_att, o_node + ".resample")
            pm.connectAttr(self.absolute_att, o_node + ".absolute")

            # Squash n Stretch
            o_node = applyop.gear_squashstretch2_op(
                div_cns, None, pm.getAttr(self.volDriver_att), "x")
            pm.connectAttr(self.volume_att, o_node + ".blend")
            pm.connectAttr(self.volDriver_att, o_node + ".driver")
            pm.connectAttr(self.st_att[i], o_node + ".stretch")
            pm.connectAttr(self.sq_att[i], o_node + ".squash")

        # match IK/FK ref
        pm.parentConstraint(self.bone0, self.match_fk0_off, mo=True)
        pm.parentConstraint(self.bone1, self.match_fk1_off, mo=True)
        if self.settings["ikTR"]:
            transform.matchWorldTransform(self.ikRot_ctl, self.match_ikRot)
            transform.matchWorldTransform(self.fk_ctl[2], self.match_fk2)

        return
Пример #21
0
    def addFkOperator(self, i, rootWorld_node, crv_node):

        fk_local_npo_xfoms = []
        if i not in [len(self.guide.apos), 0]:
            xform = getTransform(self.fk_local_npo[i])
            fk_local_npo_xfoms.append(xform)

        # break FK hierarchical orient
        if i not in [len(self.guide.apos), 0]:
            s = self.fk_ctl[i - 1]
            s2 = self.fk_npo[i]
            d = self.fk_local_npo[i]

            mulmat_node = applyop.gear_mulmatrix_op(s2.attr("matrix"), s.attr("matrix"))
            mulmat_node2 = applyop.gear_mulmatrix_op(mulmat_node.attr("output"), s2.attr("inverseMatrix"))

            dm_node = node.createDecomposeMatrixNode(mulmat_node2 + ".output")
            pm.connectAttr(dm_node + ".outputTranslate", d.attr("t"))

            check_list = (pm.Attribute, unicode, str)  # noqa
            cond = pm.createNode("condition")
            pm.setAttr(cond + ".operation", 4)  # greater
            attribute.connectSet(self.fk_collapsed_att, cond + ".secondTerm", check_list)
            attribute.connectSet(dm_node + ".outputRotate", cond + ".colorIfTrue", check_list)
            pm.setAttr(cond + ".colorIfFalseR", 0.)
            pm.setAttr(cond + ".colorIfFalseG", 0.)
            pm.setAttr(cond + ".colorIfFalseB", 0.)
            pm.connectAttr(cond + ".outColor", d.attr("r"))

        # References
        if i == 0:  # we add extra 10% to the first position
            u = (1.0 / (len(self.guide.apos) - 1.0)) / 10000
        else:
            u = getCurveUAtPoint(self.slv_crv, self.guide.apos[i])

        tmp_div_npo_transform = getTransform(self.div_cns_npo[i])  # to fix mismatch before/after later
        cns = applyop.pathCns(self.div_cns[i], self.slv_crv, False, u, True)
        cns.setAttr("frontAxis", 1)  # front axis is 'Y'
        cns.setAttr("upAxis", 0)  # front axis is 'X'

        # Roll
        # choose ik_ctls
        for _i, uv in enumerate(self.ik_uv_param):
            if u < uv:

                ik_a = self.ik_ctl[_i - 1]
                ik_b = self.ik_ctl[_i]

                roll_a = self.ik_decompose_rot[_i - 1]
                roll_b = self.ik_decompose_rot[_i]

                ratio = (uv - u) * (self.settings["ikNb"] - 1)
                break

        else:
            ik_a = self.ik_ctl[-2]
            ik_b = self.ik_ctl[-1]

            roll_a = self.ik_decompose_rot[-2]
            roll_b = self.ik_decompose_rot[-1]

            ratio = 1.

        intMatrix = applyop.gear_intmatrix_op(
            ik_a + ".worldMatrix",
            ik_b + ".worldMatrix",
            ratio)

        dm_node = node.createDecomposeMatrixNode(intMatrix + ".output")
        # pm.connectAttr(dm_node + ".outputRotate", self.twister[i].attr("rotate"))
        pm.parentConstraint(self.twister[i], self.ref_twist[i], maintainOffset=True)

        pm.connectAttr(self.ref_twist[i] + ".translate", cns + ".worldUpVector")
        self.div_cns_npo[i].setMatrix(tmp_div_npo_transform, worldSpace=True)

        # rotationdriver
        roll_ratio = (i + 1.00) / len(self.fk_ctl)
        mul1 = pm.createNode("multDoubleLinear")
        pm.connectAttr(roll_a.attr("outRoll"), mul1.attr("input1"))
        pm.setAttr(mul1.attr("input2"), ratio)

        mul2 = pm.createNode("multDoubleLinear")
        pm.connectAttr(roll_b.attr("outRoll"), mul2.attr("input1"))
        pm.setAttr(mul2.attr("input2"), (1. - ratio))

        add = pm.createNode("addDoubleLinear")
        pm.connectAttr(mul1.attr("output"), add.attr("input1"))
        pm.connectAttr(mul2.attr("output"), add.attr("input2"))

        compose_rot = pm.createNode("composeRotate")
        pm.setAttr(compose_rot.attr("axisOrientX"), 90.0)
        pm.setAttr(compose_rot.attr("axisOrientZ"), 90.0)
        pm.connectAttr(add.attr("output"), compose_rot.attr("roll"))
        pm.connectAttr(compose_rot.attr("outRotate"), self.div_roll_npo[i].attr("rotate"))

        # compensate scale reference
        div_node = node.createDivNode(
            [1, 1, 1],
            [rootWorld_node + ".outputScaleX",
             rootWorld_node + ".outputScaleY",
             rootWorld_node + ".outputScaleZ"])

        # Squash n Stretch
        op = applyop.gear_squashstretch2_op(self.scl_transforms[i],
                                            self.root,
                                            pm.arclen(self.slv_crv),
                                            "y",
                                            div_node + ".output")

        pm.connectAttr(self.volume_att, op + ".blend")
        pm.connectAttr(crv_node + ".arcLength", op + ".driver")
        # pm.connectAttr(self.st_att[i], op + ".stretch")
        # pm.connectAttr(self.sq_att[i], op + ".squash")

        # Controlers
        tmp_local_npo_transform = getTransform(self.fk_local_npo[i])  # to fix mismatch before/after later
        if i == 0:
            mulmat_node = applyop.gear_mulmatrix_op(
                self.div_roll_npo[i].attr("worldMatrix"),
                self.root.attr("worldInverseMatrix"))

            dm_node = node.createDecomposeMatrixNode(mulmat_node + ".output")
            pm.connectAttr(dm_node + ".outputTranslate", self.fk_npo[i].attr("t"))

        elif i != len(self.guide.apos) - 1:
            mulmat_node = applyop.gear_mulmatrix_op(
                self.div_roll_npo[i].attr("worldMatrix"),
                self.div_roll_npo[i - 1].attr("worldInverseMatrix"))

            dm_node = node.createDecomposeMatrixNode(mulmat_node + ".output")
            mul_node = node.createMulNode(div_node + ".output", dm_node + ".outputTranslate")
            pm.connectAttr(mul_node + ".output", self.fk_npo[i].attr("t"))

        else:
            pass

        if i == len(self.guide.apos) - 1:
            # pm.connectAttr(dm_node + ".outputRotate", self.fk_local_npo2.attr("r"))
            _ = pm.parentConstraint(self.ik_ctl[-1],
                                    self.fk_local_npo2,
                                    skipTranslate=("x", "y", "z"),
                                    maintainOffset=True)
        else:
            pm.connectAttr(dm_node + ".outputRotate", self.fk_npo[i].attr("r"))
        # self.addOperatorsOrientationLock(i, cns)
        self.fk_local_npo[i].setMatrix(tmp_local_npo_transform, worldSpace=True)

        # References
        if i < (len(self.fk_ctl) - 1):

            if self.negate:
                aim = (0., 1., 0.)
                upv = (0., 0., 1.)
            else:
                aim = (0., -1., 0.)
                upv = (0., 0., -1.)

            pm.aimConstraint(self.div_cns_npo[i + 1],
                             self.div_cns_npo[i],
                             mo=True,
                             worldUpType="object",
                             worldUpObject=self.fk_upvectors[i],
                             worldUpVector=(0., 1., 0.),
                             aimVector=aim,
                             upVector=upv,
                             )
Пример #22
0
def addJnt(obj=False,
           parent=False,
           noReplace=False,
           grp=None,
           jntName=None,
           *args):
    """Create one joint for each selected object.

    Args:
        obj (bool or dagNode, optional): The object to drive the new
            joint. If False will use the current selection.
        parent (bool or dagNode, optional): The parent for the joint.
            If False will try to parent to jnt_org. If jnt_org doesn't
            exist will parent the joint under the obj
        noReplace (bool, optional): If True will add the extension
            "_jnt" to the new joint name
        grp (pyNode or None, optional): The set to add the new joint.
            If none will use "rig_deformers_grp"
        *args: Maya's dummy

    Returns:
        pyNode: The New created joint.

    """
    if not obj:
        oSel = pm.selected()
    else:
        oSel = [obj]

    for obj in oSel:
        if not parent:
            try:
                oParent = pm.PyNode("jnt_org")
            except TypeError:
                oParent = obj
        else:
            oParent = parent
        if not jntName:
            if noReplace:
                jntName = "_".join(obj.name().split("_")) + "_jnt"
            else:
                jntName = "_".join(obj.name().split("_")[:-1]) + "_jnt"
        jnt = pm.createNode("joint", n=jntName)

        if grp:
            grp.add(jnt)
        else:
            try:
                defSet = pm.PyNode("rig_deformers_grp")
                pm.sets(defSet, add=jnt)
            except TypeError:
                pm.sets(n="rig_deformers_grp")
                defSet = pm.PyNode("rig_deformers_grp")
                pm.sets(defSet, add=jnt)

        oParent.addChild(jnt)

        jnt.setAttr("jointOrient", 0, 0, 0)
        try:
            mulmat_node = node.createMultMatrixNode(
                obj + ".worldMatrix", jnt + ".parentInverseMatrix")
            dm_node = node.createDecomposeMatrixNode(mulmat_node +
                                                     ".matrixSum")
            pm.connectAttr(dm_node + ".outputTranslate", jnt + ".t")
            pm.connectAttr(dm_node + ".outputRotate", jnt + ".r")
            pm.connectAttr(dm_node + ".outputScale", jnt + ".s")
        except RuntimeError:
            for axis in ["tx", "ty", "tz", "rx", "ry", "rz"]:
                jnt.attr(axis).set(0.0)

    return jnt
Пример #23
0
    def addOperators(self):
        """Create operators and set the relations for the component rig

        Apply operators, constraints, expressions to the hierarchy.
        In order to keep the code clean and easier to debug,
        we shouldn't create any new object in this method.

        """

        # Tangent position ---------------------------------
        # common part
        d = vector.getDistance(self.guide.apos[0], self.guide.apos[1])
        dist_node = node.createDistNode(self.ik0_ctl, self.ik1_ctl)
        rootWorld_node = node.createDecomposeMatrixNode(
            self.root.attr("worldMatrix"))

        div_node = node.createDivNode(dist_node + ".distance",
                                      rootWorld_node + ".outputScaleX")

        div_node = node.createDivNode(div_node + ".outputX", d)

        # tan0
        mul_node = node.createMulNode(self.tan0_att,
                                      self.tan0_npo.getAttr("ty"))

        res_node = node.createMulNode(mul_node + ".outputX",
                                      div_node + ".outputX")

        pm.connectAttr(res_node + ".outputX", self.tan0_npo.attr("ty"))

        # tan1
        mul_node = node.createMulNode(self.tan1_att,
                                      self.tan1_npo.getAttr("ty"))

        res_node = node.createMulNode(mul_node + ".outputX",
                                      div_node + ".outputX")

        pm.connectAttr(res_node + ".outputX", self.tan1_npo.attr("ty"))

        # Tangent Mid --------------------------------------
        if self.settings["centralTangent"]:
            tanIntMat = applyop.gear_intmatrix_op(
                self.tan0_npo.attr("worldMatrix"),
                self.tan1_npo.attr("worldMatrix"), .5)

            applyop.gear_mulmatrix_op(
                tanIntMat.attr("output"),
                self.tan_npo.attr("parentInverseMatrix[0]"), self.tan_npo)

            pm.connectAttr(self.tan_ctl.attr("translate"),
                           self.tan0_off.attr("translate"))

            pm.connectAttr(self.tan_ctl.attr("translate"),
                           self.tan1_off.attr("translate"))

        # Curves -------------------------------------------
        op = applyop.gear_curveslide2_op(self.slv_crv, self.mst_crv, 0, 1.5,
                                         .5, .5)

        pm.connectAttr(self.position_att, op + ".position")
        pm.connectAttr(self.maxstretch_att, op + ".maxstretch")
        pm.connectAttr(self.maxsquash_att, op + ".maxsquash")
        pm.connectAttr(self.softness_att, op + ".softness")

        # Volume driver ------------------------------------
        crv_node = node.createCurveInfoNode(self.slv_crv)

        # Division -----------------------------------------
        for i in range(self.settings["division"]):

            # References
            u = i / (self.settings["division"] - 1.0)

            cns = applyop.pathCns(self.div_cns[i], self.slv_crv, False, u,
                                  True)

            cns.setAttr("frontAxis", 1)  # front axis is 'Y'
            cns.setAttr("upAxis", 0)  # front axis is 'X'

            # Roll
            intMatrix = applyop.gear_intmatrix_op(
                self.ik0_ctl + ".worldMatrix", self.ik1_ctl + ".worldMatrix",
                u)

            dm_node = node.createDecomposeMatrixNode(intMatrix + ".output")
            pm.connectAttr(dm_node + ".outputRotate",
                           self.twister[i].attr("rotate"))

            pm.parentConstraint(self.twister[i],
                                self.ref_twist[i],
                                maintainOffset=True)

            pm.connectAttr(self.ref_twist[i] + ".translate",
                           cns + ".worldUpVector")

            # Squash n Stretch
            op = applyop.gear_squashstretch2_op(self.scl_transforms[i],
                                                self.root,
                                                pm.arclen(self.slv_crv), "y")

            pm.connectAttr(self.volume_att, op + ".blend")
            pm.connectAttr(crv_node + ".arcLength", op + ".driver")
            pm.connectAttr(self.st_att[i], op + ".stretch")
            pm.connectAttr(self.sq_att[i], op + ".squash")

        # Connections (Hooks) ------------------------------
        pm.pointConstraint(self.scl_transforms[0], self.cnx0)
        pm.scaleConstraint(self.scl_transforms[0], self.cnx0)
        pm.orientConstraint(self.ik0_ctl, self.cnx0)
        pm.pointConstraint(self.scl_transforms[-1], self.cnx1)
        pm.scaleConstraint(self.scl_transforms[-1], self.cnx1)
        pm.orientConstraint(self.ik1_ctl, self.cnx1)
Пример #24
0
    def ghostSliderForEyeBrow(self, ghostControls, surface, sliderParent):
        """Modify the ghost control behaviour to slide on top of a surface

        Args:
            ghostControls (dagNode): The ghost control
            surface (Surface): The NURBS surface
            sliderParent (dagNode): The parent for the slider.
        """

        if not isinstance(ghostControls, list):
            ghostControls = [ghostControls]

        def conn(ctl, driver, ghost):
            for attr in ["translate", "scale", "rotate"]:
                pm.connectAttr("{}.{}".format(ctl, attr),
                               "{}.{}".format(driver, attr))
                # pm.disconnectAttr("{}.{}".format(ctl, attr), "{}.{}".format(ghost, attr))

        surfaceShape = surface.getShape()
        sliders = []

        for i, ctlGhost in enumerate(ghostControls):
            ctl = pm.listConnections(ctlGhost, t="transform")[-1]
            t = ctl.getMatrix(worldSpace=True)
            scl = [1, 1, 1]
            if self.negate:
                scl = [-1, 1, 1]
            # t = transform.setMatrixScale(t, scl)

            gDriver = primitive.addTransform(
                ctlGhost.getParent(), "{}_slideDriver".format(ctl.name()), t)
            # conn(ctl, gDriver, ctlGhost)
            # print("ctlGhost.getParent: {}, ctl: {}, gDriver: {}, ctlGhost: {}".format(ctlGhost.getParent(), ctl, gDriver, ctlGhost))

            oParent = ctlGhost.getParent()
            npoName = "_".join(ctlGhost.name().split("_")[:-1]) + "_npo"
            npo = pm.PyNode(
                pm.createNode("transform", n=npoName, p=oParent, ss=True))

            npo.setTransformation(ctlGhost.getMatrix())
            ymt_util.setKeyableAttributesDontLockVisibility(npo, [])
            pm.parent(ctlGhost, npo)

            slider = primitive.addTransform(sliderParent,
                                            ctl.name() + "_slideDriven", t)
            sliders.append(slider)

            down, _, up = findPathAtoB(ctl, sliderParent)
            mul_node = pm.createNode("multMatrix")
            j = k = 0
            for j, d in enumerate(down):
                d.attr("matrix") >> mul_node.attr("matrixIn[{}]".format(j))
            _.attr("matrix") >> mul_node.attr("matrixIn[{}]".format(j + 1))
            for k, u in enumerate(up):
                u.attr("inverseMatrix") >> mul_node.attr(
                    "matrixIn[{}]".format(k + j + 1))

            dm_node = node.createDecomposeMatrixNode(
                mul_node.attr("matrixSum"))

            cps_node = pm.createNode("closestPointOnSurface")
            dm_node.attr("outputTranslate") >> cps_node.attr("inPosition")
            surfaceShape.attr("local") >> cps_node.attr("inputSurface")
            cps_node.attr("position") >> slider.attr("translate")

            if self.negate:
                aim = [0, 0, -1]
            else:
                aim = [0, 0, 1]
            pm.normalConstraint(surfaceShape,
                                slider,
                                aimVector=aim,
                                upVector=[0, 1, 0],
                                worldUpType="objectrotation",
                                worldUpVector=[0, 1, 0],
                                worldUpObject=gDriver)
            pm.parent(ctlGhost.getParent(), slider)

            pm.parent(gDriver.getParent(), self.mainControl)
Пример #25
0
def createRivetTweak(mesh,
                     edgePair,
                     name,
                     parent=None,
                     ctlParent=None,
                     jntParent=None,
                     color=[0, 0, 0],
                     size=.04,
                     defSet=None,
                     ctlSet=None,
                     side=None,
                     gearMulMatrix=True,
                     attach_rot=False,
                     inputMesh=None):
    """Create a tweak joint attached to the mesh using a rivet

    Args:
        mesh (mesh): The object to add the tweak
        edgePair (pair list): The edge pair to create the rivet
        name (str): The name for the tweak
        parent (None or dagNode, optional): The parent for the tweak
        jntParent (None or dagNode, optional): The parent for the joints
        ctlParent (None or dagNode, optional): The parent for the tweak control
        color (list, optional): The color for the control
        size (float, optional): Size of the control
        defSet (None or set, optional): Deformer set to add the joints
        ctlSet (None or set, optional): the set to add the controls
        side (None, str): String to set the side. Valid values are L, R or C.
            If the side is not set or the value is not valid, the side will be
            set automatically based on the world position
        gearMulMatrix (bool, optional): If False will use Maya default multiply
            matrix node

    Returns:
        PyNode: The tweak control
    """
    blendShape = blendShapes.getBlendShape(mesh)
    if not inputMesh:
        inputMesh = blendShape.listConnections(sh=True, t="shape", d=False)[0]

    oRivet = rivet.rivet()
    base = oRivet.create(inputMesh, edgePair[0], edgePair[1], parent)
    # get side
    if not side or side not in ["L", "R", "C"]:
        if base.getTranslation(space='world')[0] < -0.01:
            side = "R"
        elif base.getTranslation(space='world')[0] > 0.01:
            side = "L"
        else:
            side = "C"

    nameSide = name + "_tweak_" + side
    pm.rename(base, nameSide)

    if not ctlParent:
        ctlParent = base
        ctl_parent_tag = None
    else:
        ctl_parent_tag = ctlParent

    # Joints NPO
    npo = pm.PyNode(pm.createNode("transform",
                                  n=nameSide + "_npo",
                                  p=ctlParent,
                                  ss=True))
    if attach_rot:
        # npo.setTranslation(base.getTranslation(space="world"), space="world")
        pm.parentConstraint(base, npo, mo=False)
    else:
        pm.pointConstraint(base, npo, mo=False)

    # create joints
    if not jntParent:
        jntParent = npo
        matrix_cnx = False
    else:
        # need extra connection to ensure is moving with th npo, even is
        # not child of npo
        matrix_cnx = True

    jointBase = primitive.addJoint(jntParent, nameSide + "_jnt_lvl")
    joint = primitive.addJoint(jointBase, nameSide + "_jnt")

    # reset axis and invert behaviour
    for axis in "XYZ":
        pm.setAttr(jointBase + ".jointOrient" + axis, 0)
        pm.setAttr(npo + ".translate" + axis, 0)
        # pm.setAttr(jointBase + ".translate" + axis, 0)

    pp = npo.getParent()
    pm.parent(npo, w=True)
    for axis in "xyz":
        npo.attr("r" + axis).set(0)
    if side == "R":
        npo.attr("ry").set(180)
        npo.attr("sz").set(-1)
    pm.parent(npo, pp)

    dm_node = None

    if matrix_cnx:
        mulmat_node = applyop.gear_mulmatrix_op(
            npo + ".worldMatrix", jointBase + ".parentInverseMatrix")
        dm_node = node.createDecomposeMatrixNode(
            mulmat_node + ".output")
        m = mulmat_node.attr('output').get()
        pm.connectAttr(dm_node + ".outputTranslate", jointBase + ".t")
        pm.connectAttr(dm_node + ".outputRotate", jointBase + ".r")

        # invert negative scaling in Joints. We only inver Z axis, so is
        # the only axis that we are checking
        print(dm_node.attr("outputScaleZ").get())
        if dm_node.attr("outputScaleZ").get() < 0:
            mul_nod_invert = node.createMulNode(
                dm_node.attr("outputScaleZ"),
                -1)
            out_val = mul_nod_invert.attr("outputX")
        else:
            out_val = dm_node.attr("outputScaleZ")

        pm.connectAttr(dm_node.attr("outputScaleX"), jointBase + ".sx")
        pm.connectAttr(dm_node.attr("outputScaleY"), jointBase + ".sy")
        pm.connectAttr(out_val, jointBase + ".sz")
        pm.connectAttr(dm_node + ".outputShear", jointBase + ".shear")

        # Segment scale compensate Off to avoid issues with the global
        # scale
        jointBase.setAttr("segmentScaleCompensate", 0)
        joint.setAttr("segmentScaleCompensate", 0)

        jointBase.setAttr("jointOrient", 0, 0, 0)

        # setting the joint orient compensation in order to have clean
        # rotation channels
        jointBase.attr("jointOrientX").set(jointBase.attr("rx").get())
        jointBase.attr("jointOrientY").set(jointBase.attr("ry").get())
        jointBase.attr("jointOrientZ").set(jointBase.attr("rz").get())

        im = m.inverse()

        if gearMulMatrix:
            mul_nod = applyop.gear_mulmatrix_op(
                mulmat_node.attr('output'), im, jointBase, 'r')
            dm_node2 = mul_nod.output.listConnections()[0]
        else:
            mul_nod = node.createMultMatrixNode(
                mulmat_node.attr('matrixSum'), im, jointBase, 'r')
            dm_node2 = mul_nod.matrixSum.listConnections()[0]

        if dm_node.attr("outputScaleZ").get() < 0:
            negateTransformConnection(dm_node2.outputRotate, jointBase.rotate)

    else:
        resetJntLocalSRT(jointBase)

    # hidding joint base by changing the draw mode
    pm.setAttr(jointBase + ".drawStyle", 2)
    if not defSet:
        try:
            defSet = pm.PyNode("rig_deformers_grp")
        except TypeError:
            pm.sets(n="rig_deformers_grp", empty=True)
            defSet = pm.PyNode("rig_deformers_grp")
    pm.sets(defSet, add=joint)

    controlType = "sphere"
    o_icon = icon.create(npo,
                         nameSide + "_ctl",
                         datatypes.Matrix(),
                         color,
                         controlType,
                         w=size)

    attribute.addAttribute(o_icon, "isCtl", "bool", keyable=False)

    transform.resetTransform(o_icon)
    if dm_node and dm_node.attr("outputScaleZ").get() < 0:
        pm.connectAttr(o_icon.scale, joint.scale)
        negateTransformConnection(o_icon.rotate, joint.rotate)
        negateTransformConnection(o_icon.translate,
                                  joint.translate,
                                  [1, 1, -1])

    else:
        for t in [".translate", ".scale", ".rotate"]:
            pm.connectAttr(o_icon + t, joint + t)

    # create the attributes to handlde mirror and symetrical pose
    attribute.addAttribute(
        o_icon, "invTx", "bool", 0, keyable=False, niceName="Invert Mirror TX")
    attribute.addAttribute(
        o_icon, "invTy", "bool", 0, keyable=False, niceName="Invert Mirror TY")
    attribute.addAttribute(
        o_icon, "invTz", "bool", 0, keyable=False, niceName="Invert Mirror TZ")
    attribute.addAttribute(
        o_icon, "invRx", "bool", 0, keyable=False, niceName="Invert Mirror RX")
    attribute.addAttribute(
        o_icon, "invRy", "bool", 0, keyable=False, niceName="Invert Mirror RY")
    attribute.addAttribute(
        o_icon, "invRz", "bool", 0, keyable=False, niceName="Invert Mirror RZ")
    attribute.addAttribute(
        o_icon, "invSx", "bool", 0, keyable=False, niceName="Invert Mirror SX")
    attribute.addAttribute(
        o_icon, "invSy", "bool", 0, keyable=False, niceName="Invert Mirror SY")
    attribute.addAttribute(
        o_icon, "invSz", "bool", 0, keyable=False, niceName="Invert Mirror SZ")

    # magic of doritos connection
    pre_bind_matrix_connect(mesh, joint, jointBase)

    # add control tag
    node.add_controller_tag(o_icon, ctl_parent_tag)

    if not ctlSet:
        try:
            ctlSet = pm.PyNode("rig_controllers_grp")
        except TypeError:
            pm.sets(n="rig_controllers_grp", empty=True)
            ctlSet = pm.PyNode("rig_controllers_grp")
    pm.sets(ctlSet, add=o_icon)

    return o_icon
Пример #26
0
    def addOperators(self):
        """Create operators and set the relations for the component rig

        Apply operators, constraints, expressions to the hierarchy.
        In order to keep the code clean and easier to debug,
        we shouldn't create any new object in this method.

        """
        dm_node_scl = node.createDecomposeMatrixNode(self.root.worldMatrix)
        if self.settings["keepLength"]:
            arclen_node = pm.arclen(self.mst_crv, ch=True)
            alAttr = pm.getAttr(arclen_node + ".arcLength")
            ration_node = node.createMulNode(self.length_ratio_att, alAttr)

            pm.addAttr(self.mst_crv, ln="length_ratio", k=True, w=True)
            node.createDivNode(arclen_node.arcLength, ration_node.outputX,
                               self.mst_crv.length_ratio)

            div_node_scl = node.createDivNode(self.mst_crv.length_ratio,
                                              dm_node_scl.outputScaleX)

        step = 1.000 / (self.def_number - 1)
        u = 0.000
        for i in range(self.def_number):
            cnsUpv = applyop.pathCns(self.upv_cns[i],
                                     self.upv_crv,
                                     cnsType=False,
                                     u=u,
                                     tangent=False)

            cns = applyop.pathCns(self.div_cns[i], self.mst_crv, False, u,
                                  True)

            # Connectiong the scale for scaling compensation
            for axis, AX in zip("xyz", "XYZ"):
                pm.connectAttr(dm_node_scl.attr("outputScale{}".format(AX)),
                               self.div_cns[i].attr("s{}".format(axis)))

            if self.settings["keepLength"]:

                div_node2 = node.createDivNode(u, div_node_scl.outputX)

                cond_node = node.createConditionNode(div_node2.input1X,
                                                     div_node2.outputX, 4,
                                                     div_node2.input1X,
                                                     div_node2.outputX)

                pm.connectAttr(cond_node + ".outColorR", cnsUpv + ".uValue")
                pm.connectAttr(cond_node + ".outColorR", cns + ".uValue")

            cns.setAttr("worldUpType", 1)
            cns.setAttr("frontAxis", 0)
            cns.setAttr("upAxis", 1)

            pm.connectAttr(self.upv_cns[i].attr("worldMatrix[0]"),
                           cns.attr("worldUpMatrix"))
            u += step

        if self.settings["keepLength"]:
            # add the safty distance offset
            self.tweakTip_npo.attr("tx").set(self.off_dist)
            # connect vis line ref
            for shp in self.line_ref.getShapes():
                pm.connectAttr(self.ikVis_att, shp.attr("visibility"))

        for ctl in self.tweak_ctl:
            for shp in ctl.getShapes():
                pm.connectAttr(self.ikVis_att, shp.attr("visibility"))
        for ctl in self.fk_ctl:
            for shp in ctl.getShapes():
                pm.connectAttr(self.fkVis_att, shp.attr("visibility"))

        if self.settings["extraTweak"]:
            for tweak_ctl in self.extratweak_ctl:
                for shp in tweak_ctl.getShapes():
                    pm.connectAttr(self.tweakVis_att, shp.attr("visibility"))
Пример #27
0
def ghostSlider(ghostControls, surface, sliderParent):
    """Modify the ghost control behaviour to slide on top of a surface

    Args:
        ghostControls (dagNode): The ghost control
        surface (Surface): The NURBS surface
        sliderParent (dagNode): The parent for the slider.
    """
    if not isinstance(ghostControls, list):
        ghostControls = [ghostControls]

    # Seleccionamos los controles Ghost que queremos mover sobre el surface

    surfaceShape = surface.getShape()

    for ctlGhost in ghostControls:
        ctl = pm.listConnections(ctlGhost, t="transform")[-1]
        t = ctl.getMatrix(worldSpace=True)

        gDriver = primitive.addTransform(ctlGhost.getParent(),
                                         ctl.name() + "_slideDriver", t)

        try:
            pm.connectAttr(ctl + ".translate", gDriver + ".translate")
            pm.disconnectAttr(ctl + ".translate", ctlGhost + ".translate")
        except RuntimeError:
            pass

        try:
            pm.connectAttr(ctl + ".scale", gDriver + ".scale")
            pm.disconnectAttr(ctl + ".scale", ctlGhost + ".scale")
        except RuntimeError:
            pass

        try:
            pm.connectAttr(ctl + ".rotate", gDriver + ".rotate")
            pm.disconnectAttr(ctl + ".rotate", ctlGhost + ".rotate")
        except RuntimeError:
            pass

        oParent = ctlGhost.getParent()
        npoName = "_".join(ctlGhost.name().split("_")[:-1]) + "_npo"
        oTra = pm.PyNode(
            pm.createNode("transform", n=npoName, p=oParent, ss=True))
        oTra.setTransformation(ctlGhost.getMatrix())
        pm.parent(ctlGhost, oTra)

        slider = primitive.addTransform(sliderParent,
                                        ctl.name() + "_slideDriven", t)

        # connexion

        dm_node = node.createDecomposeMatrixNode(
            gDriver.attr("worldMatrix[0]"))
        cps_node = pm.createNode("closestPointOnSurface")
        dm_node.attr("outputTranslate") >> cps_node.attr("inPosition")
        surfaceShape.attr("worldSpace[0]") >> cps_node.attr("inputSurface")
        cps_node.attr("position") >> slider.attr("translate")

        pm.normalConstraint(surfaceShape,
                            slider,
                            aimVector=[0, 0, 1],
                            upVector=[0, 1, 0],
                            worldUpType="objectrotation",
                            worldUpVector=[0, 1, 0],
                            worldUpObject=gDriver)

        pm.parent(ctlGhost.getParent(), slider)
Пример #28
0
    def addOperators(self):
        """Create operators and set the relations for the component rig

        Apply operators, constraints, expressions to the hierarchy.
        In order to keep the code clean and easier to debug,
        we shouldn't create any new object in this method.

        """

        # Curves -------------------------------------------
        op = applyop.gear_curveslide2_op(
            self.slv_crv, self.mst_crv, 0, 1.5, .5, .5)

        pm.connectAttr(self.position_att, op + ".position")
        pm.connectAttr(self.lenght_att, op + ".maxstretch")

        op = applyop.gear_curveslide2_op(
            self.slv_upv_crv, self.upv_crv, 0, 1.5, .5, .5)

        pm.connectAttr(self.position_att, op + ".position")
        pm.connectAttr(self.lenght_att, op + ".maxstretch")

        for tang in self.tangentsCtl:
            for shp in tang.getShapes():
                pm.connectAttr(self.tangentsVis_att, shp.attr("visibility"))

        for twnpo, fkctl in zip(self.tweak_npo, self.fk_ctl):
            intMatrix = applyop.gear_intmatrix_op(
                fkctl.attr("worldMatrix"),
                fkctl.getParent().attr("worldMatrix"),
                .5)

            applyop.gear_mulmatrix_op(intMatrix.attr("output"),
                                      twnpo.attr("parentInverseMatrix[0]"),
                                      twnpo)

        dm_node_scl = node.createDecomposeMatrixNode(self.root.worldMatrix)
        if self.settings["keepLength"]:
            arclen_node = pm.arclen(self.slv_crv, ch=True)
            alAttr = pm.getAttr(arclen_node + ".arcLength")

            pm.addAttr(self.slv_crv, ln="length_ratio", k=True, w=True)
            node.createDivNode(arclen_node.arcLength,
                               alAttr,
                               self.slv_crv.length_ratio)

            div_node_scl = node.createDivNode(self.slv_crv.length_ratio,
                                              dm_node_scl.outputScaleX)

        step = 1.000 / (self.def_number - 1)
        u = 0.000
        for i in range(self.def_number):
            mult_node = node.createMulNode(u, self.lenght_att)
            cnsUpv = applyop.pathCns(self.upv_cns[i],
                                     self.slv_upv_crv,
                                     cnsType=False,
                                     u=u,
                                     tangent=False)
            pm.connectAttr(mult_node.outputX, cnsUpv.uValue)

            cns = applyop.pathCns(
                self.div_cns[i], self.slv_crv, False, u, True)
            pm.connectAttr(mult_node.outputX, cns.uValue)

            # Connectiong the scale for scaling compensation
            for axis, AX in zip("xyz", "XYZ"):
                pm.connectAttr(dm_node_scl.attr("outputScale{}".format(AX)),
                               self.div_cns[i].attr("s{}".format(axis)))

            if self.settings["keepLength"]:

                div_node2 = node.createDivNode(u, div_node_scl.outputX)

                cond_node = node.createConditionNode(div_node2.input1X,
                                                     div_node2.outputX,
                                                     4,
                                                     div_node2.input1X,
                                                     div_node2.outputX)

                # pm.connectAttr(cond_node + ".outColorR",
                #                cnsUpv + ".uValue")
                # pm.connectAttr(cond_node + ".outColorR",
                #                cns + ".uValue")
                pm.connectAttr(cond_node + ".outColorR",
                               mult_node + ".input1X", f=True)

            # Connect the scaling for self.Extra_tweak_npo
            et_npo = self.Extra_tweak_npo[i]
            pm.connectAttr(self.spin_att, et_npo + ".rz")

            base_node = node.createMulNode(self.baseSize_att, 1.00000 - u, output=None)
            tip_node = node.createMulNode(self.tipSize_att, u, output=None)
            sum_node = node.createPlusMinusAverage1D([base_node.outputX, tip_node.outputX])
            # print et_npo
            pm.connectAttr(sum_node.output1D, et_npo.scaleX, f=True)
            pm.connectAttr(sum_node.output1D, et_npo.scaleY, f=True)
            pm.connectAttr(sum_node.output1D, et_npo.scaleZ, f=True)

            cns.setAttr("worldUpType", 1)
            cns.setAttr("frontAxis", 0)
            cns.setAttr("upAxis", 1)

            pm.connectAttr(self.upv_cns[i].attr("worldMatrix[0]"),
                           cns.attr("worldUpMatrix"))
            u += step

        for et in self.Extra_tweak_ctl:
            for shp in et.getShapes():
                pm.connectAttr(self.tweakVis_att, shp.attr("visibility"))

        if self.settings["keepLength"]:
            # add the safty distance offset
            self.tweakTip_npo.attr("tx").set(self.off_dist)
            # connect vis line ref
            for shp in self.line_ref.getShapes():
                pm.connectAttr(self.ikVis_att, shp.attr("visibility"))

        for ctl in self.tweak_ctl:
            for shp in ctl.getShapes():
                pm.connectAttr(self.ikVis_att, shp.attr("visibility"))
        for ctl in self.fk_ctl:
            for shp in ctl.getShapes():
                pm.connectAttr(self.fkVis_att, shp.attr("visibility"))
Пример #29
0
    def addOperators(self):
        """Create operators and set the relations for the component rig

        Apply operators, constraints, expressions to the hierarchy.
        In order to keep the code clean and easier to debug,
        we shouldn't create any new object in this method.

        """

        # Auto bend ----------------------------
        if self.settings["autoBend"]:
            mul_node = node.createMulNode(
                [self.autoBendChain[0].ry, self.autoBendChain[0].rz],
                [self.sideBend_att, self.frontBend_att])

            mul_node.outputX >> self.ik1autoRot_lvl.rz
            mul_node.outputY >> self.ik1autoRot_lvl.rx

            self.ikHandleAutoBend = primitive.addIkHandle(
                self.autoBend_ctl, self.getName("ikHandleAutoBend"),
                self.autoBendChain, "ikSCsolver")

        # Tangent position ---------------------------------
        # common part
        d = vector.getDistance(self.guide.apos[0], self.guide.apos[-1])
        dist_node = node.createDistNode(self.ik0_ctl, self.ik1_ctl)
        rootWorld_node = node.createDecomposeMatrixNode(
            self.root.attr("worldMatrix"))

        div_node = node.createDivNode(dist_node + ".distance",
                                      rootWorld_node + ".outputScaleX")

        div_node = node.createDivNode(div_node + ".outputX", d)

        # tan0
        mul_node = node.createMulNode(self.tan0_att,
                                      self.tan0_npo.getAttr("ty"))

        res_node = node.createMulNode(mul_node + ".outputX",
                                      div_node + ".outputX")

        pm.connectAttr(res_node + ".outputX", self.tan0_npo.attr("ty"))

        # tan1
        mul_node = node.createMulNode(self.tan1_att,
                                      self.tan1_npo.getAttr("ty"))

        res_node = node.createMulNode(mul_node + ".outputX",
                                      div_node + ".outputX")

        pm.connectAttr(res_node + ".outputX", self.tan1_npo.attr("ty"))

        # Tangent Mid --------------------------------------
        if self.settings["centralTangent"]:
            tanIntMat = applyop.gear_intmatrix_op(
                self.tan0_npo.attr("worldMatrix"),
                self.tan1_npo.attr("worldMatrix"), .5)

            applyop.gear_mulmatrix_op(
                tanIntMat.attr("output"),
                self.tan_npo.attr("parentInverseMatrix[0]"), self.tan_npo)

            pm.connectAttr(self.tan_ctl.attr("translate"),
                           self.tan0_off.attr("translate"))

            pm.connectAttr(self.tan_ctl.attr("translate"),
                           self.tan1_off.attr("translate"))

        # Curves -------------------------------------------
        op = applyop.gear_curveslide2_op(self.slv_crv, self.mst_crv, 0, 1.5,
                                         .5, .5)

        pm.connectAttr(self.position_att, op + ".position")
        pm.connectAttr(self.maxstretch_att, op + ".maxstretch")
        pm.connectAttr(self.maxsquash_att, op + ".maxsquash")
        pm.connectAttr(self.softness_att, op + ".softness")

        # Volume driver ------------------------------------
        crv_node = node.createCurveInfoNode(self.slv_crv)

        # Division -----------------------------------------
        for i in range(self.settings["division"]):

            # References
            u = i / (self.settings["division"] - 1.0)
            if i == 0:  # we add extra 10% to the first vertebra
                u = (1.0 / (self.settings["division"] - 1.0)) / 10

            cns = applyop.pathCns(self.div_cns[i], self.slv_crv, False, u,
                                  True)

            cns.setAttr("frontAxis", 1)  # front axis is 'Y'
            cns.setAttr("upAxis", 0)  # front axis is 'X'

            # Roll
            intMatrix = applyop.gear_intmatrix_op(
                self.ik0_ctl + ".worldMatrix", self.ik1_ctl + ".worldMatrix",
                u)

            dm_node = node.createDecomposeMatrixNode(intMatrix + ".output")
            pm.connectAttr(dm_node + ".outputRotate",
                           self.twister[i].attr("rotate"))

            pm.parentConstraint(self.twister[i],
                                self.ref_twist[i],
                                maintainOffset=True)

            pm.connectAttr(self.ref_twist[i] + ".translate",
                           cns + ".worldUpVector")

            # compensate scale reference
            div_node = node.createDivNode([1, 1, 1], [
                rootWorld_node + ".outputScaleX", rootWorld_node +
                ".outputScaleY", rootWorld_node + ".outputScaleZ"
            ])

            # Squash n Stretch
            op = applyop.gear_squashstretch2_op(self.scl_transforms[i],
                                                self.root,
                                                pm.arclen(self.slv_crv), "y",
                                                div_node + ".output")

            pm.connectAttr(self.volume_att, op + ".blend")
            pm.connectAttr(crv_node + ".arcLength", op + ".driver")
            pm.connectAttr(self.st_att[i], op + ".stretch")
            pm.connectAttr(self.sq_att[i], op + ".squash")

            # Controlers
            if i == 0:
                mulmat_node = applyop.gear_mulmatrix_op(
                    self.div_cns[i].attr("worldMatrix"),
                    self.root.attr("worldInverseMatrix"))

                dm_node = node.createDecomposeMatrixNode(mulmat_node +
                                                         ".output")

                pm.connectAttr(dm_node + ".outputTranslate",
                               self.fk_npo[i].attr("t"))

            else:
                mulmat_node = applyop.gear_mulmatrix_op(
                    self.div_cns[i].attr("worldMatrix"),
                    self.div_cns[i - 1].attr("worldInverseMatrix"))

                dm_node = node.createDecomposeMatrixNode(mulmat_node +
                                                         ".output")

                mul_node = node.createMulNode(div_node + ".output",
                                              dm_node + ".outputTranslate")

                pm.connectAttr(mul_node + ".output", self.fk_npo[i].attr("t"))

            pm.connectAttr(dm_node + ".outputRotate", self.fk_npo[i].attr("r"))

            # Orientation Lock
            if i == 0:
                dm_node = node.createDecomposeMatrixNode(self.ik0_ctl +
                                                         ".worldMatrix")

                blend_node = node.createBlendNode(
                    [dm_node + ".outputRotate%s" % s for s in "XYZ"],
                    [cns + ".rotate%s" % s for s in "XYZ"], self.lock_ori0_att)

                self.div_cns[i].attr("rotate").disconnect()

                pm.connectAttr(blend_node + ".output",
                               self.div_cns[i] + ".rotate")

            elif i == self.settings["division"] - 1:
                dm_node = node.createDecomposeMatrixNode(self.ik1_ctl +
                                                         ".worldMatrix")

                blend_node = node.createBlendNode(
                    [dm_node + ".outputRotate%s" % s for s in "XYZ"],
                    [cns + ".rotate%s" % s for s in "XYZ"], self.lock_ori1_att)

                self.div_cns[i].attr("rotate").disconnect()
                pm.connectAttr(blend_node + ".output",
                               self.div_cns[i] + ".rotate")

        # Connections (Hooks) ------------------------------
        pm.parentConstraint(self.hip_lvl, self.cnx0)
        pm.scaleConstraint(self.hip_lvl, self.cnx0)
        pm.parentConstraint(self.scl_transforms[-1], self.cnx1)
        pm.scaleConstraint(self.scl_transforms[-1], self.cnx1)
def ghostSliderForMouth(ghostControls, intTra, surface, sliderParent):
    """Modify the ghost control behaviour to slide on top of a surface

    Args:
        ghostControls (dagNode): The ghost control
        surface (Surface): The NURBS surface
        sliderParent (dagNode): The parent for the slider.
    """
    if not isinstance(ghostControls, list):
        ghostControls = [ghostControls]

    def conn(ctl, driver, ghost):
        for attr in ["translate", "scale", "rotate"]:
            try:
                pm.connectAttr("{}.{}".format(ctl, attr),
                               "{}.{}".format(driver, attr))
                pm.disconnectAttr("{}.{}".format(ctl, attr),
                                  "{}.{}".format(ghost, attr))
            except RuntimeError:
                pass

    def connCenter(ctl, driver, ghost):
        # mul_node1 = pm.createNode("multMatrix")
        # mul_node2 = pm.createNode("multMatrix")

        down, _, up = ymt_util.findPathAtoB(ctl, driver)
        mult = pm.createNode("multMatrix")

        for i, d in enumerate(down):
            d.attr("matrix") >> mult.attr("matrixIn[{}]".format(i))

        for j, u in enumerate(up[:-1]):
            u.attr("inverseMatrix") >> mult.attr(
                "matrixIn[{}]".format(i + j + 1))

        decomp = pm.createNode("decomposeMatrix")

        dm_node = node.createDecomposeMatrixNode(mult.attr("matrixSum"))

        for attr in ["translate", "scale", "rotate"]:
            pm.connectAttr("{}.output{}".format(dm_node, attr.capitalize()),
                           "{}.{}".format(driver, attr))
            pm.disconnectAttr("{}.{}".format(ctl, attr),
                              "{}.{}".format(ghost, attr))

    surfaceShape = surface.getShape()
    sliders = []

    for i, ctlGhost in enumerate(ghostControls):
        ctl = pm.listConnections(ctlGhost, t="transform")[-1]
        t = ctl.getMatrix(worldSpace=True)

        gDriver = primitive.addTransform(surface.getParent(),
                                         "{}_slideDriver".format(ctl.name()),
                                         t)
        if 0 == i:
            connCenter(ctl, gDriver, ctlGhost)

        else:
            conn(ctl, gDriver, ctlGhost)

        oParent = ctlGhost.getParent()
        npoName = "_".join(ctlGhost.name().split("_")[:-1]) + "_npo"
        oTra = pm.PyNode(
            pm.createNode("transform", n=npoName, p=oParent, ss=True))
        oTra.setTransformation(ctlGhost.getMatrix())
        pm.parent(ctlGhost, oTra)

        slider = primitive.addTransform(sliderParent,
                                        ctl.name() + "_slideDriven", t)
        sliders.append(slider)

        # connexion
        if 0 == i:
            dm_node = node.createDecomposeMatrixNode(gDriver.attr("matrix"))

        else:
            mul_node = pm.createNode("multMatrix")
            i = 0
            parent = ctl
            while parent != sliderParent:
                parent.attr("matrix") >> mul_node.attr(
                    "matrixIn[{}]".format(i))
                parent = parent.getParent()
                i += 1
                if 10 < i:
                    logger.error("maximum recursion")
                    break

            dm_node = node.createDecomposeMatrixNode(
                mul_node.attr("matrixSum"))

        cps_node = pm.createNode("closestPointOnSurface")
        dm_node.attr("outputTranslate") >> cps_node.attr("inPosition")
        surfaceShape.attr("local") >> cps_node.attr("inputSurface")
        cps_node.attr("position") >> slider.attr("translate")

        pm.normalConstraint(surfaceShape,
                            slider,
                            aimVector=[0, 0, 1],
                            upVector=[0, 1, 0],
                            worldUpType="objectrotation",
                            worldUpVector=[0, 1, 0],
                            worldUpObject=gDriver)

        pm.parent(ctlGhost.getParent(), slider)
        ymt_util.setKeyableAttributesDontLockVisibility(slider, [])

    for slider in sliders[1:]:
        _visi_off_lock(slider)