예제 #1
0
def addCnsCurve(parent, name, centers, degree=1, m=datatypes.Matrix()):
    """Create a curve attached to given centers. One point per center

    Arguments:
        parent (dagNode): Parent object.
        name (str): Name
        centers (list of dagNode): Object that will drive the curve.
        degree (int): 1 for linear curve, 3 for Cubic.

    Returns:
        dagNode: The newly created curve.
    """
    # rebuild list to avoid input list modification
    centers = centers[:]
    if degree == 3:
        if len(centers) == 2:
            centers.insert(0, centers[0])
            centers.append(centers[-1])
        elif len(centers) == 3:
            centers.append(centers[-1])

    points = [datatypes.Vector() for center in centers]

    node = addCurve(parent, name, points, False, degree, m=m)

    applyop.gear_curvecns_op(node, centers)

    return node
예제 #2
0
def rig(edge_loop="",
        up_vertex="",
        low_vertex="",
        name_prefix="",
        thickness=0.3,
        do_skin=True,
        rigid_loops=5,
        falloff_loops=8,
        head_joint=None,
        jaw_joint=None,
        parent_node=None,
        control_name="ctl",
        upper_lip_ctl=None,
        lower_lip_ctl=None):

    ######
    # Var
    ######

    FRONT_OFFSET = .02
    NB_ROPE = 15

    ##################
    # Helper functions
    ##################
    def setName(name, side="C", idx=None):
        namesList = [name_prefix, side, name]
        if idx is not None:
            namesList[1] = side + str(idx)
        name = "_".join(namesList)
        return name

    ###############
    # Checkers
    ##############

    # Loop
    if edge_loop:
        try:
            edge_loop = [pm.PyNode(e) for e in edge_loop.split(",")]
        except pm.MayaNodeError:
            pm.displayWarning(
                "Some of the edges listed in edge loop can not be found")
            return
    else:
        pm.displayWarning("Please set the edge loop first")
        return

    # Vertex
    if up_vertex:
        try:
            up_vertex = pm.PyNode(up_vertex)
        except pm.MayaNodeError:
            pm.displayWarning("%s can not be found" % up_vertex)
            return
    else:
        pm.displayWarning("Please set the upper lip central vertex")
        return

    if low_vertex:
        try:
            low_vertex = pm.PyNode(low_vertex)
        except pm.MayaNodeError:
            pm.displayWarning("%s can not be found" % low_vertex)
            return
    else:
        pm.displayWarning("Please set the lower lip central vertex")
        return

    # skinnign data
    if do_skin:
        if not head_joint:
            pm.displayWarning("Please set the Head Jnt or unCheck Compute "
                              "Topological Autoskin")
            return
        else:
            try:
                head_joint = pm.PyNode(head_joint)
            except pm.MayaNodeError:
                pm.displayWarning(
                    "Head Joint: %s can not be found" % head_joint
                )
                return
        if not jaw_joint:
            pm.displayWarning("Please set the Jaw Jnt or unCheck Compute "
                              "Topological Autoskin")
            return
        else:
            try:
                jaw_joint = pm.PyNode(jaw_joint)
            except pm.MayaNodeError:
                pm.displayWarning("Jaw Joint: %s can not be found" % jaw_joint)
                return
    # check if the rig already exist in the current scene
    if pm.ls(setName("root")):
        pm.displayWarning("The object %s already exist in the scene. Please "
                          "choose another name prefix" % setName("root"))
        return

    #####################
    # Root creation
    #####################
    lips_root = primitive.addTransform(None, setName("root"))
    lipsCrv_root = primitive.addTransform(lips_root, setName("crvs"))
    lipsRope_root = primitive.addTransform(lips_root, setName("rope"))

    #####################
    # Geometry
    #####################
    geo = pm.listRelatives(edge_loop[0], parent=True)[0]

    #####################
    # Groups
    #####################
    try:
        ctlSet = pm.PyNode("rig_controllers_grp")
    except pm.MayaNodeError:
        pm.sets(n="rig_controllers_grp", em=True)
        ctlSet = pm.PyNode("rig_controllers_grp")
    try:
        defset = pm.PyNode("rig_deformers_grp")
    except pm.MayaNodeError:
        pm.sets(n="rig_deformers_grp", em=True)
        defset = pm.PyNode("rig_deformers_grp")

    #####################
    # Curves creation
    #####################

    # get extreme position using the outer loop
    extr_v = meshNavigation.getExtremeVertexFromLoop(edge_loop)
    upPos = extr_v[0]
    lowPos = extr_v[1]
    inPos = extr_v[2]
    outPos = extr_v[3]
    edgeList = extr_v[4]
    vertexList = extr_v[5]
    upPos = up_vertex
    lowPos = low_vertex

    # upper crv
    upLip_edgeRange = meshNavigation.edgeRangeInLoopFromMid(edgeList,
                                                            upPos,
                                                            inPos,
                                                            outPos)
    upCrv = curve.createCuveFromEdges(upLip_edgeRange,
                                      setName("upperLip"),
                                      parent=lipsCrv_root)
    # store the closest vertex by curv cv index. To be use fo the auto skining
    upLip_closestVtxList = []
    # offset upper lip Curve
    cvs = upCrv.getCVs(space="world")
    for i, cv in enumerate(cvs):

        closestVtx = meshNavigation.getClosestVertexFromTransform(geo, cv)
        upLip_closestVtxList.append(closestVtx)
        if i == 0:
            # we know the curv starts from right to left
            offset = [cv[0] - thickness, cv[1], cv[2] - thickness]
        elif i == len(cvs) - 1:
            offset = [cv[0] + thickness, cv[1], cv[2] - thickness]
        else:
            offset = [cv[0], cv[1] + thickness, cv[2]]
        upCrv.setCV(i, offset, space='world')

    # lower crv
    lowLip_edgeRange = meshNavigation.edgeRangeInLoopFromMid(edgeList,
                                                             lowPos,
                                                             inPos,
                                                             outPos)
    lowCrv = curve.createCuveFromEdges(lowLip_edgeRange,
                                       setName("lowerLip"),
                                       parent=lipsCrv_root)
    lowLip_closestVtxList = []
    # offset lower lip Curve
    cvs = lowCrv.getCVs(space="world")
    for i, cv in enumerate(cvs):
        closestVtx = meshNavigation.getClosestVertexFromTransform(geo, cv)
        lowLip_closestVtxList.append(closestVtx)
        if i == 0:
            # we know the curv starts from right to left
            offset = [cv[0] - thickness, cv[1], cv[2] - thickness]
        elif i == len(cvs) - 1:
            offset = [cv[0] + thickness, cv[1], cv[2] - thickness]
        else:
            # we populate the closest vertext list here to skipt the first
            # and latest point
            offset = [cv[0], cv[1] - thickness, cv[2]]
        lowCrv.setCV(i, offset, space='world')

    upCrv_ctl = curve.createCurveFromCurve(upCrv,
                                           setName("upCtl_crv"),
                                           nbPoints=7,
                                           parent=lipsCrv_root)
    lowCrv_ctl = curve.createCurveFromCurve(lowCrv,
                                            setName("lowCtl_crv"),
                                            nbPoints=7,
                                            parent=lipsCrv_root)

    upRope = curve.createCurveFromCurve(upCrv,
                                        setName("upRope_crv"),
                                        nbPoints=NB_ROPE,
                                        parent=lipsCrv_root)
    lowRope = curve.createCurveFromCurve(lowCrv,
                                         setName("lowRope_crv"),
                                         nbPoints=NB_ROPE,
                                         parent=lipsCrv_root)

    upCrv_upv = curve.createCurveFromCurve(upCrv,
                                           setName("upCrv_upv"),
                                           nbPoints=7,
                                           parent=lipsCrv_root)
    lowCrv_upv = curve.createCurveFromCurve(lowCrv,
                                            setName("lowCrv_upv"),
                                            nbPoints=7,
                                            parent=lipsCrv_root)

    upRope_upv = curve.createCurveFromCurve(upCrv,
                                            setName("upRope_upv"),
                                            nbPoints=NB_ROPE,
                                            parent=lipsCrv_root)
    lowRope_upv = curve.createCurveFromCurve(lowCrv,
                                             setName("lowRope_upv"),
                                             nbPoints=NB_ROPE,
                                             parent=lipsCrv_root)

    # offset upv curves

    for crv in [upCrv_upv, lowCrv_upv, upRope_upv, lowRope_upv]:
        cvs = crv.getCVs(space="world")
        for i, cv in enumerate(cvs):

            # we populate the closest vertext list here to skipt the first
            # and latest point
            offset = [cv[0], cv[1], cv[2] + FRONT_OFFSET]
            crv.setCV(i, offset, space='world')

    rigCrvs = [upCrv,
               lowCrv,
               upCrv_ctl,
               lowCrv_ctl,
               upRope,
               lowRope,
               upCrv_upv,
               lowCrv_upv,
               upRope_upv,
               lowRope_upv]

    for crv in rigCrvs:
        crv.attr("visibility").set(False)

    ##################
    # Joints
    ##################

    lvlType = "transform"

    # upper joints
    upperJoints = []
    cvs = upCrv.getCVs(space="world")
    pm.progressWindow(title='Creating Upper Joints', progress=0, max=len(cvs))

    for i, cv in enumerate(cvs):
        pm.progressWindow(e=True,
                          step=1,
                          status='\nCreating Joint for  %s' % cv)
        oTransUpV = pm.PyNode(pm.createNode(
            lvlType,
            n=setName("upLipRopeUpv", idx=str(i).zfill(3)),
            p=lipsRope_root,
            ss=True))
        oTrans = pm.PyNode(
            pm.createNode(lvlType,
                          n=setName("upLipRope", idx=str(i).zfill(3)),
                          p=lipsRope_root, ss=True))

        oParam, oLength = curve.getCurveParamAtPosition(upRope, cv)
        uLength = curve.findLenghtFromParam(upRope, oParam)
        u = uLength / oLength

        applyop.pathCns(
            oTransUpV, upRope_upv, cnsType=False, u=u, tangent=False)

        cns = applyop.pathCns(
            oTrans, upRope, cnsType=False, u=u, tangent=False)

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

        pm.connectAttr(oTransUpV.attr("worldMatrix[0]"),
                       cns.attr("worldUpMatrix"))

        # getting joint parent
        if head_joint and isinstance(head_joint, (str, string_types)):
            try:
                j_parent = pm.PyNode(head_joint)
            except pm.MayaNodeError:
                j_parent = False
        elif head_joint and isinstance(head_joint, pm.PyNode):
            j_parent = head_joint
        else:
            j_parent = False

        jnt = rigbits.addJnt(oTrans, noReplace=True, parent=j_parent)
        upperJoints.append(jnt)
        pm.sets(defset, add=jnt)
    pm.progressWindow(e=True, endProgress=True)

    # lower joints
    lowerJoints = []
    cvs = lowCrv.getCVs(space="world")
    pm.progressWindow(title='Creating Lower Joints', progress=0, max=len(cvs))

    for i, cv in enumerate(cvs):
        pm.progressWindow(e=True,
                          step=1,
                          status='\nCreating Joint for  %s' % cv)
        oTransUpV = pm.PyNode(pm.createNode(
            lvlType,
            n=setName("lowLipRopeUpv", idx=str(i).zfill(3)),
            p=lipsRope_root,
            ss=True))

        oTrans = pm.PyNode(pm.createNode(
            lvlType,
            n=setName("lowLipRope", idx=str(i).zfill(3)),
            p=lipsRope_root,
            ss=True))

        oParam, oLength = curve.getCurveParamAtPosition(lowRope, cv)
        uLength = curve.findLenghtFromParam(lowRope, oParam)
        u = uLength / oLength

        applyop.pathCns(oTransUpV,
                        lowRope_upv,
                        cnsType=False,
                        u=u,
                        tangent=False)
        cns = applyop.pathCns(oTrans,
                              lowRope,
                              cnsType=False,
                              u=u,
                              tangent=False)

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

        pm.connectAttr(oTransUpV.attr("worldMatrix[0]"),
                       cns.attr("worldUpMatrix"))

        # getting joint parent
        if jaw_joint and isinstance(jaw_joint, (str, string_types)):
            try:
                j_parent = pm.PyNode(jaw_joint)
            except pm.MayaNodeError:
                pass
        elif jaw_joint and isinstance(jaw_joint, pm.PyNode):
            j_parent = jaw_joint
        else:
            j_parent = False
        jnt = rigbits.addJnt(oTrans, noReplace=True, parent=j_parent)
        lowerJoints.append(jnt)
        pm.sets(defset, add=jnt)
    pm.progressWindow(e=True, endProgress=True)

    ##################
    # Controls
    ##################

    # Controls lists
    upControls = []
    upVec = []
    upNpo = []
    lowControls = []
    lowVec = []
    lowNpo = []
    # controls options
    axis_list = ["sx", "sy", "sz", "ro"]
    upCtlOptions = [["corner", "R", "square", 4, .05, axis_list],
                    ["upOuter", "R", "circle", 14, .03, []],
                    ["upInner", "R", "circle", 14, .03, []],
                    ["upper", "C", "square", 4, .05, axis_list],
                    ["upInner", "L", "circle", 14, .03, []],
                    ["upOuter", "L", "circle", 14, .03, []],
                    ["corner", "L", "square", 4, .05, axis_list]]

    lowCtlOptions = [["lowOuter", "R", "circle", 14, .03, []],
                     ["lowInner", "R", "circle", 14, .03, []],
                     ["lower", "C", "square", 4, .05, axis_list],
                     ["lowInner", "L", "circle", 14, .03, []],
                     ["lowOuter", "L", "circle", 14, .03, []]]

    params = ["tx", "ty", "tz", "rx", "ry", "rz"]

    # upper controls
    cvs = upCrv_ctl.getCVs(space="world")
    pm.progressWindow(title='Upper controls', progress=0, max=len(cvs))

    v0 = transform.getTransformFromPos(cvs[0])
    v1 = transform.getTransformFromPos(cvs[-1])
    distSize = vector.getDistance(v0, v1) * 3

    for i, cv in enumerate(cvs):
        pm.progressWindow(e=True,
                          step=1,
                          status='\nCreating control for%s' % cv)
        t = transform.getTransformFromPos(cv)

        # Get nearest joint for orientation of controls
        joints = upperJoints + lowerJoints
        nearest_joint = None
        nearest_distance = None
        for joint in joints:
            distance = vector.getDistance(
                transform.getTranslation(joint),
                cv
            )
            if nearest_distance is None or distance < nearest_distance:
                nearest_distance = distance
                nearest_joint = joint

        if nearest_joint:
            t = transform.setMatrixPosition(
                transform.getTransform(nearest_joint), cv
            )
            temp = primitive.addTransform(
                lips_root, setName("temp"), t
            )
            temp.rx.set(0)
            t = transform.getTransform(temp)
            pm.delete(temp)

        oName = upCtlOptions[i][0]
        oSide = upCtlOptions[i][1]
        o_icon = upCtlOptions[i][2]
        color = upCtlOptions[i][3]
        wd = upCtlOptions[i][4]
        oPar = upCtlOptions[i][5]
        npo = primitive.addTransform(lips_root,
                                     setName("%s_npo" % oName, oSide),
                                     t)
        upNpo.append(npo)
        ctl = icon.create(npo,
                          setName("%s_%s" % (oName, control_name), oSide),
                          t,
                          icon=o_icon,
                          w=wd * distSize,
                          d=wd * distSize,
                          ro=datatypes.Vector(1.57079633, 0, 0),
                          po=datatypes.Vector(0, 0, .07 * distSize),
                          color=color)

        upControls.append(ctl)
        name_split = control_name.split("_")
        if len(name_split) == 2 and name_split[-1] == "ghost":
            pass
        else:
            pm.sets(ctlSet, add=ctl)
        attribute.addAttribute(ctl, "isCtl", "bool", keyable=False)
        attribute.setKeyableAttributes(ctl, params + oPar)

        upv = primitive.addTransform(ctl, setName("%s_upv" % oName, oSide), t)
        upv.attr("tz").set(FRONT_OFFSET)
        upVec.append(upv)
        if oSide == "R":
            npo.attr("sx").set(-1)
    pm.progressWindow(e=True, endProgress=True)

    # lower controls
    cvs = lowCrv_ctl.getCVs(space="world")
    pm.progressWindow(title='Lower controls', progress=0, max=len(cvs))

    for i, cv in enumerate(cvs[1:-1]):
        pm.progressWindow(e=True,
                          step=1,
                          status='\nCreating control for%s' % cv)

        t = transform.getTransformFromPos(cv)

        # Get nearest joint for orientation of controls
        joints = upperJoints + lowerJoints
        nearest_joint = None
        nearest_distance = None
        for joint in joints:
            distance = vector.getDistance(
                transform.getTranslation(joint),
                cv
            )
            if nearest_distance is None or distance < nearest_distance:
                nearest_distance = distance
                nearest_joint = joint

        if nearest_joint:
            t = transform.setMatrixPosition(
                transform.getTransform(nearest_joint), cv
            )
            temp = primitive.addTransform(
                lips_root, setName("temp"), t
            )
            temp.rx.set(0)
            t = transform.getTransform(temp)
            pm.delete(temp)

        oName = lowCtlOptions[i][0]
        oSide = lowCtlOptions[i][1]
        o_icon = lowCtlOptions[i][2]
        color = lowCtlOptions[i][3]
        wd = lowCtlOptions[i][4]
        oPar = lowCtlOptions[i][5]
        npo = primitive.addTransform(lips_root,
                                     setName("%s_npo" % oName, oSide),
                                     t)
        lowNpo.append(npo)
        ctl = icon.create(npo,
                          setName("%s_%s" % (oName, control_name), oSide),
                          t,
                          icon=o_icon,
                          w=wd * distSize,
                          d=wd * distSize,
                          ro=datatypes.Vector(1.57079633, 0, 0),
                          po=datatypes.Vector(0, 0, .07 * distSize),
                          color=color)
        lowControls.append(ctl)
        name_split = control_name.split("_")
        if len(name_split) == 2 and control_name.split("_")[-1] == "ghost":
            pass
        else:
            pm.sets(ctlSet, add=ctl)
        attribute.addAttribute(ctl, "isCtl", "bool", keyable=False)
        attribute.setKeyableAttributes(ctl, params + oPar)

        upv = primitive.addTransform(ctl, setName("%s_upv" % oName, oSide), t)
        upv.attr("tz").set(FRONT_OFFSET)
        lowVec.append(upv)
        if oSide == "R":
            npo.attr("sx").set(-1)
    pm.progressWindow(e=True, endProgress=True)

    # reparentig controls
    pm.parent(upNpo[1], lowNpo[0], upControls[0])
    pm.parent(upNpo[2], upNpo[4], upControls[3])
    pm.parent(upNpo[-2], lowNpo[-1], upControls[-1])
    pm.parent(lowNpo[1], lowNpo[3], lowControls[2])

    # Connecting control crvs with controls
    applyop.gear_curvecns_op(upCrv_ctl, upControls)
    applyop.gear_curvecns_op(lowCrv_ctl,
                             [upControls[0]] + lowControls + [upControls[-1]])

    applyop.gear_curvecns_op(upCrv_upv, upVec)
    applyop.gear_curvecns_op(lowCrv_upv, [upVec[0]] + lowVec + [upVec[-1]])

    # adding wires
    pm.wire(upCrv, w=upCrv_ctl, dropoffDistance=[0, 1000])
    pm.wire(lowCrv, w=lowCrv_ctl, dropoffDistance=[0, 1000])
    pm.wire(upRope, w=upCrv_ctl, dropoffDistance=[0, 1000])
    pm.wire(lowRope, w=lowCrv_ctl, dropoffDistance=[0, 1000])

    pm.wire(upRope_upv, w=upCrv_upv, dropoffDistance=[0, 1000])
    pm.wire(lowRope_upv, w=lowCrv_upv, dropoffDistance=[0, 1000])

    # setting constrains
    # up
    cns_node = pm.parentConstraint(upControls[0],
                                   upControls[3],
                                   upControls[1].getParent(),
                                   mo=True,
                                   skipRotate=["x", "y", "z"])
    cns_node.attr(upControls[0].name() + "W0").set(.75)
    cns_node.attr(upControls[3].name() + "W1").set(.25)
    cns_node.interpType.set(0)  # noFlip

    cns_node = pm.parentConstraint(upControls[0],
                                   upControls[3],
                                   upControls[2].getParent(),
                                   mo=True,
                                   skipRotate=["x", "y", "z"])
    cns_node.attr(upControls[0].name() + "W0").set(.25)
    cns_node.attr(upControls[3].name() + "W1").set(.75)
    cns_node.interpType.set(0)  # noFlip

    cns_node = pm.parentConstraint(upControls[3],
                                   upControls[6],
                                   upControls[4].getParent(),
                                   mo=True,
                                   skipRotate=["x", "y", "z"])
    cns_node.attr(upControls[3].name() + "W0").set(.75)
    cns_node.attr(upControls[6].name() + "W1").set(.25)
    cns_node.interpType.set(0)  # noFlip

    cns_node = pm.parentConstraint(upControls[3],
                                   upControls[6],
                                   upControls[5].getParent(),
                                   mo=True,
                                   skipRotate=["x", "y", "z"])
    cns_node.attr(upControls[3].name() + "W0").set(.25)
    cns_node.attr(upControls[6].name() + "W1").set(.75)
    cns_node.interpType.set(0)  # noFlip

    # low
    cns_node = pm.parentConstraint(upControls[0],
                                   lowControls[2],
                                   lowControls[0].getParent(),
                                   mo=True,
                                   skipRotate=["x", "y", "z"])
    cns_node.attr(upControls[0].name() + "W0").set(.75)
    cns_node.attr(lowControls[2].name() + "W1").set(.25)
    cns_node.interpType.set(0)  # noFlip

    cns_node = pm.parentConstraint(upControls[0],
                                   lowControls[2],
                                   lowControls[1].getParent(),
                                   mo=True,
                                   skipRotate=["x", "y", "z"])
    cns_node.attr(upControls[0].name() + "W0").set(.25)
    cns_node.attr(lowControls[2].name() + "W1").set(.75)
    cns_node.interpType.set(0)  # noFlip

    cns_node = pm.parentConstraint(lowControls[2],
                                   upControls[6],
                                   lowControls[3].getParent(),
                                   mo=True,
                                   skipRotate=["x", "y", "z"])
    cns_node.attr(lowControls[2].name() + "W0").set(.75)
    cns_node.attr(upControls[6].name() + "W1").set(.25)
    cns_node.interpType.set(0)  # noFlip

    cns_node = pm.parentConstraint(lowControls[2],
                                   upControls[6],
                                   lowControls[4].getParent(),
                                   mo=True,
                                   skipRotate=["x", "y", "z"])
    cns_node.attr(lowControls[2].name() + "W0").set(.25)
    cns_node.attr(upControls[6].name() + "W1").set(.75)
    cns_node.interpType.set(0)  # noFlip

    ###########################################
    # Connecting rig
    ###########################################
    if parent_node:
        try:
            if isinstance(parent_node, string_types):
                parent_node = pm.PyNode(parent_node)
            parent_node.addChild(lips_root)
        except pm.MayaNodeError:
            pm.displayWarning("The Lips rig can not be parent to: %s. Maybe "
                              "this object doesn't exist." % parent_node)
    if head_joint and jaw_joint:
        try:
            if isinstance(head_joint, string_types):
                head_joint = pm.PyNode(head_joint)
        except pm.MayaNodeError:
            pm.displayWarning("Head Joint or Upper Lip Joint %s. Can not be "
                              "fount in the scene" % head_joint)
            return
        try:
            if isinstance(jaw_joint, string_types):
                jaw_joint = pm.PyNode(jaw_joint)
        except pm.MayaNodeError:
            pm.displayWarning("Jaw Joint or Lower Lip Joint %s. Can not be "
                              "fount in the scene" % jaw_joint)
            return

        ref_ctls = [head_joint, jaw_joint]

        if upper_lip_ctl and lower_lip_ctl:
            try:
                if isinstance(upper_lip_ctl, string_types):
                    upper_lip_ctl = pm.PyNode(upper_lip_ctl)
            except pm.MayaNodeError:
                pm.displayWarning("Upper Lip Ctl %s. Can not be "
                                  "fount in the scene" % upper_lip_ctl)
                return
            try:
                if isinstance(lower_lip_ctl, string_types):
                    lower_lip_ctl = pm.PyNode(lower_lip_ctl)
            except pm.MayaNodeError:
                pm.displayWarning("Lower Lip Ctl %s. Can not be "
                                  "fount in the scene" % lower_lip_ctl)
                return
            ref_ctls = [upper_lip_ctl, lower_lip_ctl]

        # in order to avoid flips lets create a reference transform
        # also to avoid flips, set any multi target parentConstraint to noFlip
        ref_cns_list = []
        print (ref_ctls)
        for cns_ref in ref_ctls:

            t = transform.getTransformFromPos(
                cns_ref.getTranslation(space='world'))
            ref = pm.createNode("transform",
                                n=cns_ref.name() + "_cns",
                                p=cns_ref,
                                ss=True)
            ref.setMatrix(t, worldSpace=True)
            ref_cns_list.append(ref)
        # right corner connection
        cns_node = pm.parentConstraint(ref_cns_list[0],
                                       ref_cns_list[1],
                                       upControls[0].getParent(),
                                       mo=True)
        cns_node.interpType.set(0)  # noFlip
        # left corner connection
        cns_node = pm.parentConstraint(ref_cns_list[0],
                                       ref_cns_list[1],
                                       upControls[-1].getParent(),
                                       mo=True)
        cns_node.interpType.set(0)  # noFlip
        # up control connection
        cns_node = pm.parentConstraint(ref_cns_list[0],
                                       upControls[3].getParent(),
                                       mo=True)
        # low control connection
        cns_node = pm.parentConstraint(ref_cns_list[1],
                                       lowControls[2].getParent(),
                                       mo=True)

    ###########################################
    # Auto Skinning
    ###########################################
    if do_skin:
        # eyelid vertex rows
        totalLoops = rigid_loops + falloff_loops
        vertexLoopList = meshNavigation.getConcentricVertexLoop(vertexList,
                                                                totalLoops)
        vertexRowList = meshNavigation.getVertexRowsFromLoops(vertexLoopList)

        # we set the first value 100% for the first initial loop
        skinPercList = [1.0]
        # we expect to have a regular grid topology
        for r in range(rigid_loops):
            for rr in range(2):
                skinPercList.append(1.0)
        increment = 1.0 / float(falloff_loops)
        # we invert to smooth out from 100 to 0
        inv = 1.0 - increment
        for r in range(falloff_loops):
            for rr in range(2):
                if inv < 0.0:
                    inv = 0.0
                skinPercList.append(inv)
            inv -= increment

        # this loop add an extra 0.0 indices to avoid errors
        for r in range(10):
            for rr in range(2):
                skinPercList.append(0.0)

        # base skin
        if head_joint:
            try:
                head_joint = pm.PyNode(head_joint)
            except pm.MayaNodeError:
                pm.displayWarning(
                    "Auto skin aborted can not find %s " % head_joint)
                return

        # Check if the object has a skinCluster
        objName = pm.listRelatives(geo, parent=True)[0]

        skinCluster = skin.getSkinCluster(objName)
        if not skinCluster:
            skinCluster = pm.skinCluster(head_joint,
                                         geo,
                                         tsb=True,
                                         nw=2,
                                         n='skinClsEyelid')

        lipsJoints = upperJoints + lowerJoints
        closestVtxList = upLip_closestVtxList + lowLip_closestVtxList
        pm.progressWindow(title='Auto skinning process',
                          progress=0,
                          max=len(lipsJoints))

        for i, jnt in enumerate(lipsJoints):
            pm.progressWindow(e=True, step=1, status='\nSkinning %s' % jnt)
            skinCluster.addInfluence(jnt, weight=0)
            v = closestVtxList[i]
            for row in vertexRowList:
                if v in row:
                    for i, rv in enumerate(row):
                        # find the deformer with max value for each vertex
                        w = pm.skinPercent(skinCluster,
                                           rv,
                                           query=True,
                                           value=True)
                        transJoint = pm.skinPercent(skinCluster,
                                                    rv,
                                                    query=True,
                                                    t=None)
                        max_value = max(w)
                        max_index = w.index(max_value)

                        perc = skinPercList[i]
                        t_value = [(jnt, perc),
                                   (transJoint[max_index], 1.0 - perc)]
                        pm.skinPercent(skinCluster,
                                       rv,
                                       transformValue=t_value)
        pm.progressWindow(e=True, endProgress=True)
예제 #3
0
    def _addCurveControllers(self, t, crv, ctlNames, inCtl=None, outCtl=None):

        cvs = crv.getCVs(space="world")
        if self.negate:
            # cvs = [cv for cv in reversed(cvs)]
            pass

        ctls = []
        for i, cv in enumerate(cvs):
            if inCtl is not None and i == 0:
                ctls.append(inCtl)
                continue

            if outCtl is not None and (i == len(cvs) - 1):
                ctls.append(outCtl)
                continue

            if utils.is_odd(i):
                color = 14
                wd = .5
                offset = self.offset * 1.1
                icon_shape = "circle"
                params = ["tx", "ty", "tz"]

            else:
                color = 4
                wd = .7
                offset = self.offset * 1.3
                icon_shape = "square"
                params = ["tx", "ty", "tz", "ro", "rx", "ry", "rz", "sx", "sy", "sz"]

            t = setMatrixPosition(t, cvs[i])
            npo = addTransform(self.center_lookat, self.getName("%s_npo" % ctlNames[i]), t)
            npoBase = npo

            if i == 2:
                # we add an extra level to input the tracking ofset values
                npo = addTransform(npo, self.getName("%s_trk" % ctlNames[i]), t)
                self.trackLvl.append(npo)

            ctl = self.addCtl(npo,
                              "%s_%s" % (ctlNames[i], self.ctlName),
                              t,
                              color,
                              icon_shape,
                              w=wd,
                              d=wd,
                              ro=datatypes.Vector(1.57079633, 0, 0),
                              po=offset
                              )

            self.addToSubGroup(self.over_ctl, self.primaryControllersGroupName)
            ymt_util.setKeyableAttributesDontLockVisibility(ctl, params)
            ctls.append(ctl)

        # adding parent average contrains to odd controls
        for i, ctl in enumerate(ctls):
            if utils.is_odd(i):
                s = ctls[i - 1]
                d = ctls[i + 1]
                pm.parentConstraint(s, d, ctl.getParent(), mo=True)

        applyop.gear_curvecns_op(crv, ctls)
        return ctls
    def addControllers(self):
        axis_list = ["sx", "sy", "sz", "ro"]
        upCtlOptions = [["corner", "R", "square", 4, .05, axis_list],
                        ["upOuter", "R", "circle", 14, .03, []],
                        ["upInner", "R", "circle", 14, .03, []],
                        ["upper", "C", "square", 4, .05, axis_list],
                        ["upInner", "L", "circle", 14, .03, []],
                        ["upOuter", "L", "circle", 14, .03, []],
                        ["corner", "L", "square", 4, .05, axis_list]]

        lowCtlOptions = [["lowOuter", "R", "circle", 14, .03, []],
                         ["lowInner", "R", "circle", 14, .03, []],
                         ["lower", "C", "square", 4, .05, axis_list],
                         ["lowInner", "L", "circle", 14, .03, []],
                         ["lowOuter", "L", "circle", 14, .03, []]]

        self.upNpos, self.upCtls, self.upUpvs = self._addControls(
            self.upCrv_ctl, upCtlOptions, False)
        self.lowNpos, self.lowCtls, self.lowUpvs = self._addControls(
            self.lowCrv_ctl, lowCtlOptions, True)

        self.lips_R_Corner_ctl = self.upCtls[0]
        self.lips_R_upOuter_ctl = self.upCtls[1]
        self.lips_R_upInner_ctl = self.upCtls[2]
        self.lips_C_upper_ctl = self.upCtls[3]
        self.lips_L_upInner_ctl = self.upCtls[4]
        self.lips_L_upOuter_ctl = self.upCtls[5]
        self.lips_L_Corner_ctl = self.upCtls[6]

        self.lips_R_lowOuter_ctl = self.lowCtls[0]
        self.lips_R_lowInner_ctl = self.lowCtls[1]
        self.lips_C_lower_ctl = self.lowCtls[2]
        self.lips_L_lowInner_ctl = self.lowCtls[3]
        self.lips_L_lowOuter_ctl = self.lowCtls[4]

        self.lips_R_Corner_npo = self.upNpos[0]
        self.lips_R_upOuter_npo = self.upNpos[1]
        self.lips_R_upInner_npo = self.upNpos[2]
        self.lips_C_upper_npo = self.upNpos[3]
        self.lips_L_upInner_npo = self.upNpos[4]
        self.lips_L_upOuter_npo = self.upNpos[5]
        self.lips_L_Corner_npo = self.upNpos[6]

        self.lips_R_lowOuter_npo = self.lowNpos[0]
        self.lips_R_lowInner_npo = self.lowNpos[1]
        self.lips_C_lower_npo = self.lowNpos[2]
        self.lips_L_lowInner_npo = self.lowNpos[3]
        self.lips_L_lowOuter_npo = self.lowNpos[4]

        upvec = self.upUpvs + self.lowUpvs

        pm.parent(self.lips_R_upOuter_npo, self.lips_R_lowOuter_npo,
                  self.lips_R_Corner_ctl)
        pm.parent(self.lips_R_upInner_npo, self.lips_L_upInner_npo,
                  self.lips_C_upper_ctl)
        pm.parent(self.lips_L_upOuter_npo, self.lips_L_lowOuter_npo,
                  self.lips_L_Corner_ctl)
        pm.parent(self.lips_R_lowInner_npo, self.lips_L_lowInner_npo,
                  self.lips_C_lower_ctl)

        # Connecting control crvs with controls
        applyop.gear_curvecns_op(self.upCrv_ctl, self.upCtls)
        applyop.gear_curvecns_op(self.lowCrv_ctl, [self.upCtls[0]] +
                                 self.lowCtls + [self.upCtls[-1]])

        applyop.gear_curvecns_op(self.upCrv_upv, upvec)
        applyop.gear_curvecns_op(self.lowCrv_upv,
                                 [upvec[0]] + self.lowUpvs + [upvec[-1]])

        # adding wires
        pm.wire(self.upCrv, w=self.upCrv_ctl, dropoffDistance=[0, 1000])
        pm.wire(self.lowCrv, w=self.lowCrv_ctl, dropoffDistance=[0, 1000])
        pm.wire(self.upRope, w=self.upCrv_ctl, dropoffDistance=[0, 1000])
        pm.wire(self.lowRope, w=self.lowCrv_ctl, dropoffDistance=[0, 1000])

        pm.wire(self.upRope_upv, w=self.upCrv_upv, dropoffDistance=[0, 1000])
        pm.wire(self.lowRope_upv, w=self.lowCrv_upv, dropoffDistance=[0, 1000])

        return
예제 #5
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
예제 #6
0
def eyeRig(eyeMesh,
           edgeLoop,
           blinkH,
           namePrefix,
           offset,
           rigidLoops,
           falloffLoops,
           headJnt,
           doSkin,
           parent=None,
           ctlName="ctl",
           sideRange=False,
           customCorner=False,
           intCorner=None,
           extCorner=None,
           ctlGrp=None,
           defGrp=None):
    """Create eyelid and eye rig

    Args:
        eyeMesh (TYPE): Description
        edgeLoop (TYPE): Description
        blinkH (TYPE): Description
        namePrefix (TYPE): Description
        offset (TYPE): Description
        rigidLoops (TYPE): Description
        falloffLoops (TYPE): Description
        headJnt (TYPE): Description
        doSkin (TYPE): Description
        parent (None, optional): Description
        ctlName (str, optional): Description
        sideRange (bool, optional): Description
        customCorner (bool, optional): Description
        intCorner (None, optional): Description
        extCorner (None, optional): Description
        ctlGrp (None, optional): Description
        defGrp (None, optional): Description

    Returns:
        TYPE: Description
    """
    # Checkers
    if edgeLoop:
        edgeLoopList = [pm.PyNode(e) for e in edgeLoop.split(",")]
    else:
        pm.displayWarning("Please set the edge loop first")
        return

    if eyeMesh:
        try:
            eyeMesh = pm.PyNode(eyeMesh)
        except pm.MayaNodeError:
            pm.displayWarning("The object %s can not be found in the "
                              "scene" % (eyeMesh))
            return
    else:
        pm.displayWarning("Please set the eye mesh first")

    if doSkin:
        if not headJnt:
            pm.displayWarning("Please set the Head Jnt or unCheck "
                              "Compute Topological Autoskin")
            return

    # Initial Data
    bboxCenter = meshNavigation.bboxCenter(eyeMesh)

    extr_v = meshNavigation.getExtremeVertexFromLoop(edgeLoopList, sideRange)
    upPos = extr_v[0]
    lowPos = extr_v[1]
    inPos = extr_v[2]
    outPos = extr_v[3]
    edgeList = extr_v[4]
    vertexList = extr_v[5]

    # Detect the side L or R from the x value
    if inPos.getPosition(space='world')[0] < 0.0:
        side = "R"
        inPos = extr_v[3]
        outPos = extr_v[2]
        normalPos = outPos
        npw = normalPos.getPosition(space='world')
        normalVec = npw - bboxCenter
    else:
        side = "L"
        normalPos = outPos
        npw = normalPos.getPosition(space='world')
        normalVec = bboxCenter - npw
    # Manual Vertex corners
    if customCorner:
        if intCorner:
            try:
                if side == "R":
                    inPos = pm.PyNode(extCorner)
                else:
                    inPos = pm.PyNode(intCorner)
            except pm.MayaNodeError:
                pm.displayWarning("%s can not be found" % intCorner)
                return
        else:
            pm.displayWarning("Please set the internal eyelid corner")
            return

        if extCorner:
            try:
                normalPos = pm.PyNode(extCorner)
                npw = normalPos.getPosition(space='world')
                if side == "R":
                    outPos = pm.PyNode(intCorner)
                    normalVec = npw - bboxCenter
                else:
                    outPos = pm.PyNode(extCorner)
                    normalVec = bboxCenter - npw
            except pm.MayaNodeError:
                pm.displayWarning("%s can not be found" % extCorner)
                return
        else:
            pm.displayWarning("Please set the external eyelid corner")
            return

    # Check if we have prefix:
    if namePrefix:
        namePrefix = string.removeInvalidCharacter(namePrefix)
    else:
        pm.displayWarning("Prefix is needed")
        return

    def setName(name, ind=None):
        namesList = [namePrefix, side, name]
        if ind is not None:
            namesList[1] = side + str(ind)
        name = "_".join(namesList)
        return name

    if pm.ls(setName("root")):
        pm.displayWarning("The object %s already exist in the scene. Please "
                          "choose another name prefix" % setName("root"))
        return

    # Eye root
    eye_root = primitive.addTransform(None, setName("root"))
    eyeCrv_root = primitive.addTransform(eye_root, setName("crvs"))

    # Eyelid Main crvs
    try:
        upEyelid = meshNavigation.edgeRangeInLoopFromMid(
            edgeList, upPos, inPos, outPos)
        upCrv = curve.createCurveFromOrderedEdges(upEyelid,
                                                  inPos,
                                                  setName("upperEyelid"),
                                                  parent=eyeCrv_root)
        upCrv_ctl = curve.createCurveFromOrderedEdges(upEyelid,
                                                      inPos,
                                                      setName("upCtl_crv"),
                                                      parent=eyeCrv_root)
        pm.rebuildCurve(upCrv_ctl, s=2, rt=0, rpo=True, ch=False)

        lowEyelid = meshNavigation.edgeRangeInLoopFromMid(
            edgeList, lowPos, inPos, outPos)
        lowCrv = curve.createCurveFromOrderedEdges(lowEyelid,
                                                   inPos,
                                                   setName("lowerEyelid"),
                                                   parent=eyeCrv_root)
        lowCrv_ctl = curve.createCurveFromOrderedEdges(lowEyelid,
                                                       inPos,
                                                       setName("lowCtl_crv"),
                                                       parent=eyeCrv_root)

        pm.rebuildCurve(lowCrv_ctl, s=2, rt=0, rpo=True, ch=False)

    except UnboundLocalError:
        if customCorner:
            pm.displayWarning("This error is maybe caused because the custom "
                              "Corner vertex is not part of the edge loop")
        pm.displayError(traceback.format_exc())
        return

    upBlink = curve.createCurveFromCurve(upCrv,
                                         setName("upblink_crv"),
                                         nbPoints=30,
                                         parent=eyeCrv_root)
    lowBlink = curve.createCurveFromCurve(lowCrv,
                                          setName("lowBlink_crv"),
                                          nbPoints=30,
                                          parent=eyeCrv_root)

    upTarget = curve.createCurveFromCurve(upCrv,
                                          setName("upblink_target"),
                                          nbPoints=30,
                                          parent=eyeCrv_root)
    lowTarget = curve.createCurveFromCurve(lowCrv,
                                           setName("lowBlink_target"),
                                           nbPoints=30,
                                           parent=eyeCrv_root)
    midTarget = curve.createCurveFromCurve(lowCrv,
                                           setName("midBlink_target"),
                                           nbPoints=30,
                                           parent=eyeCrv_root)

    rigCrvs = [
        upCrv, lowCrv, upCrv_ctl, lowCrv_ctl, upBlink, lowBlink, upTarget,
        lowTarget, midTarget
    ]

    for crv in rigCrvs:
        crv.attr("visibility").set(False)

    # localBBOX
    localBBox = eyeMesh.getBoundingBox(invisible=True, space='world')
    wRadius = abs((localBBox[0][0] - localBBox[1][0]))
    dRadius = abs((localBBox[0][1] - localBBox[1][1]) / 1.7)

    # Groups
    if not ctlGrp:
        ctlGrp = "rig_controllers_grp"
    try:
        ctlSet = pm.PyNode(ctlGrp)
    except pm.MayaNodeError:
        pm.sets(n=ctlGrp, em=True)
        ctlSet = pm.PyNode(ctlGrp)
    if not defGrp:
        defGrp = "rig_deformers_grp"
    try:
        defset = pm.PyNode(defGrp)
    except pm.MayaNodeError:
        pm.sets(n=defGrp, em=True)
        defset = pm.PyNode(defGrp)

    # Calculate center looking at
    averagePosition = (
        (upPos.getPosition(space='world') + lowPos.getPosition(space='world') +
         inPos.getPosition(space='world') + outPos.getPosition(space='world'))
        / 4)
    if side == "R":
        negate = False
        offset = offset
        over_offset = dRadius
    else:
        negate = False
        over_offset = dRadius

    if side == "R" and sideRange or side == "R" and customCorner:
        axis = "z-x"
        # axis = "zx"
    else:
        axis = "z-x"

    t = transform.getTransformLookingAt(bboxCenter,
                                        averagePosition,
                                        normalVec,
                                        axis=axis,
                                        negate=negate)

    over_npo = primitive.addTransform(eye_root, setName("center_lookatRoot"),
                                      t)

    over_ctl = icon.create(over_npo,
                           setName("over_%s" % ctlName),
                           t,
                           icon="square",
                           w=wRadius,
                           d=dRadius,
                           ro=datatypes.Vector(1.57079633, 0, 0),
                           po=datatypes.Vector(0, 0, over_offset),
                           color=4)
    node.add_controller_tag(over_ctl)
    attribute.add_mirror_config_channels(over_ctl)
    attribute.setKeyableAttributes(
        over_ctl,
        params=["tx", "ty", "tz", "ro", "rx", "ry", "rz", "sx", "sy", "sz"])

    if side == "R":
        over_npo.attr("rx").set(over_npo.attr("rx").get() * -1)
        over_npo.attr("ry").set(over_npo.attr("ry").get() + 180)
        over_npo.attr("sz").set(-1)

    if len(ctlName.split("_")) == 2 and ctlName.split("_")[-1] == "ghost":
        pass
    else:
        pm.sets(ctlSet, add=over_ctl)

    center_lookat = primitive.addTransform(over_ctl, setName("center_lookat"),
                                           t)

    # Tracking
    # Eye aim control
    t_arrow = transform.getTransformLookingAt(bboxCenter,
                                              averagePosition,
                                              upPos.getPosition(space='world'),
                                              axis="zy",
                                              negate=False)

    radius = abs((localBBox[0][0] - localBBox[1][0]) / 1.7)
    arrow_npo = primitive.addTransform(eye_root, setName("aim_npo"), t_arrow)
    arrow_ctl = icon.create(arrow_npo,
                            setName("aim_%s" % ctlName),
                            t_arrow,
                            icon="arrow",
                            w=1,
                            po=datatypes.Vector(0, 0, radius),
                            color=4)
    if len(ctlName.split("_")) == 2 and ctlName.split("_")[-1] == "ghost":
        pass
    else:
        pm.sets(ctlSet, add=arrow_ctl)
    attribute.setKeyableAttributes(arrow_ctl, params=["rx", "ry", "rz"])

    # tracking custom trigger
    if side == "R":
        tt = t_arrow
    else:
        tt = t
    aimTrigger_root = primitive.addTransform(center_lookat,
                                             setName("aimTrigger_root"), tt)
    aimTrigger_lvl = primitive.addTransform(aimTrigger_root,
                                            setName("aimTrigger_lvl"), tt)
    aimTrigger_lvl.attr("tz").set(1.0)
    aimTrigger_ref = primitive.addTransform(aimTrigger_lvl,
                                            setName("aimTrigger_ref"), tt)
    aimTrigger_ref.attr("tz").set(0.0)
    # connect  trigger with arrow_ctl
    pm.parentConstraint(arrow_ctl, aimTrigger_ref, mo=True)

    # Controls lists
    upControls = []
    trackLvl = []

    # upper eyelid controls
    upperCtlNames = ["inCorner", "upInMid", "upMid", "upOutMid", "outCorner"]
    cvs = upCrv_ctl.getCVs(space="world")
    if side == "R" and not sideRange:
        # if side == "R":
        cvs = [cv for cv in reversed(cvs)]
    for i, cv in enumerate(cvs):
        if utils.is_odd(i):
            color = 14
            wd = .5
            icon_shape = "circle"
            params = ["tx", "ty", "tz"]
        else:
            color = 4
            wd = .7
            icon_shape = "square"
            params = [
                "tx", "ty", "tz", "ro", "rx", "ry", "rz", "sx", "sy", "sz"
            ]

        t = transform.setMatrixPosition(t, cvs[i])
        npo = primitive.addTransform(center_lookat,
                                     setName("%s_npo" % upperCtlNames[i]), t)
        npoBase = npo
        if i == 2:
            # we add an extra level to input the tracking ofset values
            npo = primitive.addTransform(npo,
                                         setName("%s_trk" % upperCtlNames[i]),
                                         t)
            trackLvl.append(npo)

        ctl = icon.create(npo,
                          setName("%s_%s" % (upperCtlNames[i], ctlName)),
                          t,
                          icon=icon_shape,
                          w=wd,
                          d=wd,
                          ro=datatypes.Vector(1.57079633, 0, 0),
                          po=datatypes.Vector(0, 0, offset),
                          color=color)
        attribute.add_mirror_config_channels(ctl)
        node.add_controller_tag(ctl, over_ctl)
        upControls.append(ctl)
        if len(ctlName.split("_")) == 2 and ctlName.split("_")[-1] == "ghost":
            pass
        else:
            pm.sets(ctlSet, add=ctl)
        attribute.setKeyableAttributes(ctl, params)
        if side == "R":
            npoBase.attr("ry").set(180)
            npoBase.attr("sz").set(-1)

    # adding parent average contrains to odd controls
    for i, ctl in enumerate(upControls):
        if utils.is_odd(i):
            cns_node = pm.parentConstraint(upControls[i - 1],
                                           upControls[i + 1],
                                           ctl.getParent(),
                                           mo=True)
            # Make the constraint "noFlip"
            cns_node.interpType.set(0)

    # lower eyelid controls
    lowControls = [upControls[0]]
    lowerCtlNames = [
        "inCorner", "lowInMid", "lowMid", "lowOutMid", "outCorner"
    ]

    cvs = lowCrv_ctl.getCVs(space="world")
    if side == "R" and not sideRange:
        cvs = [cv for cv in reversed(cvs)]
    for i, cv in enumerate(cvs):
        # we skip the first and last point since is already in the uper eyelid
        if i in [0, 4]:
            continue
        if utils.is_odd(i):
            color = 14
            wd = .5
            icon_shape = "circle"
            params = ["tx", "ty", "tz"]
        else:
            color = 4
            wd = .7
            icon_shape = "square"
            params = [
                "tx", "ty", "tz", "ro", "rx", "ry", "rz", "sx", "sy", "sz"
            ]

        t = transform.setMatrixPosition(t, cvs[i])
        npo = primitive.addTransform(center_lookat,
                                     setName("%s_npo" % lowerCtlNames[i]), t)
        npoBase = npo
        if i == 2:
            # we add an extra level to input the tracking ofset values
            npo = primitive.addTransform(npo,
                                         setName("%s_trk" % lowerCtlNames[i]),
                                         t)
            trackLvl.append(npo)
        ctl = icon.create(npo,
                          setName("%s_%s" % (lowerCtlNames[i], ctlName)),
                          t,
                          icon=icon_shape,
                          w=wd,
                          d=wd,
                          ro=datatypes.Vector(1.57079633, 0, 0),
                          po=datatypes.Vector(0, 0, offset),
                          color=color)
        attribute.add_mirror_config_channels(ctl)

        lowControls.append(ctl)
        if len(ctlName.split("_")) == 2 and ctlName.split("_")[-1] == "ghost":
            pass
        else:
            pm.sets(ctlSet, add=ctl)
        attribute.setKeyableAttributes(ctl, params)
        # mirror behaviout on R side controls
        if side == "R":
            npoBase.attr("ry").set(180)
            npoBase.attr("sz").set(-1)
    for lctl in reversed(lowControls[1:]):
        node.add_controller_tag(lctl, over_ctl)
    lowControls.append(upControls[-1])

    # adding parent average contrains to odd controls
    for i, ctl in enumerate(lowControls):
        if utils.is_odd(i):
            cns_node = pm.parentConstraint(lowControls[i - 1],
                                           lowControls[i + 1],
                                           ctl.getParent(),
                                           mo=True)
            # Make the constraint "noFlip"
            cns_node.interpType.set(0)

    # Connecting control crvs with controls
    applyop.gear_curvecns_op(upCrv_ctl, upControls)
    applyop.gear_curvecns_op(lowCrv_ctl, lowControls)

    # adding wires
    w1 = pm.wire(upCrv, w=upBlink)[0]
    w2 = pm.wire(lowCrv, w=lowBlink)[0]

    w3 = pm.wire(upTarget, w=upCrv_ctl)[0]
    w4 = pm.wire(lowTarget, w=lowCrv_ctl)[0]

    # adding blendshapes
    bs_upBlink = pm.blendShape(upTarget,
                               midTarget,
                               upBlink,
                               n="blendShapeUpBlink")
    bs_lowBlink = pm.blendShape(lowTarget,
                                midTarget,
                                lowBlink,
                                n="blendShapeLowBlink")
    bs_mid = pm.blendShape(lowTarget,
                           upTarget,
                           midTarget,
                           n="blendShapeLowBlink")

    # setting blendshape reverse connections
    rev_node = pm.createNode("reverse")
    pm.connectAttr(bs_upBlink[0].attr(midTarget.name()), rev_node + ".inputX")
    pm.connectAttr(rev_node + ".outputX", bs_upBlink[0].attr(upTarget.name()))
    rev_node = pm.createNode("reverse")
    pm.connectAttr(bs_lowBlink[0].attr(midTarget.name()), rev_node + ".inputX")
    pm.connectAttr(rev_node + ".outputX",
                   bs_lowBlink[0].attr(lowTarget.name()))
    rev_node = pm.createNode("reverse")
    pm.connectAttr(bs_mid[0].attr(upTarget.name()), rev_node + ".inputX")
    pm.connectAttr(rev_node + ".outputX", bs_mid[0].attr(lowTarget.name()))

    # setting default values
    bs_mid[0].attr(upTarget.name()).set(blinkH)

    # joints root
    jnt_root = primitive.addTransformFromPos(eye_root,
                                             setName("joints"),
                                             pos=bboxCenter)

    # head joint
    if headJnt:
        try:
            headJnt = pm.PyNode(headJnt)
            jnt_base = headJnt
        except pm.MayaNodeError:
            pm.displayWarning("Aborted can not find %s " % headJnt)
            return
    else:
        # Eye root
        jnt_base = jnt_root

    eyeTargets_root = primitive.addTransform(eye_root, setName("targets"))

    eyeCenter_jnt = rigbits.addJnt(arrow_ctl,
                                   jnt_base,
                                   grp=defset,
                                   jntName=setName("center_jnt"))

    # Upper Eyelid joints ##################################################

    cvs = upCrv.getCVs(space="world")
    upCrv_info = node.createCurveInfoNode(upCrv)

    # aim constrain targets and joints
    upperEyelid_aimTargets = []
    upperEyelid_jnt = []
    upperEyelid_jntRoot = []

    for i, cv in enumerate(cvs):

        # aim targets
        trn = primitive.addTransformFromPos(eyeTargets_root,
                                            setName("upEyelid_aimTarget", i),
                                            pos=cv)
        upperEyelid_aimTargets.append(trn)
        # connecting positions with crv
        pm.connectAttr(upCrv_info + ".controlPoints[%s]" % str(i),
                       trn.attr("translate"))

        # joints
        jntRoot = primitive.addJointFromPos(jnt_root,
                                            setName("upEyelid_jnt_base", i),
                                            pos=bboxCenter)
        jntRoot.attr("radius").set(.08)
        jntRoot.attr("visibility").set(False)
        upperEyelid_jntRoot.append(jntRoot)
        applyop.aimCns(jntRoot, trn, axis="zy", wupObject=jnt_root)

        jnt_ref = primitive.addJointFromPos(jntRoot,
                                            setName("upEyelid_jnt_ref", i),
                                            pos=cv)
        jnt_ref.attr("radius").set(.08)
        jnt_ref.attr("visibility").set(False)

        jnt = rigbits.addJnt(jnt_ref,
                             jnt_base,
                             grp=defset,
                             jntName=setName("upEyelid_jnt", i))
        upperEyelid_jnt.append(jnt)

    # Lower Eyelid joints ##################################################

    cvs = lowCrv.getCVs(space="world")
    lowCrv_info = node.createCurveInfoNode(lowCrv)

    # aim constrain targets and joints
    lowerEyelid_aimTargets = []
    lowerEyelid_jnt = []
    lowerEyelid_jntRoot = []

    for i, cv in enumerate(cvs):
        if i in [0, len(cvs) - 1]:
            continue

        # aim targets
        trn = primitive.addTransformFromPos(eyeTargets_root,
                                            setName("lowEyelid_aimTarget", i),
                                            pos=cv)
        lowerEyelid_aimTargets.append(trn)
        # connecting positions with crv
        pm.connectAttr(lowCrv_info + ".controlPoints[%s]" % str(i),
                       trn.attr("translate"))

        # joints
        jntRoot = primitive.addJointFromPos(jnt_root,
                                            setName("lowEyelid_base", i),
                                            pos=bboxCenter)
        jntRoot.attr("radius").set(.08)
        jntRoot.attr("visibility").set(False)
        lowerEyelid_jntRoot.append(jntRoot)
        applyop.aimCns(jntRoot, trn, axis="zy", wupObject=jnt_root)

        jnt_ref = primitive.addJointFromPos(jntRoot,
                                            setName("lowEyelid_jnt_ref", i),
                                            pos=cv)
        jnt_ref.attr("radius").set(.08)
        jnt_ref.attr("visibility").set(False)

        jnt = rigbits.addJnt(jnt_ref,
                             jnt_base,
                             grp=defset,
                             jntName=setName("lowEyelid_jnt", i))
        lowerEyelid_jnt.append(jnt)

    # Channels
    # Adding and connecting attributes for the blink
    up_ctl = upControls[2]
    blink_att = attribute.addAttribute(over_ctl,
                                       "blink",
                                       "float",
                                       0,
                                       minValue=0,
                                       maxValue=1)
    blinkMult_att = attribute.addAttribute(over_ctl,
                                           "blinkMult",
                                           "float",
                                           1,
                                           minValue=1,
                                           maxValue=2)
    midBlinkH_att = attribute.addAttribute(over_ctl,
                                           "blinkHeight",
                                           "float",
                                           blinkH,
                                           minValue=0,
                                           maxValue=1)
    mult_node = node.createMulNode(blink_att, blinkMult_att)
    pm.connectAttr(mult_node + ".outputX",
                   bs_upBlink[0].attr(midTarget.name()))
    pm.connectAttr(mult_node + ".outputX",
                   bs_lowBlink[0].attr(midTarget.name()))
    pm.connectAttr(midBlinkH_att, bs_mid[0].attr(upTarget.name()))

    low_ctl = lowControls[2]

    # Adding channels for eye tracking
    upVTracking_att = attribute.addAttribute(up_ctl,
                                             "vTracking",
                                             "float",
                                             .02,
                                             minValue=0,
                                             maxValue=1,
                                             keyable=False,
                                             channelBox=True)
    upHTracking_att = attribute.addAttribute(up_ctl,
                                             "hTracking",
                                             "float",
                                             .01,
                                             minValue=0,
                                             maxValue=1,
                                             keyable=False,
                                             channelBox=True)

    lowVTracking_att = attribute.addAttribute(low_ctl,
                                              "vTracking",
                                              "float",
                                              .01,
                                              minValue=0,
                                              maxValue=1,
                                              keyable=False,
                                              channelBox=True)
    lowHTracking_att = attribute.addAttribute(low_ctl,
                                              "hTracking",
                                              "float",
                                              .01,
                                              minValue=0,
                                              maxValue=1,
                                              keyable=False,
                                              channelBox=True)

    mult_node = node.createMulNode(upVTracking_att, aimTrigger_ref.attr("ty"))
    pm.connectAttr(mult_node + ".outputX", trackLvl[0].attr("ty"))
    mult_node = node.createMulNode(upHTracking_att, aimTrigger_ref.attr("tx"))
    pm.connectAttr(mult_node + ".outputX", trackLvl[0].attr("tx"))

    mult_node = node.createMulNode(lowVTracking_att, aimTrigger_ref.attr("ty"))
    pm.connectAttr(mult_node + ".outputX", trackLvl[1].attr("ty"))
    mult_node = node.createMulNode(lowHTracking_att, aimTrigger_ref.attr("tx"))
    pm.connectAttr(mult_node + ".outputX", trackLvl[1].attr("tx"))

    # Tension on blink
    node.createReverseNode(blink_att, w1.scale[0])
    node.createReverseNode(blink_att, w3.scale[0])
    node.createReverseNode(blink_att, w2.scale[0])
    node.createReverseNode(blink_att, w4.scale[0])

    ###########################################
    # Reparenting
    ###########################################
    if parent:
        try:
            if isinstance(parent, basestring):
                parent = pm.PyNode(parent)
            parent.addChild(eye_root)
        except pm.MayaNodeError:
            pm.displayWarning("The eye rig can not be parent to: %s. Maybe "
                              "this object doesn't exist." % parent)

    ###########################################
    # Auto Skinning
    ###########################################
    if doSkin:
        # eyelid vertex rows
        totalLoops = rigidLoops + falloffLoops
        vertexLoopList = meshNavigation.getConcentricVertexLoop(
            vertexList, totalLoops)
        vertexRowList = meshNavigation.getVertexRowsFromLoops(vertexLoopList)

        # we set the first value 100% for the first initial loop
        skinPercList = [1.0]
        # we expect to have a regular grid topology
        for r in range(rigidLoops):
            for rr in range(2):
                skinPercList.append(1.0)
        increment = 1.0 / float(falloffLoops)
        # we invert to smooth out from 100 to 0
        inv = 1.0 - increment
        for r in range(falloffLoops):
            for rr in range(2):
                if inv < 0.0:
                    inv = 0.0
                skinPercList.append(inv)
            inv -= increment

        # this loop add an extra 0.0 indices to avoid errors
        for r in range(10):
            for rr in range(2):
                skinPercList.append(0.0)

        # base skin
        geo = pm.listRelatives(edgeLoopList[0], parent=True)[0]
        # Check if the object has a skinCluster
        objName = pm.listRelatives(geo, parent=True)[0]

        skinCluster = skin.getSkinCluster(objName)
        if not skinCluster:
            skinCluster = pm.skinCluster(headJnt,
                                         geo,
                                         tsb=True,
                                         nw=2,
                                         n='skinClsEyelid')

        eyelidJoints = upperEyelid_jnt + lowerEyelid_jnt
        pm.progressWindow(title='Auto skinning process',
                          progress=0,
                          max=len(eyelidJoints))
        firstBoundary = False
        for jnt in eyelidJoints:
            pm.progressWindow(e=True, step=1, status='\nSkinning %s' % jnt)
            skinCluster.addInfluence(jnt, weight=0)
            v = meshNavigation.getClosestVertexFromTransform(geo, jnt)

            for row in vertexRowList:

                if v in row:
                    it = 0  # iterator
                    inc = 1  # increment
                    for i, rv in enumerate(row):
                        try:
                            perc = skinPercList[it]
                            t_val = [(jnt, perc), (headJnt, 1.0 - perc)]
                            pm.skinPercent(skinCluster,
                                           rv,
                                           transformValue=t_val)
                            if rv.isOnBoundary():
                                # we need to compare with the first boundary
                                # to check if the row have inverted direction
                                # and offset the value
                                if not firstBoundary:
                                    firstBoundary = True
                                    firstBoundaryValue = it

                                else:
                                    if it < firstBoundaryValue:
                                        it -= 1
                                    elif it > firstBoundaryValue:
                                        it += 1
                                inc = 2
                        except IndexError:
                            continue

                        it = it + inc
        pm.progressWindow(e=True, endProgress=True)

        # Eye Mesh skinning
        skinCluster = skin.getSkinCluster(eyeMesh)
        if not skinCluster:
            skinCluster = pm.skinCluster(eyeCenter_jnt,
                                         eyeMesh,
                                         tsb=True,
                                         nw=1,
                                         n='skinClsEye')
예제 #7
0
def rig(
    eyeMesh=None,
    edgeLoop="",
    blinkH=20,
    namePrefix="eye",
    offset=0.05,
    rigidLoops=2,
    falloffLoops=4,
    headJnt=None,
    doSkin=True,
    parent_node=None,
    ctlName="ctl",
    sideRange=False,
    customCorner=False,
    intCorner=None,
    extCorner=None,
    ctlSet=None,
    defSet=None,
    upperVTrack=0.02,
    upperHTrack=0.01,
    lowerVTrack=0.02,
    lowerHTrack=0.01,
    aim_controller="",
    deformers_group="",
    everyNVertex=1,
):
    """Create eyelid and eye rig

    Args:
        eyeMesh (TYPE): Description
        edgeLoop (TYPE): Description
        blinkH (TYPE): Description
        namePrefix (TYPE): Description
        offset (TYPE): Description
        rigidLoops (TYPE): Description
        falloffLoops (TYPE): Description
        headJnt (TYPE): Description
        doSkin (TYPE): Description
        parent_node (None, optional): Description
        ctlName (str, optional): Description
        sideRange (bool, optional): Description
        customCorner (bool, optional): Description
        intCorner (None, optional): Description
        extCorner (None, optional): Description
        ctlSet (None, optional): Description
        defSet (None, optional): Description
        upperVTrack (None, optional): Description
        upperHTrack (None, optional): Description
        lowerVTrack (None, optional): Description
        lowerHTrack (None, optional): Description
        aim_controller (None, optional): Description
        deformers_group (None, optional): Description
        everyNVertex (int, optional): Will create a joint every N vertex

    No Longer Returned:
        TYPE: Description
    """

    ##########################################
    # INITIAL SETUP
    ##########################################
    up_axis = pm.upAxis(q=True, axis=True)
    if up_axis == "z":
        z_up = True
    else:
        z_up = False

    # getters
    edgeLoopList = get_edge_loop(edgeLoop)
    eyeMesh = get_eye_mesh(eyeMesh)

    # checkers
    if not edgeLoopList or not eyeMesh:
        return
    if doSkin:
        if not headJnt:
            pm.displayWarning("Please set the Head Jnt or unCheck "
                              "Compute Topological Autoskin")
            return

    # Convert data
    blinkH = blinkH / 100.0

    # Initial Data
    bboxCenter = meshNavigation.bboxCenter(eyeMesh)

    extr_v = meshNavigation.getExtremeVertexFromLoop(edgeLoopList, sideRange,
                                                     z_up)
    upPos = extr_v[0]
    lowPos = extr_v[1]
    inPos = extr_v[2]
    outPos = extr_v[3]
    edgeList = extr_v[4]
    vertexList = extr_v[5]

    # Detect the side L or R from the x value
    if inPos.getPosition(space="world")[0] < 0.0:
        side = "R"
        inPos = extr_v[3]
        outPos = extr_v[2]
        normalPos = outPos
        npw = normalPos.getPosition(space="world")
        normalVec = npw - bboxCenter
    else:
        side = "L"
        normalPos = outPos
        npw = normalPos.getPosition(space="world")
        normalVec = bboxCenter - npw

    # Manual Vertex corners
    if customCorner:
        if intCorner:
            try:
                if side == "R":
                    inPos = pm.PyNode(extCorner)
                else:
                    inPos = pm.PyNode(intCorner)
            except pm.MayaNodeError:
                pm.displayWarning("%s can not be found" % intCorner)
                return
        else:
            pm.displayWarning("Please set the internal eyelid corner")
            return

        if extCorner:
            try:
                normalPos = pm.PyNode(extCorner)
                npw = normalPos.getPosition(space="world")
                if side == "R":
                    outPos = pm.PyNode(intCorner)
                    normalVec = npw - bboxCenter
                else:
                    outPos = pm.PyNode(extCorner)
                    normalVec = bboxCenter - npw
            except pm.MayaNodeError:
                pm.displayWarning("%s can not be found" % extCorner)
                return
        else:
            pm.displayWarning("Please set the external eyelid corner")
            return

    # Check if we have prefix:
    if namePrefix:
        namePrefix = string.removeInvalidCharacter(namePrefix)
    else:
        pm.displayWarning("Prefix is needed")
        return

    def setName(name, ind=None):
        namesList = [namePrefix, side, name]
        if ind is not None:
            namesList[1] = side + str(ind)
        name = "_".join(namesList)
        return name

    if pm.ls(setName("root")):
        pm.displayWarning("The object %s already exist in the scene. Please "
                          "choose another name prefix" % setName("root"))
        return

    ##########################################
    # CREATE OBJECTS
    ##########################################

    # Eye root
    eye_root = primitive.addTransform(None, setName("root"))
    eyeCrv_root = primitive.addTransform(eye_root, setName("crvs"))

    # Eyelid Main crvs
    try:
        upEyelid_edge = meshNavigation.edgeRangeInLoopFromMid(
            edgeList, upPos, inPos, outPos)
        up_crv = curve.createCurveFromOrderedEdges(upEyelid_edge,
                                                   inPos,
                                                   setName("upperEyelid"),
                                                   parent=eyeCrv_root)
        upCtl_crv = curve.createCurveFromOrderedEdges(upEyelid_edge,
                                                      inPos,
                                                      setName("upCtl_crv"),
                                                      parent=eyeCrv_root)
        pm.rebuildCurve(upCtl_crv, s=2, rt=0, rpo=True, ch=False)

        lowEyelid_edge = meshNavigation.edgeRangeInLoopFromMid(
            edgeList, lowPos, inPos, outPos)
        low_crv = curve.createCurveFromOrderedEdges(lowEyelid_edge,
                                                    inPos,
                                                    setName("lowerEyelid"),
                                                    parent=eyeCrv_root)
        lowCtl_crv = curve.createCurveFromOrderedEdges(lowEyelid_edge,
                                                       inPos,
                                                       setName("lowCtl_crv"),
                                                       parent=eyeCrv_root)

        pm.rebuildCurve(lowCtl_crv, s=2, rt=0, rpo=True, ch=False)

    except UnboundLocalError:
        if customCorner:
            pm.displayWarning("This error is maybe caused because the custom "
                              "Corner vertex is not part of the edge loop")
        pm.displayError(traceback.format_exc())
        return

    # blendshape  curves. All crv have 30 point to allow blendshape connect
    upDriver_crv = curve.createCurveFromCurve(up_crv,
                                              setName("upDriver_crv"),
                                              nbPoints=30,
                                              parent=eyeCrv_root)
    upDriver_crv.attr("lineWidth").set(5)
    lowDriver_crv = curve.createCurveFromCurve(low_crv,
                                               setName("lowDriver_crv"),
                                               nbPoints=30,
                                               parent=eyeCrv_root)
    lowDriver_crv.attr("lineWidth").set(5)

    upRest_target_crv = curve.createCurveFromCurve(
        up_crv, setName("upRest_target_crv"), nbPoints=30, parent=eyeCrv_root)
    lowRest_target_crv = curve.createCurveFromCurve(
        low_crv,
        setName("lowRest_target_crv"),
        nbPoints=30,
        parent=eyeCrv_root)
    upProfile_target_crv = curve.createCurveFromCurve(
        up_crv,
        setName("upProfile_target_crv"),
        nbPoints=30,
        parent=eyeCrv_root,
    )
    lowProfile_target_crv = curve.createCurveFromCurve(
        low_crv,
        setName("lowProfile_target_crv"),
        nbPoints=30,
        parent=eyeCrv_root,
    )

    # mid driver
    midUpDriver_crv = curve.createCurveFromCurve(up_crv,
                                                 setName("midUpDriver_crv"),
                                                 nbPoints=30,
                                                 parent=eyeCrv_root)
    midLowDriver_crv = curve.createCurveFromCurve(low_crv,
                                                  setName("midLowDriver_crv"),
                                                  nbPoints=30,
                                                  parent=eyeCrv_root)

    # curve that define the close point of the eyelid
    closeTarget_crv = curve.createCurveFromCurve(up_crv,
                                                 setName("closeTarget_crv"),
                                                 nbPoints=30,
                                                 parent=eyeCrv_root)

    eyeCrv_root.attr("visibility").set(False)

    # localBBOX
    localBBox = eyeMesh.getBoundingBox(invisible=True, space="world")
    wRadius = abs((localBBox[0][0] - localBBox[1][0]))
    dRadius = abs((localBBox[0][1] - localBBox[1][1]) / 1.7)

    # Groups
    if not ctlSet:
        ctlSet = "rig_controllers_grp"
    try:
        ctlSet = pm.PyNode(ctlSet)
    except pm.MayaNodeError:
        pm.sets(n=ctlSet, em=True)
        ctlSet = pm.PyNode(ctlSet)
    if not defSet:
        defSet = "rig_deformers_grp"
    try:
        defset = pm.PyNode(defSet)
    except pm.MayaNodeError:
        pm.sets(n=defSet, em=True)
        defset = pm.PyNode(defSet)

    # Calculate center looking at
    averagePosition = (upPos.getPosition(space="world") + lowPos.getPosition(
        space="world") + inPos.getPosition(space="world") +
                       outPos.getPosition(space="world")) / 4

    if z_up:
        axis = "zx"
    else:
        axis = "z-x"
    t = transform.getTransformLookingAt(bboxCenter,
                                        averagePosition,
                                        normalVec,
                                        axis=axis,
                                        negate=False)

    over_npo = primitive.addTransform(eye_root, setName("center_lookatRoot"),
                                      t)

    center_lookat = primitive.addTransform(over_npo, setName("center_lookat"),
                                           t)

    if side == "R":
        over_npo.attr("rx").set(over_npo.attr("rx").get() * -1)
        over_npo.attr("ry").set(over_npo.attr("ry").get() + 180)
        over_npo.attr("sz").set(-1)
    t = transform.getTransform(over_npo)

    # Tracking
    # Eye aim control
    t_arrow = transform.getTransformLookingAt(
        bboxCenter,
        averagePosition,
        upPos.getPosition(space="world"),
        axis="zy",
        negate=False,
    )

    radius = abs((localBBox[0][0] - localBBox[1][0]) / 1.7)

    arrow_ctl = None
    arrow_npo = None
    if aim_controller:
        arrow_ctl = pm.PyNode(aim_controller)
    else:
        arrow_npo = primitive.addTransform(eye_root, setName("aim_npo"),
                                           t_arrow)
        arrow_ctl = icon.create(
            arrow_npo,
            setName("aim_%s" % ctlName),
            t_arrow,
            icon="arrow",
            w=1,
            po=datatypes.Vector(0, 0, radius),
            color=4,
        )
    if len(ctlName.split("_")) == 2 and ctlName.split("_")[-1] == "ghost":
        pass
    else:
        pm.sets(ctlSet, add=arrow_ctl)
    attribute.setKeyableAttributes(arrow_ctl, params=["rx", "ry", "rz"])
    attribute.addAttribute(arrow_ctl, "isCtl", "bool", keyable=False)

    # tracking custom trigger
    if side == "R":
        tt = t_arrow
    else:
        tt = t
    aimTrigger_root = primitive.addTransform(center_lookat,
                                             setName("aimTrigger_root"), tt)
    # For some unknown reason the right side gets scewed rotation values
    mgear.core.transform.resetTransform(aimTrigger_root)
    aimTrigger_lvl = primitive.addTransform(aimTrigger_root,
                                            setName("aimTrigger_lvl"), tt)
    # For some unknown reason the right side gets scewed rotation values
    mgear.core.transform.resetTransform(aimTrigger_lvl)
    aimTrigger_lvl.attr("tz").set(1.0)
    aimTrigger_ref = primitive.addTransform(aimTrigger_lvl,
                                            setName("aimTrigger_ref"), tt)
    # For some unknown reason the right side gets scewed rotation values
    mgear.core.transform.resetTransform(aimTrigger_ref)
    aimTrigger_ref.attr("tz").set(0.0)
    # connect  trigger with arrow_ctl
    pm.parentConstraint(arrow_ctl, aimTrigger_ref, mo=True)

    # Blink driver controls
    if z_up:
        trigger_axis = "tz"
        ro_up = [0, 1.57079633 * 2, 1.57079633]
        ro_low = [0, 0, 1.57079633]
        po = [0, offset * -1, 0]
        low_pos = 2  # Z
    else:
        trigger_axis = "ty"
        ro_up = (1.57079633, 1.57079633, 0)
        ro_low = [1.57079633, 1.57079633, 1.57079633 * 2]
        po = [0, 0, offset]
        low_pos = 1  # Y

    # upper ctl
    p = upRest_target_crv.getCVs(space="world")[15]
    ut = transform.setMatrixPosition(datatypes.Matrix(), p)
    npo = primitive.addTransform(over_npo, setName("upBlink_npo"), ut)

    up_ctl = icon.create(
        npo,
        setName("upBlink_ctl"),
        ut,
        icon="arrow",
        w=2.5,
        d=2.5,
        ro=datatypes.Vector(ro_up[0], ro_up[1], ro_up[2]),
        po=datatypes.Vector(po[0], po[1], po[2]),
        color=4,
    )
    attribute.setKeyableAttributes(up_ctl, [trigger_axis])
    pm.sets(ctlSet, add=up_ctl)

    # use translation of the object to drive the blink
    blink_driver = primitive.addTransform(up_ctl, setName("blink_drv"), ut)

    # lowe ctl
    p_low = lowRest_target_crv.getCVs(space="world")[15]
    p[low_pos] = p_low[low_pos]
    lt = transform.setMatrixPosition(ut, p)
    npo = primitive.addTransform(over_npo, setName("lowBlink_npo"), lt)

    low_ctl = icon.create(
        npo,
        setName("lowBlink_ctl"),
        lt,
        icon="arrow",
        w=1.5,
        d=1.5,
        ro=datatypes.Vector(ro_low[0], ro_low[1], ro_low[2]),
        po=datatypes.Vector(po[0], po[1], po[2]),
        color=4,
    )
    attribute.setKeyableAttributes(low_ctl, [trigger_axis])
    pm.sets(ctlSet, add=low_ctl)

    # Controls lists
    upControls = []
    trackLvl = []
    track_corner_lvl = []
    corner_ctl = []
    ghost_ctl = []

    # upper eyelid controls
    upperCtlNames = ["inCorner", "upInMid", "upMid", "upOutMid", "outCorner"]
    cvs = upCtl_crv.getCVs(space="world")
    if side == "R" and not sideRange:
        # if side == "R":
        cvs = [cv for cv in reversed(cvs)]
        # offset = offset * -1
    for i, cv in enumerate(cvs):
        if utils.is_odd(i):
            color = 14
            wd = 0.3
            icon_shape = "circle"
            params = ["tx", "ty", "tz"]
        else:
            color = 4
            wd = 0.6
            icon_shape = "circle"
            params = [
                "tx",
                "ty",
                "tz",
                "ro",
                "rx",
                "ry",
                "rz",
                "sx",
                "sy",
                "sz",
            ]

        t = transform.setMatrixPosition(t, cvs[i])
        npo = primitive.addTransform(center_lookat,
                                     setName("%s_npo" % upperCtlNames[i]), t)
        npoBase = npo
        # track for corners and mid point level
        if i in [0, 2, 4]:
            # we add an extra level to input the tracking ofset values
            npo = primitive.addTransform(npo,
                                         setName("%s_trk" % upperCtlNames[i]),
                                         t)
            if i == 2:
                trackLvl.append(npo)
            else:
                track_corner_lvl.append(npo)

        if i in [1, 2, 3]:
            ctl = primitive.addTransform(npo,
                                         setName("%s_loc" % upperCtlNames[i]),
                                         t)
            # ghost controls
            if i == 2:
                gt = transform.setMatrixPosition(
                    t, transform.getPositionFromMatrix(ut))
            else:
                gt = t
            npo_g = primitive.addTransform(
                up_ctl, setName("%sCtl_npo" % upperCtlNames[i]), gt)
            ctl_g = icon.create(
                npo_g,
                setName("%s_%s" % (upperCtlNames[i], ctlName)),
                gt,
                icon=icon_shape,
                w=wd,
                d=wd,
                ro=datatypes.Vector(1.57079633, 0, 0),
                po=datatypes.Vector(0, 0, offset),
                color=color,
            )
            # define the ctl_param to recive the ctl configuration
            ctl_param = ctl_g
            ghost_ctl.append(ctl_g)
            # connect local SRT
            rigbits.connectLocalTransform([ctl_g, ctl])
        else:
            ctl = icon.create(
                npo,
                setName("%s_%s" % (upperCtlNames[i], ctlName)),
                t,
                icon=icon_shape,
                w=wd,
                d=wd,
                ro=datatypes.Vector(1.57079633, 0, 0),
                po=datatypes.Vector(0, 0, offset),
                color=color,
            )
            # define the ctl_param to recive the ctl configuration
            ctl_param = ctl
        attribute.addAttribute(ctl_param, "isCtl", "bool", keyable=False)
        attribute.add_mirror_config_channels(ctl_param)
        node.add_controller_tag(ctl_param, over_npo)
        if len(ctlName.split("_")) == 2 and ctlName.split("_")[-1] == "ghost":
            pass
        else:
            pm.sets(ctlSet, add=ctl_param)
        attribute.setKeyableAttributes(ctl_param, params)
        upControls.append(ctl)
        # add corner ctls to corner ctl list for tracking
        if i in [0, 4]:
            corner_ctl.append(ctl)
        # if side == "R":
        #     npoBase.attr("ry").set(180)
        #     npoBase.attr("sz").set(-1)
    # adding parent constraints to odd controls
    for i, ctl in enumerate(upControls):
        if utils.is_odd(i):
            cns_node = pm.parentConstraint(upControls[i - 1],
                                           upControls[i + 1],
                                           ctl.getParent(),
                                           mo=True)
            # Make the constraint "noFlip"
            cns_node.interpType.set(0)

    # adding parent constraint ghost controls
    cns_node = pm.parentConstraint(ghost_ctl[1],
                                   upControls[0],
                                   ghost_ctl[0].getParent(),
                                   mo=True)
    cns_node.interpType.set(0)
    cns_node = pm.parentConstraint(ghost_ctl[1],
                                   upControls[-1],
                                   ghost_ctl[2].getParent(),
                                   mo=True)
    cns_node.interpType.set(0)
    # lower eyelid controls
    lowControls = [upControls[0]]
    lowerCtlNames = [
        "inCorner",
        "lowInMid",
        "lowMid",
        "lowOutMid",
        "outCorner",
    ]

    cvs = lowCtl_crv.getCVs(space="world")
    if side == "R" and not sideRange:
        cvs = [cv for cv in reversed(cvs)]
    for i, cv in enumerate(cvs):
        # we skip the first and last point since is already in the uper eyelid
        if i in [0, 4]:
            continue
        if utils.is_odd(i):
            color = 14
            wd = 0.3
            icon_shape = "circle"
            params = ["tx", "ty", "tz"]
        else:
            color = 4
            wd = 0.6
            icon_shape = "circle"
            params = [
                "tx",
                "ty",
                "tz",
                "ro",
                "rx",
                "ry",
                "rz",
                "sx",
                "sy",
                "sz",
            ]

        t = transform.setMatrixPosition(t, cvs[i])
        npo = primitive.addTransform(center_lookat,
                                     setName("%s_npo" % lowerCtlNames[i]), t)
        npoBase = npo
        if i in [1, 2, 3]:
            if i == 2:
                # we add an extra level to input the tracking ofset values
                npo = primitive.addTransform(
                    npo, setName("%s_trk" % lowerCtlNames[i]), t)
                trackLvl.append(npo)
            ctl = primitive.addTransform(npo,
                                         setName("%s_loc" % lowerCtlNames[i]),
                                         t)
            # ghost controls
            if i == 2:
                gt = transform.setMatrixPosition(
                    t, transform.getPositionFromMatrix(lt))
            else:
                gt = t
            # ghost controls
            npo_g = primitive.addTransform(
                low_ctl, setName("%sCtl_npo" % lowerCtlNames[i]), gt)
            ctl_g = icon.create(
                npo_g,
                setName("%s_%s" % (lowerCtlNames[i], ctlName)),
                gt,
                icon=icon_shape,
                w=wd,
                d=wd,
                ro=datatypes.Vector(1.57079633, 0, 0),
                po=datatypes.Vector(0, 0, offset),
                color=color,
            )
            # define the ctl_param to recive the ctl configuration
            ctl_param = ctl_g
            ghost_ctl.append(ctl_g)
            # connect local SRT
            rigbits.connectLocalTransform([ctl_g, ctl])
        else:
            ctl = icon.create(
                npo,
                setName("%s_%s" % (lowerCtlNames[i], ctlName)),
                t,
                icon=icon_shape,
                w=wd,
                d=wd,
                ro=datatypes.Vector(1.57079633, 0, 0),
                po=datatypes.Vector(0, 0, offset),
                color=color,
            )
            # define the ctl_param to recive the ctl configuration
            ctl_param = ctl
        attribute.addAttribute(ctl_param, "isCtl", "bool", keyable=False)
        attribute.add_mirror_config_channels(ctl_param)

        lowControls.append(ctl)
        if len(ctlName.split("_")) == 2 and ctlName.split("_")[-1] == "ghost":
            pass
        else:
            pm.sets(ctlSet, add=ctl_param)
        attribute.setKeyableAttributes(ctl_param, params)
        # mirror behaviout on R side controls
        # if side == "R":
        #     npoBase.attr("ry").set(180)
        #     npoBase.attr("sz").set(-1)
    for lctl in reversed(lowControls[1:]):
        node.add_controller_tag(lctl, over_npo)
    lowControls.append(upControls[-1])

    # adding parent constraints to odd controls
    for i, ctl in enumerate(lowControls):
        if utils.is_odd(i):
            cns_node = pm.parentConstraint(
                lowControls[i - 1],
                lowControls[i + 1],
                ctl.getParent(),
                mo=True,
            )
            # Make the constraint "noFlip"
            cns_node.interpType.set(0)

    # adding parent constraint ghost controls
    cns_node = pm.parentConstraint(ghost_ctl[4],
                                   upControls[0],
                                   ghost_ctl[3].getParent(),
                                   mo=True)
    cns_node.interpType.set(0)
    cns_node = pm.parentConstraint(ghost_ctl[4],
                                   upControls[-1],
                                   ghost_ctl[5].getParent(),
                                   mo=True)
    cns_node.interpType.set(0)
    ##########################################
    # OPERATORS
    ##########################################
    # Connecting control crvs with controls
    applyop.gear_curvecns_op(upCtl_crv, upControls)
    applyop.gear_curvecns_op(lowCtl_crv, lowControls)

    # adding wires
    w1 = pm.wire(up_crv, w=upDriver_crv)[0]
    w2 = pm.wire(low_crv, w=lowDriver_crv)[0]

    w3 = pm.wire(upProfile_target_crv, w=upCtl_crv)[0]
    w4 = pm.wire(lowProfile_target_crv, w=lowCtl_crv)[0]

    if z_up:
        trigger_axis = "tz"
    else:
        trigger_axis = "ty"

    # connect blink driver
    pm.pointConstraint(low_ctl, blink_driver, mo=False)
    rest_val = blink_driver.attr(trigger_axis).get()

    up_div_node = node.createDivNode(up_ctl.attr(trigger_axis), rest_val)
    low_div_node = node.createDivNode(low_ctl.attr(trigger_axis),
                                      rest_val * -1)

    # contact driver
    minus_node = node.createPlusMinusAverage1D(
        [rest_val, blink_driver.attr(trigger_axis)], operation=2)
    contact_div_node = node.createDivNode(minus_node.output1D, rest_val)

    # wire tension
    for w in [w1, w2, w3, w4]:
        w.dropoffDistance[0].set(100)

    # TODO: what is the best solution?
    # trigger using proximity
    # remap_node = pm.createNode("remapValue")
    # contact_div_node.outputX >> remap_node.inputValue
    # remap_node.value[0].value_Interp.set(2)
    # remap_node.inputMin.set(0.995)
    # reverse_node = node.createReverseNode(remap_node.outColorR)
    # for w in [w1, w2]:
    #     reverse_node.outputX >> w.scale[0]

    # trigger at starting movement for up and low
    # up
    remap_node = pm.createNode("remapValue")
    up_ctl.attr(trigger_axis) >> remap_node.inputValue
    remap_node.value[0].value_Interp.set(2)
    remap_node.inputMax.set(rest_val / 8)
    reverse_node = node.createReverseNode(remap_node.outColorR)
    reverse_node.outputX >> w1.scale[0]
    # low
    remap_node = pm.createNode("remapValue")
    low_ctl.attr(trigger_axis) >> remap_node.inputValue
    remap_node.value[0].value_Interp.set(2)
    remap_node.inputMin.set((rest_val / 8) * -1)
    remap_node.outColorR >> w2.scale[0]

    # mid position drivers blendshapes
    bs_midUpDrive = pm.blendShape(
        lowRest_target_crv,
        upProfile_target_crv,
        midUpDriver_crv,
        n="midUpDriver_blendShape",
    )

    bs_midLowDrive = pm.blendShape(
        upRest_target_crv,
        lowProfile_target_crv,
        midLowDriver_crv,
        n="midlowDriver_blendShape",
    )

    bs_closeTarget = pm.blendShape(
        midUpDriver_crv,
        midLowDriver_crv,
        closeTarget_crv,
        n="closeTarget_blendShape",
    )

    pm.connectAttr(
        up_div_node.outputX,
        bs_midUpDrive[0].attr(lowRest_target_crv.name()),
    )

    pm.connectAttr(
        low_div_node.outputX,
        bs_midLowDrive[0].attr(upRest_target_crv.name()),
    )

    pm.setAttr(bs_closeTarget[0].attr(midUpDriver_crv.name()), 0.5)
    pm.setAttr(bs_closeTarget[0].attr(midLowDriver_crv.name()), 0.5)

    # Main crv drivers
    bs_upBlink = pm.blendShape(
        lowRest_target_crv,
        closeTarget_crv,
        upProfile_target_crv,
        upDriver_crv,
        n="upBlink_blendShape",
    )
    bs_lowBlink = pm.blendShape(
        upRest_target_crv,
        closeTarget_crv,
        lowProfile_target_crv,
        lowDriver_crv,
        n="lowBlink_blendShape",
    )

    # blink contact connections
    cond_node_up = node.createConditionNode(contact_div_node.outputX, 1, 3, 0,
                                            up_div_node.outputX)
    pm.connectAttr(
        cond_node_up.outColorR,
        bs_upBlink[0].attr(lowRest_target_crv.name()),
    )

    cond_node_low = node.createConditionNode(contact_div_node.outputX, 1, 3, 0,
                                             low_div_node.outputX)
    pm.connectAttr(
        cond_node_low.outColorR,
        bs_lowBlink[0].attr(upRest_target_crv.name()),
    )

    cond_node_close = node.createConditionNode(contact_div_node.outputX, 1, 2,
                                               1, 0)
    cond_node_close.colorIfFalseR.set(0)
    pm.connectAttr(
        cond_node_close.outColorR,
        bs_upBlink[0].attr(closeTarget_crv.name()),
    )

    pm.connectAttr(
        cond_node_close.outColorR,
        bs_lowBlink[0].attr(closeTarget_crv.name()),
    )

    pm.setAttr(bs_upBlink[0].attr(upProfile_target_crv.name()), 1)
    pm.setAttr(bs_lowBlink[0].attr(lowProfile_target_crv.name()), 1)

    # joints root
    jnt_root = primitive.addTransformFromPos(eye_root,
                                             setName("joints"),
                                             pos=bboxCenter)
    if deformers_group:
        deformers_group = pm.PyNode(deformers_group)
        pm.parentConstraint(eye_root, jnt_root, mo=True)
        pm.scaleConstraint(eye_root, jnt_root, mo=True)
        deformers_group.addChild(jnt_root)

    # head joint
    if headJnt:
        try:
            headJnt = pm.PyNode(headJnt)
            jnt_base = headJnt
        except pm.MayaNodeError:
            pm.displayWarning("Aborted can not find %s " % headJnt)
            return
    else:
        # Eye root
        jnt_base = jnt_root

    eyeTargets_root = primitive.addTransform(eye_root, setName("targets"))

    eyeCenter_jnt = rigbits.addJnt(arrow_ctl,
                                   jnt_base,
                                   grp=defset,
                                   jntName=setName("center_jnt"))

    # Upper Eyelid joints ##################################################

    cvs = up_crv.getCVs(space="world")
    upCrv_info = node.createCurveInfoNode(up_crv)

    # aim constrain targets and joints
    upperEyelid_aimTargets = []
    upperEyelid_jnt = []
    upperEyelid_jntRoot = []

    if z_up:
        axis = "zy"
        wupVector = [0, 0, 1]
    else:
        axis = "-yz"
        wupVector = [0, 1, 0]

    for i, cv in enumerate(cvs):
        if i % everyNVertex:
            continue

        # aim targets
        trn = primitive.addTransformFromPos(eyeTargets_root,
                                            setName("upEyelid_aimTarget", i),
                                            pos=cv)
        upperEyelid_aimTargets.append(trn)
        # connecting positions with crv
        pm.connectAttr(upCrv_info + ".controlPoints[%s]" % str(i),
                       trn.attr("translate"))

        # joints
        jntRoot = primitive.addJointFromPos(jnt_root,
                                            setName("upEyelid_jnt_base", i),
                                            pos=bboxCenter)
        jntRoot.attr("radius").set(0.08)
        jntRoot.attr("visibility").set(False)
        upperEyelid_jntRoot.append(jntRoot)
        applyop.aimCns(jntRoot,
                       trn,
                       axis=axis,
                       wupObject=jnt_root,
                       wupVector=wupVector)

        jnt_ref = primitive.addJointFromPos(jntRoot,
                                            setName("upEyelid_jnt_ref", i),
                                            pos=cv)
        jnt_ref.attr("radius").set(0.08)
        jnt_ref.attr("visibility").set(False)

        jnt = rigbits.addJnt(jnt_ref,
                             jnt_base,
                             grp=defset,
                             jntName=setName("upEyelid_jnt", i))
        upperEyelid_jnt.append(jnt)

    # Lower Eyelid joints ##################################################

    cvs = low_crv.getCVs(space="world")
    lowCrv_info = node.createCurveInfoNode(low_crv)

    # aim constrain targets and joints
    lowerEyelid_aimTargets = []
    lowerEyelid_jnt = []
    lowerEyelid_jntRoot = []

    for i, cv in enumerate(cvs):
        if i in [0, len(cvs) - 1]:
            continue

        if i % everyNVertex:
            continue

        # aim targets
        trn = primitive.addTransformFromPos(eyeTargets_root,
                                            setName("lowEyelid_aimTarget", i),
                                            pos=cv)
        lowerEyelid_aimTargets.append(trn)
        # connecting positions with crv
        pm.connectAttr(lowCrv_info + ".controlPoints[%s]" % str(i),
                       trn.attr("translate"))

        # joints
        jntRoot = primitive.addJointFromPos(jnt_root,
                                            setName("lowEyelid_base", i),
                                            pos=bboxCenter)
        jntRoot.attr("radius").set(0.08)
        jntRoot.attr("visibility").set(False)
        lowerEyelid_jntRoot.append(jntRoot)
        applyop.aimCns(jntRoot,
                       trn,
                       axis=axis,
                       wupObject=jnt_root,
                       wupVector=wupVector)

        jnt_ref = primitive.addJointFromPos(jntRoot,
                                            setName("lowEyelid_jnt_ref", i),
                                            pos=cv)
        jnt_ref.attr("radius").set(0.08)
        jnt_ref.attr("visibility").set(False)

        jnt = rigbits.addJnt(jnt_ref,
                             jnt_base,
                             grp=defset,
                             jntName=setName("lowEyelid_jnt", i))
        lowerEyelid_jnt.append(jnt)

    # Adding channels for eye tracking
    upVTracking_att = attribute.addAttribute(up_ctl,
                                             "vTracking",
                                             "float",
                                             upperVTrack,
                                             minValue=0)
    upHTracking_att = attribute.addAttribute(up_ctl,
                                             "hTracking",
                                             "float",
                                             upperHTrack,
                                             minValue=0)

    lowVTracking_att = attribute.addAttribute(low_ctl,
                                              "vTracking",
                                              "float",
                                              lowerVTrack,
                                              minValue=0)
    lowHTracking_att = attribute.addAttribute(low_ctl,
                                              "hTracking",
                                              "float",
                                              lowerHTrack,
                                              minValue=0)

    # vertical tracking connect
    up_mult_node = node.createMulNode(upVTracking_att,
                                      aimTrigger_ref.attr("ty"))
    low_mult_node = node.createMulNode(lowVTracking_att,
                                       aimTrigger_ref.attr("ty"))
    # remap to use the low or the up eyelid as driver contact base on
    # the eyetrack trigger direction
    uT_remap_node = pm.createNode("remapValue")
    aimTrigger_ref.attr("ty") >> uT_remap_node.inputValue
    uT_remap_node.inputMax.set(0.1)
    uT_remap_node.inputMin.set(-0.1)
    up_mult_node.outputX >> uT_remap_node.outputMax
    low_mult_node.outputX >> uT_remap_node.outputMin
    # up
    u_remap_node = pm.createNode("remapValue")
    contact_div_node.outputX >> u_remap_node.inputValue
    u_remap_node.value[0].value_Interp.set(2)
    u_remap_node.inputMin.set(0.9)
    up_mult_node.outputX >> u_remap_node.outputMin
    uT_remap_node.outColorR >> u_remap_node.outputMax

    # low
    l_remap_node = pm.createNode("remapValue")
    contact_div_node.outputX >> l_remap_node.inputValue
    l_remap_node.value[0].value_Interp.set(2)
    l_remap_node.inputMin.set(0.9)
    low_mult_node.outputX >> l_remap_node.outputMin
    uT_remap_node.outColorR >> l_remap_node.outputMax

    # up connect and turn down to low when contact
    pm.connectAttr(u_remap_node.outColorR, trackLvl[0].attr("ty"))

    pm.connectAttr(l_remap_node.outColorR, trackLvl[1].attr("ty"))

    # horizontal tracking connect
    mult_node = node.createMulNode(upHTracking_att, aimTrigger_ref.attr("tx"))
    # Correct right side horizontal tracking
    # if side == "R":
    #     mult_node = node.createMulNode(mult_node.attr("outputX"), -1)
    pm.connectAttr(mult_node + ".outputX", trackLvl[0].attr("tx"))

    mult_node = node.createMulNode(lowHTracking_att, aimTrigger_ref.attr("tx"))
    # Correct right side horizontal tracking
    # if side == "R":
    #     mult_node = node.createMulNode(mult_node.attr("outputX"), -1)
    pm.connectAttr(mult_node + ".outputX", trackLvl[1].attr("tx"))

    # adding channels for corner tracking
    # track_corner_lvl
    for i, ctl in enumerate(corner_ctl):
        VTracking_att = attribute.addAttribute(ctl,
                                               "vTracking",
                                               "float",
                                               0.1,
                                               minValue=0)
        if z_up:
            mult_node = node.createMulNode(VTracking_att, up_ctl.tz)
            mult_node2 = node.createMulNode(VTracking_att, low_ctl.tz)
            plus_node = node.createPlusMinusAverage1D(
                [mult_node.outputX, mult_node2.outputX])

            mult_node3 = node.createMulNode(plus_node.output1D, -1)
            pm.connectAttr(mult_node3.outputX, track_corner_lvl[i].attr("ty"))
        else:
            mult_node = node.createMulNode(VTracking_att, up_ctl.ty)
            mult_node2 = node.createMulNode(VTracking_att, low_ctl.ty)
            plus_node = node.createPlusMinusAverage1D(
                [mult_node.outputX, mult_node2.outputX])

            pm.connectAttr(plus_node.output1D, track_corner_lvl[i].attr("ty"))

    ###########################################
    # Reparenting
    ###########################################
    if parent_node:
        try:
            if isinstance(parent_node, string_types):
                parent_node = pm.PyNode(parent_node)
            parent_node.addChild(eye_root)
        except pm.MayaNodeError:
            pm.displayWarning("The eye rig can not be parent to: %s. Maybe "
                              "this object doesn't exist." % parent_node)

    ###########################################
    # Auto Skinning
    ###########################################
    if doSkin:
        # eyelid vertex rows
        totalLoops = rigidLoops + falloffLoops
        vertexLoopList = meshNavigation.getConcentricVertexLoop(
            vertexList, totalLoops)
        vertexRowList = meshNavigation.getVertexRowsFromLoops(vertexLoopList)

        # we set the first value 100% for the first initial loop
        skinPercList = [1.0]
        # we expect to have a regular grid topology
        for r in range(rigidLoops):
            for rr in range(2):
                skinPercList.append(1.0)
        increment = 1.0 / float(falloffLoops)
        # we invert to smooth out from 100 to 0
        inv = 1.0 - increment
        for r in range(falloffLoops):
            for rr in range(2):
                if inv < 0.0:
                    inv = 0.0
                skinPercList.append(inv)
            inv -= increment

        # this loop add an extra 0.0 indices to avoid errors
        for r in range(10):
            for rr in range(2):
                skinPercList.append(0.0)

        # base skin
        geo = pm.listRelatives(edgeLoopList[0], parent=True)[0]
        # Check if the object has a skinCluster
        objName = pm.listRelatives(geo, parent=True)[0]

        skinCluster = skin.getSkinCluster(objName)
        if not skinCluster:
            skinCluster = pm.skinCluster(headJnt,
                                         geo,
                                         tsb=True,
                                         nw=2,
                                         n="skinClsEyelid")

        eyelidJoints = upperEyelid_jnt + lowerEyelid_jnt
        pm.progressWindow(title="Auto skinning process",
                          progress=0,
                          max=len(eyelidJoints))
        firstBoundary = False
        for jnt in eyelidJoints:
            pm.progressWindow(e=True, step=1, status="\nSkinning %s" % jnt)
            skinCluster.addInfluence(jnt, weight=0)
            v = meshNavigation.getClosestVertexFromTransform(geo, jnt)

            for row in vertexRowList:

                if v in row:
                    it = 0  # iterator
                    inc = 1  # increment
                    for i, rv in enumerate(row):
                        try:
                            perc = skinPercList[it]
                            t_val = [(jnt, perc), (headJnt, 1.0 - perc)]
                            pm.skinPercent(skinCluster,
                                           rv,
                                           transformValue=t_val)
                            if rv.isOnBoundary():
                                # we need to compare with the first boundary
                                # to check if the row have inverted direction
                                # and offset the value
                                if not firstBoundary:
                                    firstBoundary = True
                                    firstBoundaryValue = it

                                else:
                                    if it < firstBoundaryValue:
                                        it -= 1
                                    elif it > firstBoundaryValue:
                                        it += 1
                                inc = 2
                        except IndexError:
                            continue

                        it = it + inc
        pm.progressWindow(e=True, endProgress=True)

        # Eye Mesh skinning
        skinCluster = skin.getSkinCluster(eyeMesh)
        if not skinCluster:
            skinCluster = pm.skinCluster(eyeCenter_jnt,
                                         eyeMesh,
                                         tsb=True,
                                         nw=1,
                                         n="skinClsEye")