• No results found

Animator.SetLookAtPosition() methods to make characters follow an object with their

In document Unity 5.x Animation Cookbook (Page 166-170)

gaze

Sometimes you need a character to look at an object in the game, for instance, at the camera.

To do so, we can use two methods: Quaternion.LookRotation()

and Animator.SetLookAtPosition(). We will cover both in this recipe (the second one is covered in the There's more… section).

Getting ready

To follow this recipe, you need a character with one Idle animation. You can also go to the Chapter 05 Character actions and expressions\Recipe 04 Using

LookRotation and SetLookAtPosition methods to make characters follow an object with their gaze directory. Open the Example.scene scene there. You will find the HumanoidLookAt and HumanoidIKLookAt game objects there. The first one uses a generic LookAt() method and the second one uses the Animator.SetLookAtPosition() function. To see the effect, play the game, switch to the Scene View, and move the Target game object around (a red shiny sphere).

Characters looking at the Target game object

How to do it…

To make characters follow an object with their gaze, follow these steps:

Import the character into Unity and place it in a scene.

1.

Make sure to create an Animator Controller with at least one animation, or use an 2. existing one.

To use the firstQuaternion.LookRotation() method, create a new script and 3. call it CharacterLookAt.cs.

In that script, we use the void LateUpdate() function to alter bone rotation after 4. all animations are evaluated. In that function, we first check if a publicfloat

weight variable is less than or equal to 0. If so, we don't do anything (we turn off the look at behavior):

if (weight <= 0f) {

return;

}

If that is not true, we calculate our desired lookDirection. This is a vector in 5. which our character should look. We calculate it by subtracting our public

Transform bone position from the public Transform target position. This vector is then damped in time using the SmoothDamp() function. This prevents it from sudden changes. We use a public floatdampTime variable to determine the time in which we smooth the vector out. The dampVelocity vector is class member variable required by the SmoothDamp() function to store the changes in the lookDirection vector between frames:

lookDirection = Vector3.SmoothDamp(lookDirection, target.position - bone.position, ref dampVelocity, dampTime);

Next we check if the angle between our desired lookDirection vector and the 6. character's transform.forward vector is greater than our public float

maxAngle value. If so, we calculate the finalLookVector. This is our character's transform.forward vector, which is rotated toward the

desired lookDirection vector by the maxAngle degrees. This way we create a cone of vision for our character and prevent it from breaking the neck joint. We need to use the MathfDeg2Rad constant to change our maxAngle degrees to radians because the Vector3.RotateTowards() function uses radians instead of degrees. If the angle between lookDirection and transform.forward is less than or equal to maxAngle, we don't alter the lookDirection:

if (Vector3.Angle(lookDirection, transform.forward) >

Finally, we calculate the Quaternion rotation value by using

7. the Quaternion.LookRotation() method and multiplying its result by a public Vector3 additinalRotation value. First we need to turn

this Vector3 into a Quaternion by using the Quaternion.Euler() function.

Multiplying two quaternions is simply adding an additional rotation. We need to use the additionalRotation vector because, in most cases, the head bone's forward axis doesn't match the face of our character. By applying an additional rotation of +90 or -90 degrees in one of the axes (X, Y, or Z), we can make the script work for every rig. After calculating the rotation, we linearly interpolate the current bone.rotation value to our calculated rotation using the weight value. This way we can turn the look at on and off easily:

rotation = Quaternion.LookRotation(finalLookVector) * Quaternion.Euler(additionalRotation);

bone.rotation = Quaternion.Lerp(bone.rotation, rotation, weight);

Save the script and add it to the character.

8.

Drag and drop the head bone of the character to the Bone field in the 9. script's Inspector.

Drag and drop the look at target transform to the Target field in the 10. script's Inspector.

You may need to adjust the Additional Rotation field. Experiment in Play Mode 11. with +90 or -90 values in different axes to find a matching value. Modifying one

axis at a time should be enough.

Move the target transform in Play Mode to see the effect (you can do it in 12. the Scene View).

How it works…

In this recipe, we are using a Quaternion.LookRotation() method that creates a rotation, which works the same way as we would use the Transform.LookAt() function.

It is applied to the head bone's transform. Our character's rig and all its bones are standard transforms in Unity. We can modify their rotation or position as we would with other game objects, but we need to do it in the LateUpdate() function because all the animations have to be evaluated first. We cannot modify any of the bones' transforms in the Update() function because all our modifications would be overwritten by the animations.

The Quaternion.LookRotation() function creates a rotation that makes a transform forward axis point to the desired direction. In most cases, the head bone's forward axis doesn't match the face of the character; thus, we need to apply an additional rotation. To do so, we use the public Vector3 additionalRotation variable.

There's more…

For humanoid characters, we can use the IK approach. To do so, follow these steps:

Make sure to check the IK Pass option in the Animator Controller's layer 1. properties.

Create a new script and call it CharacterLookAtIK.cs.

2.

Create a void OnAnimatorIK(int layerIndex) function in that script. This 3. function is called in the IK Pass after all animations are evaluated.

In that script, we use the SetLookAtPosition() and SetLookAtWeight() 4. functions on the Animator component. We use a public Transform target

variable to set the look at position and a public float weight variable to set the weight of the look at. We also use the Vector3.SmoothDamp() method to damp any sudden changes in the position of our target:

targetPosition = Vector3.SmoothDamp(targetPosition, target.position, ref dampVelocity, dampTime);

anim.SetLookAtPosition(targetPosition);

anim.SetLookAtWeight(weight);

Save the script and assign it to the character.

5.

Assign the Target game object to the Target field in the script's Inspector. Make 6. sure to set the Weight field to 1.

Play the game and move the Target game object to see the result (you can do it in 7. the Scene View).

To turn the look at on and off smoothly, interpolate the weight value in time 8. using the Mathf.Lerp() function.

Action Points – performing an action in a

In document Unity 5.x Animation Cookbook (Page 166-170)