Blend Shapes: Add Target, Sculpt, Flip, Mirror, Rename, Duplicate


Maya’s blendShape node got a big revamp in Maya 2016 Extension 2 with the introduction of the Shape Editor.
It’s not necessary anymore to keep external target shape meshes and to mirror, flip or manage them manually.

These are some code snippets that help me manage the new blendShape workflow (last updated for Maya 2018).
Included are:

  • Add a blendShape node

  • Add a target shape without external mesh

  • Enter sculpt mode

  • Exit sculpt mode

  • Flip target

  • Mirror target

  • Create external mesh from target (e.g. to give to modeler)

  • Rename target on a blendShape node

from maya import cmds
base_shape = cmds.polySphere(n='C_baseShape_PLY', ch=False)[0]

# add blendShape
bls = cmds.blendShape(base_shape, frontOfChain=True, n='C_baseShape_BLS')[0]

# add target
last_used_index = cmds.blendShape(base_shape, q=True, weightCount=True)
new_target_index = 0 if last_used_index == 0 else last_used_index - 1
target_name = 'C_eyebrowUp_PLY'
# the only way to add an internal target is to add a physical mesh and then delete it
temp_duplicate = cmds.duplicate(base_shape, n=target_name)[0]
cmds.blendShape(bls, e=True, target=(base_shape, new_target_index, target_name, 1.0))
# in case duplicated base shape had deformations on it, 
# we reset the new target (0=base shape index)
cmds.blendShape(bls, e=True, resetTargetDelta=(0, new_target_index))

# enter sculpt target mode
cmds.blendShape(bls, e=True, weight=(new_target_index, 1.0))
# or use the target name: cmds.setAttr('%s.%s' % (bls, target_name), 1.0)
cmds.sculptTarget(bls, e=True, target=new_target_index)

# sculpt, sculpt, sculpt

# exit sculpt target mode
cmds.sculptTarget(bls, e=True, target=-1)
cmds.blendShape(bls, e=True, weight=(new_target_index, 0.0))

# flip target
cmds.blendShape(bls, e=True,
    flipTarget=[(0, new_target_index)], # list of base and target pairs (0=base shape index)
    mirrorDirection=0, # 0=negative,1=positive
    symmetrySpace=1, # 0=topological, 1=object, 2=UV
    symmetryAxis='x', # for object symmetrySpace

# mirror target
cmds.blendShape(bls, e=True,
    mirrorTarget=[(0, new_target_index)], # list of base and target pairs (0=base shape index)
    mirrorDirection=0, # 0=negative,1=positive
    symmetrySpace=1, # 0=topological, 1=object, 2=UV
    symmetryAxis='x', # for object symmetrySpace

# duplicate target as external mesh (no live connection to blendShape node)
duplicated_target_name = cmds.sculptTarget(bls, e=True, 

def rename_blendshape_target(bls, old_alias, new_alias):
    rename_blendshape_target('C_baseShape_BLS', 'C_eyebrowUp_PLY', 'C_eyebrowDown_PLY')
    all_aliases = cmds.aliasAttr(bls, q=True) 
    # format: ['alias0', 'weight[0]', 'alias1', 'weight[1]']
    if not old_alias in all_aliases:
        raise ValueError(
            "BlendShape node '{bls}' doesn't have an alias '{old_alias}'".format(**locals()))
    old_alias_attr_index = all_aliases.index(old_alias) + 1
    old_alias_attr = all_aliases[old_alias_attr_index]
    cmds.aliasAttr(new_alias, '{bls}.{old_alias_attr}'.format(**locals()))