May
Scott’s Famous Eye Rig
Description: This is an advanced eye rig with lots of useful controls that may be handy with working with the eyes during animation. Some of the key features of this rig are:
- Two types of eye controls, Joystick and a “Look At” controller with blending between the two
- A “convergence” control to make the eyes cross inward
- Dynamic parent switching on the “Look At” controller
- Custom scripts that go along with this rig for instant, no blending, switching between the controls and also a instant switching with no blending for changing the parent on the “Look At” control.
The biggest thing about this rig is how easy it is to control where the eyes are looking and having the control to move them in however feel most comfortable.
What you will need for this tutorial
- A copy of Maya (this tutorial was done in version 7)
- This base file to get you started – Maya ASCII
Modes to work in
- In your rotation tool setting, set it to gimbal, this is the true rotation control that will help in rotating one axis at a time properly
- In your translation tool setting, set it to local
Some quick notes before we start
A lot of these steps are similar to the first eye rig tutorial but this has a few new things to improve the functionality and a few minor additions to speed things up. The same basic idea is there from the older tutorial so if you followed that one, then you will see a lot of similar steps.
The same information on the last tutorial applies on the subject of joint orientation. On the eye joints, make sure the XYZ local axes are pointing the same direction as the world axes.
Step 1: Overview of the sample scene and whats inside
The base sample scene is similar to the previous tutorial scene, just added two new joystick type controllers for the convergence of the eyes and one for the blending from the joystick to the look at controller, plus a few other minor things to keep things simple.
The eye geometry on a reference layer so you don’t select or move them. There is a red circle that will move the “neck” joint so you can move around the rest of the rig.
The yellow eye shaped wire controller will be used as our “look at” controller.
Step 2: Setting up the joystick controller
- Create a locator and name it: locEyeJoystickOrient
- Snap the locator the jRightEye joint
- Open the attribute editor for this locator and change the rotation order to: ZXY
- Go into the expression editor and use this expression:
locEyeJoystickOrient.rotateX = ctrlEyeJoystick.translateY * -ctrlEyeJoystick.EyeMoveUpDown;
locEyeJoystickOrient.rotateY = ctrlEyeJoystick.translateX * ctrlEyeJoystick.EyeMoveLeftRight;
What this expression does is rotate the locator up/down and left/right as you move the joystick control. You can change the amount of rotation by changing the values on the joystick attributes: EyeMoveUpDown and EyeMoveLeftRight
Make sure if you do move the joystick control to move it back to center by zeroing out the translateX and Y
Step 3: Setting up the aim constraint for the “look at” controller
- Select the ctrlEyeLookAt control and group it with the default options and name it: gEyeLookAtParentConst
- With the newly created group selected, snap it to the jRightEye joint
- Enter in a good distance to move the control down the Z axis into the channel box, how about, 15
- Select the locEyeJoystickOrient locator and duplicate it with the default options and rename it to: locEyeLookAtOrient
- Now select the ctrlEyeLookAt control and then select the locEyeLookAtOrient locator so both objects are selected in that order ( you may need to use the outliner to select the right objects)
- Go to Constrain -> Aim [option box]
- Change the values to what you see here and then hit “Apply”:

- Select ctrlEyeLookAt and change the rotation order to ZXY
- Now select jRightEye and then select ctrlEyeLookAt
- Back in the Aim Constraint option box, change the “AIM Vector” in the Z column (the last one on the right) from 1 to -1 and hit “Add”
Now the locator is aim constrained to the “look at” control (ctrlEyeLookAt). Now if you move the look at controller, you will see the locator follow it. Also, the “look at” control will not always look at the eye when you move it around just for visual clarity. When finished, zero it back out so it returns to this original position.
Step 4: Connecting to the eye joints
- Select the locator locEyeJoystickOrient and duplicate it again with the default options and rename it to: locEyeOrient
- Now select locEyeJoystickOrient and then select locEyeOrient
- Go to constrain -> orient[option box] and reset the settings (edit -> reset settings)
- Uncheck “All” in the Constraint Axes and check ONLY X and Y
- Press “Apply”
- Now select locEyeLookAtOrient and then select locEyeOrient
- Again, in the orient constraint option box, hit “Apply”
- Now select locEyeOrient and then select jRightEye (joint)
- Back to the orient constraint option box, hit “Apply”
- Now select locEyeOrient and then select jLeftEye (joint)
- Last time, go in the orient constraint box and hit “Add“
- Select locEyeJoystickOrient and duplicate it with the default options and rename it to: locEyePos
- Enter the same number into the channel box what we used before with the gEyeLookAtParentConst group to move it down the Z axis, I mentioned using 15
- Select locEyeOrient and Shift select locEyePos
- Go to constrain -> parent [option box]
- Reset the setting (edit -> reset settings) and hit “Add“
Ok, we have both controls now connected to the eye joints but before its fully functional, we still have to hook up the blending between the controls and also the convergence as well. So if you move any of the controls, make sure you move them back to their default positions.
The locEyePos is how we will find out where the eye is looking for our instant snapping between controls.
Step 5: Connecting the convergence and blend controls
1. Open the expression editor and make a new expression with this:
jRightEye_orientConstraint1.offsetY = ctrlEyeConv.translateX * ctrlEyeConv.convAmount;
jLeftEye_orientConstraint1.offsetY = ctrlEyeConv.translateX * -ctrlEyeConv.convAmount;
2. Now make a new expression and enter this in:
locEyeOrient_orientConstraint1.locEyeJoystickOrientW0 = 1 – ctrlEyeBlend.translateX;
locEyeOrient_orientConstraint1.locEyeLookAtOrientW1 = ctrlEyeBlend.translateX;
Now our convergence and control blending is now fuctional. You can adjust the amount of convergence by changing the number in the convAmount on the ctrlEyeConv control to increase or decrees how much you like. You can test this by grabbing each controls and seeing what it does. Just make sure you put everything back to zero before moving on.
Step 6: Setting the dynamic parenting on the “look at” control
This part is going to be a little more complicated so I will my best in explaining how to wire it up. This demo is only going to be using two parents, the world and the head joint. You can add as many or little parents as you like, but I think two is enough for this tutorial.
- Create a new locator and name it: locELAWorldParent
- With the new locator selected, now also select gEyeLookAtParentConst
- Go to constrain -> parent[option box] and reset the settings and hit “Apply”
- Now select jHead and then select gEyeLookAtParentConst again
- Again in the parent constraint option box, hit “Add”
Now we have our parenting set but now we have to link to the parents so we can change between them, in this next part, we are going to be using a couple condition nodes to control our parents
- Open your hypershade and switch the tab from “Materials” to “Utilities”
- In the hypershade window go to Create -> General Utilities -> Condition
- Rename this condition node to: conELAWorldParent
- Create another condition node and name it: conELAHeadParent
- Select conELAWorldParent and open the attribute editor
- Change the attributes to this:

- Now select conELAHeadParent and open the attribute editor
- Do the same thing for this as the did for the other with the image above but also change the 0 next to “Second Term” to 3 (more information about this later)
- Open the connection editor (window -> general editors -> connection editor)
- Select ctrlEyeLookAt and load it into the outputs section
- Now select and load conELAWorldParent into the inputs section
- In the outputs, scroll down to the bottom and select “Parent”
- In the inputs, click on “First Term“
- Select and load conELAHeadParent in to the inputs side while still having the ctrlEyeLookAt in the ouputs side
- With the “Parent” still selected in the outputs, select on the inputs “First Term” again
- Make sure conELAHeadParent is selected and click the button to load it into the OUTPUTS side of the connection editor
- Select the Parent Constraint connected to gEyeLookAtParentConst, not the group, but the constraint itself, it will be a child under gEyeLookAtParentConst. It may be called gEyeLookAtParentConst_parentConstraint1
- With the constraint selected, load it in to the inputs of the connection editor
- In the Outputs, click the “+” sign next to Out Color and click on “Out Color R“
- On the inputs side, scroll down to the bottom and click on “J Head W1“
- Now select and load conELAWorldParent into the OUTPUTS side of the connection editor while the parent constraint is still loaded into the inputs side
- Same thing as above, click the “+” next to Out Color and click on “Out Color R”
- On the inputs, click on “Loc ELAWorld Parent W0“
- You can now close the connection editor
Do not try to test the parenting right now as we have to do a few more things first before it will work properly.
Basically the condition is either going to turn on or off the parent influence depending on which one is selected on the “look at” controller. Since the “parent” attribute on the “look at” controller is an enum type, the first item has an index of 0 and the next item is 1, and so on, so there are four items in there now, the first is the world (0) and the last is head (3) so that is where the first term connection comes into play.
Told you it was a long step, but you made it!
Step 7: Cleaning up the mess and parenting groups
- Select locEyeJoystickOrient, locEyeLookAtOrient, and locEyeOrient and group them with the name: gEyeOrients
- Snap the PIVOT of gEyeOrients to jHead (using the insert key to move the objects pivot point) Press insert again after moving the pivot
- Select jHead and then select gEyeOrients
- Go to constrain -> parent [option box] and use the default settings and click “Add“
- Select gEyeLookAtParentConst, locEyePos, locELAWorldParent, and gEyeOrients and group them with the name: gEyeRig
That is the end of the set, you may now move the neck control around to move the rig and play with the parent switching from the World to Head parents and also the blending and convergence!
You may now download the completed rig here – Maya ASCII
Taking it one step further
Now that we have the rig fully working, we can now add some special things to gain more control over how this rig works. With the addition of MEL scripts, this setup will aid the animators taking full advantage of the features in this rig.
As I mentioned in the other tutorial, I am not going to lecture about MEL or how to write scripts, but I am going to post what each script does and inside I have commented the lines on how it works. Or you just download them and try them out for yourself after finishing this tutorial.
There are two packs of scripts, one has the built in function of automatically keying the proper controls for you, the other pack doesn’t key anything. So one is useful in trying to animate, the other is good for just testing it out.
Breakdown of included scripts:
- ECS_****.mel – Eye Control Switcher script will switch between the joystick and look at control with no blending or movement in the eyes, just run it every time you want to change controllers.
- ELA_Switch2WorldParent_****.mel – Changes the dynamic parent of the look at control to the world parent with no popping or moving.
- ELA_Switch2HeadParent_****.mel – Changes the dynamic parent of the look at control to the head parent with no popping or moving.
That brings the basic rig, but you can definitely add on to this and rather than using expressions, use utility nodes to keep the performance up on your rigs. I may possibly write a more advanced but similar rig to push it even further and incorporate eyelid tracking. I hope you enjoyed the tutorial and inspired some new ideas with your eye rigs. Comments are welcome if you care to send them to me.