IK-Like Orient Rig

A Quick setup Orient Rig / Look At Constraint. There are times it is simpler and far more convenient to animate orientations in a look-at style situation.

Copy the code below and put it in a shelf icon in Maya. Select the object you wish to set up, and hit the button.

Pick your Up and Out axis (the option for reverse axis is there, -X, -Y, -Z) and GO!

# IK Orientation Control
# Created By Jason Dixon. http://internetimagery.com
#
# 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 pymel.core as pmc
import maya.api.OpenMaya as om

def message(text):
    pmc.confirmDialog(t="Uh oh...", m=text)

class Orient(object):
    """ Orient setup using IK-like system """

    AXIS = ("X","Y","Z","-X","-Y","-Z")

    def __init__(s, obj):
        if len(obj) != 1: return message("You must only select one Object")
        s.obj = obj[0]
        name = "ikorientwin"
        if pmc.window(name, ex=True): pmc.deleteUI(name)
        with pmc.window(name, t="IK-Like Orient Constraint") as s.win:
            with pmc.columnLayout(adj=True):
                s.fwd = pmc.optionMenuGrp(l="Forward Axis")
                for ax in s.AXIS: pmc.menuItem(l=ax)
                s.up = pmc.optionMenuGrp(l="Up Axis")
                for ax in s.AXIS: pmc.menuItem(l=ax)
                pmc.button(l="GO!", c=s.build)

    def build(s, *_):
        """ Build Setup """
        err = None
        cmds.undoInfo(openChunk=True)
        try:
            fwd = s.AXIS.index(s.fwd.getValue())
            up = s.AXIS.index(s.up.getValue())
            up, up_dir = (up, 1) if up < 3 else (up - 3, -1)
            fwd, fwd_dir = (fwd, 1) if fwd < 3 else (fwd - 3, -1)
            if up == fwd: return message("The two axis must be different.")
            matrix = tuple(om.MVector(a[:3]) for a in s.obj.getMatrix(ws=True))
            b_box = s.obj.getBoundingBox()
            b_size = (b_box.width(), b_box.height(), b_box.depth())
            cam_pos = om.MVector(pmc.modelEditor(pmc.playblast(ae=True), q=True, cam=True).getTranslation("world"))
            offset = (cam_pos - matrix[3]).length() * 0.1
            fwd_pos = matrix[fwd].normalize() * fwd_dir * (b_size[fwd] * 0.5 + offset) + matrix[3]
            up_pos = matrix[up].normalize() * up_dir * (b_size[up] * 0.5 + offset) + matrix[3]
            def locator(name, pos):
                loc = pmc.spaceLocator(n="%s_%s" % (s.obj, name))
                arrow = pmc.annotate(s.obj, tx="", p=(0,0,0))
                arrow.template.set(1)
                pmc.parent(arrow, loc)
                shape = loc.setPosition(pos)
                for ax in s.AXIS[:3]:
                    pmc.setAttr("%s.localScale%s" % (shape, ax), offset * 0.5)
                return loc
            fwd_loc = locator("forward", fwd_pos)
            up_loc = locator("up", up_pos)
            control = pmc.group(em=True, n="%s_attach" % s.obj)
            pmc.pointConstraint(s.obj, control)
            pmc.aimConstraint(
                fwd_loc.name(),
                control.name(),
                worldUpType="object",
                worldUpObject=up_loc.name()
            )
            pmc.orientConstraint(control, s.obj, mo=True)
            pmc.group(fwd_loc, up_loc, control, n="%s_Orient_IK" % s.obj)
            pmc.select(fwd_loc, r=True)
            pmc.deleteUI(s.win)
        except Exception as err:
            raise
        finally:
            cmds.undoInfo(closeChunk=True)
            if err: cmds.undo()


Orient(pmc.ls(sl=True, type="transform"))
rope_end