tsStickyLips tool

This tool will let you easily create a sticky lips setup for your character. The setup created is based on a wire deformer.


1. Download the script from this link: tsStickyLips.rar;

2. Copy file tsStickyLips.pyc into your maya scripts/ folder;

3. From the script editor, in a python tab type:

import tsStickyLips



As the sticky lips deformation lies on top of other deformations, this should be your very last step in facial rigging.

1. Select top edges for the uplip and press ‘<<<’;

2.  Select top edges for the bottomlip and press ‘<<<’;

3. Press ‘Create stickyLips’ button.

The script will create a copy of the geometry with sticky lips setup. You can hide the previous geo and go rendering with this copy.


Optional parameters:

The tool provides automatically on weighting the wire deformer influence areas. Two optional parameters can be tweaked to change how the weighting is done:

- Selection growth: Grows vertex selection before setting weight influence to 1;

- Smoothness: How many times the weighting should be smoothed.


Here’s the source code of the main procedure for the tech guys:

def createStyckyLips(top_edges, bottom_edges, selection_growth = 2, smoothing=8):
 base_mesh = top_edges[0].split(".")[0]

 # Create curve on top edge sel on duplicated mesh
 top_curve = cmds.polyToCurve(form=2, degree=1)[0]
 top_curve_shape = cmds.listRelatives(top_curve, c=1)[0]

 # Create curve on bottom edge sel on duplicated mesh
 bottom_curve = cmds.polyToCurve(form=2, degree=1)[0]
 bottom_curve_shape = cmds.listRelatives(bottom_curve, c=1)[0]

 # Create wire average curve
 avg_node = cmds.createNode("avgCurves")
 cmds.setAttr(avg_node + ".automaticWeight", 0)
 cmds.setAttr(avg_node + ".automaticWeight", 0)
 avg_curve = cmds.duplicate(top_curve)[0]
 avg_curve_shape = cmds.listRelatives(avg_curve, c=1)[0]
 cmds.connectAttr(top_curve_shape + ".worldSpace[0]", avg_node + ".inputCurve1", force=1)
 cmds.connectAttr(bottom_curve_shape + ".worldSpace[0]", avg_node + ".inputCurve2", force=1)
 cmds.connectAttr(avg_node + ".outputCurve", avg_curve_shape + ".create", force=1)

 #Create duplicate mesh with inputs
 dup_mesh = mel.eval("polyDuplicateAndConnect;")[0]
 dup_top_edges = [x.replace(base_mesh, dup_mesh) for x in top_edges]
 dup_bottom_edges = [x.replace(base_mesh, dup_mesh) for x in bottom_edges]

 # Create wire deformer on duplicate mesh
 wire_deformer = mel.eval("wire -gw false -en 1.000000 -ce 0.000000 -li 0.000000 -w " + avg_curve + " " + dup_mesh +";")[0]
 base_wire = avg_curve + "BaseWire"
 base_wire_shape = cmds.listRelatives(base_wire, c=1)[0]
 cmds.connectAttr(avg_node + ".outputCurve", base_wire_shape + ".create", force=1)

 # Set wire deformer params
 cmds.setAttr( wire_deformer + ".scale[0]", 0)
 cmds.setAttr( wire_deformer + ".envelope", 1.2)
 editAttrs(wire_deformer, ["ce","te","li","ro","sc[0]"], l=1, k=0, cb=0)

 #Set weights

 #Zero all weights
 mel.eval("artAttrToolScript 4 \"" + wire_deformer +"\";")
 mel.eval("artAttrPaintOperation artAttrCtx Replace;")
 mel.eval("artAttrCtx -e -value 0 `currentCtx`;")
 mel.eval("artAttrCtx -e -clear `currentCtx`;")

 #Select vertices
 mel.eval("changeSelectMode -component;")
 mel.eval("hilite -r " + dup_mesh + " ;")
 mel.eval("setComponentPickMask \"Line\" true;")
 cmds.select(dup_top_edges, dup_bottom_edges)

 for i in range(selection_growth):

 #Set weights for region to 1
 mel.eval("artAttrValues artAttrContext;")

 mel.eval("artAttrToolScript 4 \"" + wire_deformer +"\";")
 mel.eval("artAttrPaintOperation artAttrCtx Replace;")
 mel.eval("artAttrCtx -e -value 1 `currentCtx`;")
 mel.eval("artAttrCtx -e -clear `currentCtx`;")

 #Smooth n times
 mel.eval("artAttrValues artAttrContext;")
 mel.eval("artAttrPaintOperation artAttrCtx Smooth;")

 for i in range(smoothing):
 mel.eval("artAttrCtx -e -clear `currentCtx`;")

 mel.eval("changeSelectMode -object;")

 # Group,rename all objects
 main_grp = cmds.group(em=1, w=1, n=resolveName("GRP_sticky"))
 cmds.setAttr(main_grp + ".visibility", 0)
 editAttrs(main_grp, ["tx","ty","tz","rx","ry","rz","sx","sy","sz"], l=1, k=0, cb=0)

 top_curve = cmds.rename(top_curve, resolveName("CRV_sticky_top"))
 bottom_curve = cmds.rename(bottom_curve, resolveName("CRV_sticky_bottom"))
 avg_curve = cmds.rename(avg_curve, resolveName("CRV_wire"))
 base_wire = cmds.rename(base_wire, resolveName(avg_curve + "BaseWire"))

 cmds.parent(top_curve, bottom_curve, avg_curve, base_wire, main_grp)
 if cmds.listRelatives(dup_mesh, p=1):
 cmds.parent(dup_mesh, w=1)

 wire_deformer = cmds.rename(wire_deformer, resolveName("stickyWire"))

Have fun!