Shape Control

Steps

Sometimes rigs get a bit overloaded with controllers. Nurbs curves here and there hiding what is important. The performance. It would be nice to just click somewhere on the mesh and control that section.

To Use

# Use geometry as a Rig Controller.
# Created By Jason Dixon. http://internetimagery.com
#
# Usage: Add code below to a shelf button. Select some polygon faces, and a controller object. Hit the button!
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

import maya.cmds as cmds
import collections
import functools

def unique_name(name):
    working = name
    i = 0
    while cmds.objExists(working):
        i += 1
        working = "%s_%s" % (name, i)
    return working

def main():
    try:
        control = cmds.ls(sl=True, type="transform")
        if len(control) != 1:
            return cmds.warning("Please select a single controller.")
        control = control[0]
        faces = cmds.polyListComponentConversion(cmds.ls(sl=True, type="float3"), tf=True, internal=True)
        if not faces:
            return cmds.warning("Please select a controller and some faces.")
    except RuntimeError:
        return cmds.warning("Please select a controller and some faces.")

    err = cmds.undoInfo(openChunk=True)
    connect = functools.partial(cmds.connectAttr, f=True)
    try:
        # Clear out existing shapes
        control_shapes = cmds.listRelatives(control, c=True, s=True)
        if control_shapes:
            cmds.delete(control_shapes)

        # Map transform to shapes
        mesh_map = collections.defaultdict(list) # Map meshes to faces
        object_map = collections.defaultdict(set) # Map transforms to meshes
        for face in faces:
            mesh = cmds.listRelatives(face, p=True)[0]
            xform = cmds.listRelatives(mesh, p=True)[0]
            mesh_map[mesh].append(face)
            object_map[xform].add(mesh)

        # Create a new mesh and link it to the selected mesh
        for xform, meshes in object_map.iteritems():
            for mesh in meshes:
                new_mesh = cmds.createNode("mesh", n=unique_name("picker_%s" % mesh), p=control, ss=True)
                connect("%s.outMesh" % mesh, "%s.inMesh" % new_mesh)

                # Clear out unneeded faces
                cmds.select([new_mesh + "." + a.split(".")[-1] for a in mesh_map[mesh]], r=True)
                cmds.select("%s.f[:]" % new_mesh, tgl=True)
                cmds.delete()

                # Find Delete node we just created
                delete_node = cmds.listConnections("%s.inMesh" % new_mesh, type="deleteComponent")
                if not delete_node:
                    raise RuntimeError("Deletion Node not found")
                delete_node = delete_node[0]

                # Drop in between Delete node and our Mesh
                geo_xform = cmds.createNode("transformGeometry", n=unique_name("compensate_%s" % mesh), ss=True)
                connect("%s.outputGeometry" % delete_node, "%s.inputGeometry" % geo_xform)
                connect("%s.outputGeometry" % geo_xform, "%s.inMesh" % new_mesh)

                # Zero out any mesh movement
                matrix_multi = cmds.shadingNode("multMatrix", asUtility=True, n=unique_name("zero_%s" % mesh))
                connect("%s.worldMatrix[0]" % xform, "%s.matrixIn[0]" % matrix_multi)
                connect("%s.worldInverseMatrix[0]" % control, "%s.matrixIn[1]" % matrix_multi)
                connect("%s.matrixSum" % matrix_multi, "%s.transform" % geo_xform)

                # Pretify the mesh
                cmds.setAttr("%s.displayBorders" % new_mesh, 1)
                cmds.setAttr("%s.displayEdges" % new_mesh, 1)
                cmds.setAttr("%s.castsShadows" % new_mesh, 0)
                cmds.setAttr("%s.receiveShadows" % new_mesh, 0)
                cmds.setAttr("%s.motionBlur" % new_mesh, 0)
                cmds.setAttr("%s.primaryVisibility" % new_mesh, 0)
                cmds.setAttr("%s.smoothShading" % new_mesh, 0)
                cmds.setAttr("%s.visibleInReflections" % new_mesh, 0)
                cmds.setAttr("%s.visibleInRefractions" % new_mesh, 0)
                cmds.setAttr("%s.doubleSided" % new_mesh, 0)

                # Vanish!
                mat = "invsible_material"
                if not cmds.objExists(mat):
                    mat = cmds.shadingNode("surfaceShader", asShader=True, n=mat)
                    mat_set = cmds.sets(r=True, nss=True, em=True, n=unique_name("%sSG" % mat))
                    cmds.connectAttr("%s.outColor" % mat, "%s.surfaceShader" % mat_set)
                    cmds.setAttr("%s.outTransparency" % mat, 1, 1, 1, type="double3")
                else:
                    mat_set = "%sSG" % mat
                cmds.sets(control, e=True, fe=mat_set)
        cmds.select(control, r=True)
    except Exception as err:
        raise
    finally:
        cmds.undoInfo(closeChunk=True)
        if err:
            cmds.undo()

main()
rope_end