How to make an object look at another object over time?

I have an object that I want to face another object. I used transform.LookAt() and it does that in just 1 frame, but I want to spread it out over time. I was looking into Slerp() but the angle is always off. This is the code I’m using that makes it work in just 1 frame.

transform.rotation = Quaternion.LookRotation(target - transform.position);
transform.eulerAngles = new Vector3(270.0f, transform.eulerAngles.y + 180, 0f);

As I said the above code works for just 1 frame, but I’d like it work over a few seconds. Also it only looks at it on one axis, hence the eularangles set.

Usually you should place the code in Update or in a coroutine, so that the object rotates a little each frame - like this:

public float speed = 2.5f;

void Update(){
    Vector3 dir = target - transform.position;
    dir.y = 0; // keep the direction strictly horizontal
    Quaternion rot = Quaternion.LookRotation(dir);
    // slerp to the desired rotation over time
    transform.rotation = Quaternion.Slerp(transform.rotation, rot, speed * Time.deltaTime);
}

This is the so called “Lerp filter”: the rotation speed is proportional to the angle to be rotated, thus it’s fast at first and slows down when approaching the desired rotation. As a rule of thumb, speed = 5 takes about 1 second to reach 99% of the final angle, 2.5 takes 2 seconds, and so on.

Given examples apply an easing effect as they approach the direction of the target.

The code below MonoBehavior will turn the transform to which it is attached toward at a given target with a consistent speed from start to finish.


using UnityEngine;

public class LookAtBehavior : MonoBehaviour {
	public Transform Target;
	public float TurnSpeed = 50.00F;
	private Transform myTransform;

	public void Start() {
		myTransform = GetComponent<Transform>(); // Cache own Transform component
	}

	public void Update() {
		var targetDirection = Target.position - myTransform.position;
		targetDirection.y = 0.00F; // Lock global y-axis

		var targetRotation = Quaternion.LookRotation(targetDirection);
		var deltaAngle = Quaternion.Angle(myTransform.rotation, targetRotation);

		if (deltaAngle == 0.00F) { // Exit early if no update required
			return;
		}

		myTransform.rotation = Quaternion.Slerp(
			myTransform.rotation,
			targetRotation,
			TurnSpeed * Time.deltaTime / deltaAngle
		);
	}
}