Home Website Youtube GitHub

Control Mirror Tool

Hey,

Made this tool for mirroring control shapes, which I thought would be good to share:

import pymel.core as pc
import mgear

# Store selection
selection = pc.selected()

# Define mirror direction
left_to_right = True

# Get mirror pairs from all or selection
# This could be better coded without name dependency, maybe something in mGear?
nodes = selection
if not selection:
    nodes = pc.PyNode("rig_controllers_grp").members()

pairs = []
for source in nodes:
    target = None

    if selection:
        if "_L" in source.name():
            target = pc.PyNode(source.name().replace("_L", "_R"))
        
        if "_R" in source.name():
            target = pc.PyNode(source.name().replace("_R", "_L"))

    if left_to_right:
        if "_L" in source.name():
            target = pc.PyNode(source.name().replace("_L", "_R"))
    else:
        if "_R" in source.name():
            target = pc.PyNode(source.name().replace("_R", "_L"))        

    if target:
        pairs.append([source, target])

# Modify control shapes
for source, target in pairs:
    # Copy shapes
    source_copy = pc.duplicate(source)[0]
    mgear.core.attribute.setKeyableAttributes(
        source_copy,
        ["tx", "ty", "tz", "ro", "rx", "ry", "rz", "sx", "sy", "sz"]
    )

    # Delete children except shapes
    for child in source_copy.getChildren():
        if child.nodeType() != "nurbsCurve":
            pc.delete(child)

    # Mirror
    pc.select(clear=True)
    grp = pc.group(world=True)
    pc.parent(source_copy, grp)
    grp.scaleX.set(-1)

    # Reparent, freeze transforms and match color
    pc.parent(source_copy, target)
    pc.makeIdentity(source_copy, apply=True, t=1, r=1, s=1, n=0)
    pc.parent(source_copy, target.getParent())
    mgear.core.curve.set_color(source_copy, mgear.core.curve.get_color(target))

    # Replace shape
    mgear.rigbits.replaceShape(source_copy, [target])

    # Clean up
    pc.delete(grp)
    pc.delete(source_copy)

# Restore selection
pc.select(selection)

You can select a control and the script will find the mirror shape, or just let the script find all left controls and mirror across.
Its a first version of the script, so it’ll probably need some troubleshooting.

3 Likes

Hi @Toke_Stuart_Jepsen

Thank you for sharing it. Here is also another version I am using. Just in case is useful.
I should have share this before. :stuck_out_tongue:
Indeed this version is a modify version that someone shared before (Sorry I can’t recall who is the original author)

import pymel.core as pm
from mgear import core
from mgear import rigbits
from mgear.core import transform

selected = pm.ls(sl=True)

for sControl in selected:
    othSide = core.string.convertRLName(sControl.name())
    if not pm.objExists(othSide):
        continue
    othSide = pm.PyNode(othSide)
    othShape = othSide.getShape()
    othColor = othShape.overrideColor.get()
    null = pm.group(em=True)
    null_local = pm.group(em=True)
    pm.parent(null_local, null)
    transform.matchWorldTransform(sControl, null_local)
    childrenShapes = sControl.getShapes()
    for sh in childrenShapes:
        dupShape = pm.duplicate(sh, addShape=True)
        pm.parent(dupShape, null_local, s=True, r=True)
        [shape.setAttr("overrideColor", othColor) for shape in dupShape]
    null.setAttr("scaleX", -1)
    pm.parent(null_local, othSide)
    pm.makeIdentity(null_local, a=True)
    rigbits.replaceShape(source=null_local, targets=[othSide])
    pm.delete(null)
    pm.delete(null_local)
    
pm.select(selected)
5 Likes

Could this tool be included in the mGear distribution?

Sounds like a good idea to me. I’m currently trying get a development environment up, so I would be able to make a PR.

yep, that should have done long ago :stuck_out_tongue: Thanks for the help