Home Website Youtube GitHub

Can mGear create a vanilla Maya Rig that doesn't need mGear?

Having used Rapid Rig or Advanced Skeleton I realized one of the virtues of using Rapid Rig is that when it is finished setting up the Rig from the guides that the end result is one that does not require the end user/animator to have installed Rapid Rig previously.

Currently I see that when we create mGear rigs that the person who opens the rig MUST have mGear installed in order to use the rig properly.

Rapid Rig basically sets up a rig that in the end uses the generic Maya framework in order to work so no plugins/add ons are requred.

Is there a way to output a rig from mGear that is no longer dependent on mGear.mll files?

I would like to output rigs without having to require the end user/animators having to install mGear in order to use them the same way I use Rapid Rig. That the final rig is using the native Maya framework in order for the rig to work.

Or does mGear always require mGear installed if it is a rig produced with the plug in?


Short answer: not yet

Oh sorry, I didn’t see the feature request. Thanks for the link. :slight_smile:
Good to hear about the goal. Our team really likes mGear but had asked if it could be separated out from the plugin. Thank you again.

1 Like

I’d just like to jump in and say… you don’t really want that.
the reason mGear rigs can’t be opened without mGear solvers being installed is because mGear uses custom solvers for a lot of its modules that are just simply better then the maya vanilla solvers, work faster and generally work in a more predictable way…
today, I don’t see a reason for even the most technophob animators not to install mGear as it’s both free and, in the latest versions, a very simple drag n drop install
those 3 minutes of downloading and dragging it to maya will probably be worth the trouble for your team


I will add as well that all of the animation tools that allow interacting with the rig are part of mGear installation as well so not installing mGear will deprive you of all that greatness :smiley:


I wouldn’t ask that mGear stop or change that it makes a rig that is mGear plugin dependent.

What I was asking is IF it could also as an added feature produce a rig with similar setup style and features that just created a rig that no longer required the plug in was all. I wouldn’t want the mGear specific rig features to go away or anything. Just as a possible checkbox option.

This was a request from Dreamview’s internal pipeline queries.

Thanks for the info and I appreciate the defense of the mGear solver benefits.

I am looking at starting a contract which requires its rigs to use “vanilla Maya,” so no mGear plugins or solvers. I’m completely sold on the iterative workflow of mGear, however, and would love to be able to use it. While we wait for an update from the team, has anyone explored writing a script to strip out any custom mGear nodes and rebuild with Maya nodes?

I understand that we’d lose out on some functionality of custom solvers and interaction methods… but in this case I can live with that if I can output a rig that doesn’t require any custom nodes or plugins.

Yeah, I wrote a script that turns the eyes and lips curves into ribbons. It changes the curve constraint to a nurbs ribbon that is skinned by joints I add at the position of each controller. (You can just loft the existing curves to make the ribbon.)

That way I can use the face rig components without mGear plugins at least.

  • I have not even attempted to remove the IK solvers, or make a custom vanilla Shifter component. That will be a much bigger job.
  • It’s a bit too integrated with my other tools, so this won’t run for you without modification.
  • Eyes is similar.
  • Some parts of this script might also depend on my own custom naming conventions.
  • I haven’t tested this since mGear 3.7.11 when the new matrix constraint plugin was added, so this also might not work anymore! This is just for inspiration:
import pymel.core as pm
from mgear import rigbits
from mgear.core import attribute, primitive, curve

def turn_lips_to_ribbon():
    ''' Turn the lips motion paths into ribbons. '''

    # Create some intial groups
    org = pm.group(em=True, n='lips_ribbon_org')
    face_org = pm.PyNode('face_org')
    joint_org = pm.group(em=True, n='lips_control_joints_org')
    pm.parent(org, face_org)
    pm.parent(joint_org, org)

    upLipCurve = pm.PyNode('lips_C_upCtl_crv')
    lowLipCurve = pm.PyNode('lips_C_lowCtl_crv')

    # Create loft curves
    up1 = pm.duplicate(upLipCurve, n='lips_C_up_crvA')[0]
    up2 = pm.duplicate(upLipCurve, n='lips_C_up_crvA')[0]
    low1 = pm.duplicate(lowLipCurve, n='lips_C_up_crvA')[0]
    low2 = pm.duplicate(lowLipCurve, n='lips_C_up_crvA')[0]
    pm.parent(up1, up2, low1, low2, None)

    # Loft them into ribbons
    upLoft = pm.loft(up1, up2, ch=False, range=True, n='lips_C_up_ribbon')[0]
    lowLoft = pm.loft(low1, low2, ch=False, range=True, n='lips_C_low_ribbon')[0]

    pm.delete(up1, up2, low1, low2)
    pm.parent(upLoft, lowLoft, org)

    # Get the lipRopes for all the remaining joints.
    lipRopes = []
    for each in pm.ls('lips_C0*_*LipRope_jnt', type='joint'):
        ropeNode = each.inputs(type='decomposeMatrix')[0].inputs()[0].inputs()[0]
    upRopes = [rope for rope in lipRopes if 'up' in rope.name()]
    lowRopes = [rope for rope in lipRopes if 'low' in rope.name()]

    # Delete any existing constraints on the ropes
    badConstraints = pm.PyNode('lips_C_rope').getChildren(ad=True, type='constraint')

    # Plot a matrix follicle at the closestPoint for every lipRope transform.
    # Disconnect and constrain or parent the ropes under the follicles.
    def plot_folls(org, ribbon, coll, scaleMeasure):
        oRoot = pm.group(em=True, n=ribbon.name() + '_folls')
        pm.parent(oRoot, org)

        for eachJoint in coll:
            oFoll = create_follicle.pin_to_surface(ribbon, eachJoint, 5, 5)
            oLoc = pm.group(em=True, n=oFoll.getTransform().name() + '_ROOT#')
            oLoc.setTranslation(oFoll.getTransform().getTranslation(space='world'), space='world')
            pm.parent(oLoc, oFoll.getTransform())
            pm.parent(oFoll.getTransform(), oRoot)
            for eachAttr in ['t', 'r', 's', 'tx', 'ty', 'tz', 'rx', 'ry', 'rz', 'sx', 'sy', 'sz']:
            #pm.parentConstraint(oFoll.getTransform(), eachJoint, mo=True)
            #pm.scaleConstraint(oFoll.getTransform(), eachJoint, mo=True)
            pm.parent(eachJoint, oLoc)

    # rig parent, ribbon, list of nodes to plot closest point to.
    plot_folls(org, upLoft, upRopes, pm.PyNode('head_scale_measure'))
    plot_folls(org, lowLoft, lowRopes, pm.PyNode('head_scale_measure'))

    # Create control joints to skin the ribbons to.
    upperLipControls = pm.ls(['lips_R_corner_ctl', 'lips_R_upOuter_ctl', 'lips_R_upInner_ctl', 'lips_C_upper_ctl', 'lips_L_upInner_ctl', 'lips_L_upOuter_ctl', 'lips_L_corner_ctl'])
    lowerLipControls = pm.ls(['lips_R_corner_ctl', 'lips_R_lowOuter_ctl', 'lips_R_lowInner_ctl', 'lips_C_lower_ctl', 'lips_L_lowInner_ctl', 'lips_L_lowOuter_ctl', 'lips_L_corner_ctl'])

    upJoints = []
    for each in upperLipControls:
        if pm.objExists(each.name().replace('_ctl','_ribbon_ctl_jnt')):
            oJoint = pm.PyNode(each.name().replace('_ctl','_ribbon_ctl_jnt'))
            oJoint = pm.joint(n=each.name().replace('_ctl','_ribbon_ctl_jnt'))
            pm.parentConstraint(each, oJoint, mo=False)
            pm.scaleConstraint(each, oJoint, mo=True)
    lowJoints = []
    for each in lowerLipControls:
        if pm.objExists(each.name().replace('_ctl','_ribbon_ctl_jnt')):
            oJoint = pm.PyNode(each.name().replace('_ctl','_ribbon_ctl_jnt'))
            oJoint = pm.joint(n=each.name().replace('_ctl','_ribbon_ctl_jnt'))
            pm.parentConstraint(each, oJoint, mo=False)
            pm.scaleConstraint(each, oJoint, mo=True)
    pm.parent(upJoints, lowJoints, joint_org)

    oSkin = tenave.skin_geometry(upJoints, upLoft, 'upper_lip_ribbon_skinCluster')
    oSkin = tenave.skin_geometry(lowJoints, lowLoft, 'lower_lip_ribbon_skinCluster')

    # Delete all the remaining lip curves, wires and unused lip rope transforms.
    pm.delete(pm.PyNode('lips_C_rope'), pm.PyNode('lips_C_crvs'))

    # Constrain the 2 end joints to the corner lips.
    rightLips = pm.ls(
    leftLips = pm.ls(
    rightLipControl = pm.PyNode('lips_R_corner_ctl')
    leftLipControl = pm.PyNode('lips_L_corner_ctl')
    for each in rightLips:
        pm.orientConstraint(rightLipControl, each.getParent(), mo=True)
    for each in leftLips:
        pm.orientConstraint(leftLipControl, each.getParent(), mo=True)

def remove_mgear_eye_curve_nodes():
    #TODO: Add a check so it only runs over eyes.
    for curveCns in pm.ls(type='mgear_curveCns'):
        inputControls = curveCns.inputs(type='transform')
        outCurve = outCurve = curveCns.outputs(type='nurbsCurve')[0]
        if not 'eye_' in outCurve.name():
        oRoot = outCurve.getParent(2)
        if pm.objExists(oRoot.name().replace('_root','_controlJoints_org')):
            jointRoot = pm.PyNode(oRoot.name().replace('_root','_controlJoints_org'))
            jointRoot = pm.group(em=True, n=oRoot.name().replace('_root','_controlJoints_org'))
        pm.parent(jointRoot, oRoot)
        newControlJoints = []

        # Curve will double transform
        # Delete the history on the curve. Deleting the curveCns causes the right side to flip.
        pm.delete(outCurve, constructionHistory=True)
        for each in inputControls:
            if pm.objExists(each.name().replace('_ctrl','_jnt').replace('_ctl','_jnt')):
                oJoint = pm.PyNode(each.name().replace('_ctrl','_jnt').replace('_ctl','_jnt'))
                oJoint = pm.joint(n=each.name().replace('_ctrl','_jnt').replace('_ctl','_jnt'))
                pm.parentConstraint(each, oJoint, mo=False)
                pm.scaleConstraint(each, oJoint, mo=True)
            pm.parent(oJoint, jointRoot)
        oSkin = tenave.skin_geometry(newControlJoints, outCurve, '{}_skinCluster'.format(outCurve.name()))

Thanks for that, Chris! If I come up with a usable script (eventually) I’ll post it here for everybody. From some initial tests, I’m not sure that it’ll be do-able in the time that I have, however. Here’s hoping the update that was mentioned in the 2nd post comes soon!