Effortless Eye Movement: Continued


Using Unity Version 2019.4

If you've been following along with the first part of this tutorial series, you should have a basic eye movement and targeting system in place. If not, check it out and meet us back here!

Let's recap what we should have in place:

  • Our character is set up with an eye movement monobehaviour, which uses either eye bone transforms or UV texture offsets.

  • Your character has an eye rig parented to the head transform.

  • Our character has an animator controller that contains a Default state, with no behaviour, and a LookAtTarget state which uses a LookBehaviour script.

The Problem

There are two things we want to do to our eye movement system at this point: 1) Smooth out the transitions to and from a look state, and 2) Extend our system to allow our character to randomly look around.

The approach will differ greatly depending on the method you've chosen, but both will make use of coroutines.

About Coroutines

The Unity Manual does a pretty good job of explaining coroutines:

"[A coroutine] can be used as a way to spread an effect over a period of time...it is also a useful optimization. Many tasks in a game need to be carried out periodically and the most obvious way to do this is to include them in the Update function. However, this function will typically be called many times per second. When a task doesn’t need to be repeated quite so frequently, you can put it in a coroutine to get an update regularly but not every single frame."

Think of a coroutine like a "to do" list. Rather than execute all of your commands in a single frame update like a normal function, a coroutine allows you to go through your list of commands over time, repeat them on a loop until a condition is met, or even wait before executing a subsequent command.

So with that in mind, let's get to the tutorial part of this tutorial.

The Solution

Since this tutorial promises to cover two different ways to tackle eye movement, we'll need to split the tutorial into two parts. Choose the part that's right for you depending on the eye movement system you went with.

Eye bone transforms

The first things we’ll fix up are our transitions to and from looking. You may have noticed that, although the character follows the target fluidly when they’re in the “LookAtTarget” state, they don’t transition smoothly into and out of it. There are a number of ways to do this, but we’ll use the float parameters within animator.SetLookWeight.

There are three things we need to do to make this happen:

1. Add new parameters We need to create new parameters for every float we’re using in the LookAt interface. I’m only using the head weight and eye weight, so I’ll need two. If you’re using the body weight, you’ll want to add a third. Add these float parameters to your animator.

2. Update the animator with clips: We need to create three new animation clips. These clips will only contain the new float parameters just created. I’ve called these three clips “StartLooking”, “StopLooking”, and “Looking”. Drag your “StartLooking” and “StopLooking” clips to the animator controller as new states. Make note of the values you chose in the animator behaviour. That will be your “max” weight. Open the clips and add the new floats from the animator. Then switch from Dopesheet to Curves and edit the two existing keys. In “StartLooking”, my first key will have a value of 0 for both floats. My end key will have a value of 0.35 (for my max eye weight) and 0.15 (for my max head weight). Repeat this for your “StopLooking” clip with the reversed value (max weight to 0) for both floats. You can add or manipulate the keyframes as you see fit to speed up, slow down or ease the transitions and make it look as natural as possible.

The “Looking” clip will be added to any of the states that uses the behaviour. For now, that’s just our “LookAtTarget” state. Click on that state and drag the “Looking” clip to the Motion field. In this new clip, add the floats and just set both keyframes to your max value. Delete your existing transitions. At this point, you are going to ALWAYS transition to your “StartLooking” with the transition condition and then automatically, with no condition, to “LookAtTarget”. Likewise, you will always transition to your “StopLooking” state, with the DefaultEye condition, before automatically transitioning to the DefaultEye state with no condition. Here’s how mine looks:

3. Update your LookBehaviour code Now that your animator is set up, it’s time to go back into our LookBehaviour code. In the OnStateIK call, add new lines for the float parameters you've just added:

NOTE: If you’ve called your parameters something different, just make sure you replace my float names with your own. You could expose the float names as public string parameters if you wish.

Save the code and go back to your scene. Now when you enter playmode you’ll see a smooth transition into and out of targeting.