Zoom inFig. 1: Flat eyeballs.
Fig. 1: Flat eyeballs.

Rigging a character with flat eyes

20 February 2008

Zoom inFig. 2: a: Incorrect tracking. b: Correct tracking.
Fig. 2: a: Incorrect tracking. b: Correct tracking.

Sometimes there's just not enough room in your character's head for round eyes. Maybe it has a small head with big eyes, or a big mouth. Big eyeballs might peek through other parts of the model; small eyeballs would be too round and make your character appear bug-eyed. A simple solution is to use small eyeballs and squash them flat on one axis (Fig. 1) - but how do you make them track an object? You can't just add a tracking constraint or the eyes will rotate to have the flat side facing the target (Fig. 2).

This tutorial shows how to use parenting and constraints to make flat eyes track a target.


  1. Blender version 2.46 or above.
    Older versions of Blender can't evaluate constraints in local space. Instead you can use this script, but it doesn't work when rendering.
  2. A character with flat eyes.
    Follow along with this example scene. Then you can apply it to your own characters.


First, back up your work. Then set up the following hierarchy.

Zoom inFig. 3: Eye_R.RefSpace.
Fig. 3: Eye_R.RefSpace.


This object is used to find the rotation of the Tracker (below).

  1. Create an Empty and name it Eye_R.RefSpace.
  2. In the Editing buttons (F9), change the Empty Display Type to Circle.
  3. Copy the location and rotation (not size) of Eye_R: Select Eye_R.RefSpace then Eye_R, and press Ctrl-C. Choose 'Location', then repeat to copy the rotation.
  4. Parent Eye_R.RefSpace to Head: Select Eye_R.RefSpace then Head, press Ctrl-P, and choose 'Make Parent'.

You should now have a circle control in the same position as Eye_R (Fig. 3).

Zoom inFig. 4: Eye_R.Tracker.
Fig. 4: Eye_R.Tracker.


This object tracks the target (EyeFocus).

  1. Create an Empty and name it Eye_R.Tracker.
  2. Parent Eye_R.Tracker to Eye_R.RefSpace.
  3. Clear all transforms of Eye_R.Tracker: select it and press Alt-G (location), Alt-S (scale) and Alt-R (rotation).
  4. Clear the parent inverse transform of Eye_R.Tracker. Select it, press Alt-P and choose 'Clear Parent Inverse.'

Now Eye_R.Tracker should have the same transform as Eye_R.RefSpace, even though its location and rotation are zero (Fig. 4).

Zoom inFig. 5: Eye_R parented to Eye_R.FinalSpace.
Fig. 5: Eye_R parented to Eye_R.FinalSpace.


This object is used to scale Eye_R.

  1. Create an Empty and name it Eye_R.FinalSpace.
  2. Change the Empty Display Type to Cube.
  3. Parent Eye_R.FinalSpace to Eye_R.RefSpace.
  4. Clear all transforms of Eye_R.FinalSpace.
  5. Clear the parent inverse transform of Eye_R.FinalSpace.
  6. Copy the ''size'' of Eye_R.
  7. Parent Eye_R to Eye_R.FinalSpace.

We want the eye's transform to be determined by Eye_R.FinalSpace. The current setup looks OK, but if you check the transform properties of Eye_R you'll see that the location, scale and rotation are all non-zero. To fix that:

  1. Clear all transforms of Eye_R.
  2. Clear its inverse transform.

The location, rotation and scale should now be zero (Fig. 5).

Zoom inFig. 6: Constraints on Eye_R and Eye_R.Tracker.
Fig. 6: Constraints on Eye_R and Eye_R.Tracker.

Now we can create the constraints. We need a Track To constraint in the reference space. Its rotation is then copied to the eye in the squashed coordinate space (FinalSpace).

Track To

  1. Select Eye_R.Tracker. In the Object buttons (F7), click Add Constraint and choose 'Track To'.
  2. In the Target box, enter "EyeFocus".
  3. Set To to "-Y", and Up to "Z". Note: these axes may be different for you, depending on how you modelled your eye.
  4. Leave CSpace as "World Space; World Space".

Copy Rotation

  1. Select Eye_R. Add a Copy Rotation constraint.
  2. In the Target box, enter "Eye_R.Tracker".
  3. Set CSpace to "Local Space; Local Space".

The right eye is now finished (Fig. 6). Duplicate the setup for the left eye.

  1. Select Eye_R.RefSpace, Eye_R.Tracker and Eye_R.FinalSpace.
  2. Duplicate them (Shift-D).
  3. Rename the new objects to be called Eye_L instead of Eye_R. Use the Outliner to make selection easier.
  4. Select Eye_L.RefSpace. In the Transform Properties (press N in the 3D view), change the sign of the X-location (set it to +0.6).
  5. Change the sign of RotZ (set it to +40).
  6. Parent Eye_L to Eye_L.FinalSpace.
  7. Clear the location, rotation, size and parent inverse of Eye_L.
  8. Add a Copy Rotation constraint to Eye_L. Set Target to "Eye_L.Tracker" and the CSpace to be "Local Space; Local Space".

To get sensible transforms, the following channels (at least) should be locked:

These can be locked by pressing the padlock icons in the transform properties (press N in the 3D view).

That's all there is to it! Here's a demo of the completed rig.


Try moving EyeFocus, or rotate Head. The eyes should always look towards EyeFocus, but they'll be squashed on one axis by the FinalSpace objects.

Extra rigging can be added using modifiers (like a lattice), or the whole setup could be done using bones.

To make the tracking more natural, set the influence of the Track To constraints to about 50%. That will prevent the eyes from rotating too far around. But beware of gimbal lock!

Creative Commons LicenseThis work is licensed under a Creative Commons Attribution-Share Alike 2.5 Australia License.