[Unity] Mastering Smooth Movement and Rotation with Lerp and Slerp

Created: 2025-12-10Last updated: 2026-07-13

A beginner-friendly guide to Lerp (linear interpolation) and Slerp (spherical linear interpolation), the essential functions for smooth motion in Unity. Learn why objects slow down near the target (easing out) and when to use MoveTowards / RotateTowards for constant speed, with practical code examples.

You want to move an object, so you write transform.position = targetPosition; — and it instantly teleports to the destination. Every Unity beginner has been there. With direct assignment, both movement and rotation just snap into place, and you never get the smoothness of a professional game.

That smoothness comes from two interpolation functions: Lerp and Slerp. In this article, we'll cover how each one works and when to use which, uncover why objects mysteriously slow down as they approach their target, and show you the right tools for constant-speed motion (MoveTowards / RotateTowards).

Illustration of smooth interpolation: moving smoothly from a start point to an end point by filling in the points along the way

What You'll Learn

  • How Lerp(A, B, t) works and what the interpolation factor t means
  • Why you should use Slerp instead of Lerp for rotation
  • Why objects decelerate as they approach the target ("easing out")
  • MoveTowards / RotateTowards for constant-speed motion

Sponsored

What is Lerp (Linear Interpolation)?

Lerp stands for "Linear Interpolation." It's a calculation that interpolates (fills in) between two values (A and B) along a straight line, based on a specified ratio (t).

Unity provides this function for various types, including Vector3.Lerp, Color.Lerp, and Mathf.Lerp.

Basic function form:

// A: start value, B: end value, t: interpolation factor (0.0f to 1.0f)
result = Lerp(A, B, t);
  • When t = 0.0f, the result is A.
  • When t = 1.0f, the result is B.
  • When t = 0.5f, the result is exactly halfway between A and B.
Diagram of how Lerp works: on the straight line from start point A to end point B, t = 0 gives A, 0.5 gives the midpoint, and 1 gives B

Lerp is most commonly used wherever you need a linear change — moving objects, transitioning colors, or smoothly changing numeric values.

Sponsored

What is Slerp (Spherical Linear Interpolation)?

Slerp stands for "Spherical Linear Interpolation." While Lerp connects two points with a straight line, Slerp interpolates along an arc on a sphere.

Slerp is primarily used with Quaternions — in other words, for object rotation.

Why Does Rotation Need Slerp?

Rotation is a change in angle, so it's natural to interpolate along a circular arc rather than a straight line. If you interpolate rotation with Lerp, the angular velocity becomes uneven partway through, which can make the motion look slightly off. Slerp interpolates evenly along the arc, so turning characters and rotating cameras look smooth.

Comparison of Lerp and Slerp interpolation paths: Lerp connects two points with a straight line, while Slerp interpolates rotation along an arc on a sphere

The Key Differences Between Lerp and Slerp

FeatureLerp (Linear)Slerp (Spherical Linear)
Interpolation pathStraight lineArc on a sphere
Main useVector3 (position), Color, float (numbers)Quaternion (rotation)
Sweeping t from 0 to 1Moves along the line at constant speedRotates along the arc at constant angular velocity
Computational costLightSlightly heavier than Lerp (rotation math)

A Common Beginner Pitfall: Why Does It Slow Down Near the Target?

If you write something like Vector3.Lerp(transform.position, target, 0.1f) inside Update() — moving a fixed fraction of the way from the current position to the target every frame — the object slows down as it approaches the target.

This isn't a property of Lerp itself; it comes from how you use it. Each frame you cover "10% of the remaining distance," so as the remaining distance shrinks, so does each step. The result is fast at first, slow at the end — an effect called easing out.

Comparison of easing out versus constant-speed movement: Lerp moving a fixed fraction of the remaining distance each frame leaves footprints that get closer together as it decelerates, while MoveTowards leaves evenly spaced footprints at constant speed

For something like a follow camera, where you want a natural deceleration, this behavior is actually ideal. But it's the wrong tool when you want constant-speed motion — for that, use MoveTowards, covered below.

Sponsored

Practical Examples

Example 1: Smooth Following with Lerp (Easing Out)

This code smoothly moves an object toward a target. You get a natural deceleration animation — slowing down as it approaches the target — with almost no effort.

// File name: LerpFollow.cs
using UnityEngine;

public class LerpFollow : MonoBehaviour
{
    public Transform target;   // The object to follow

    // Follow strength (higher = catches up faster)
    [Range(0.1f, 10f)]
    public float smoothness = 3f;

    void Update()
    {
        if (target == null) return;

        // Move a fixed fraction of the way from the current position to the target each frame.
        // As the remaining distance shrinks, so does each step — a natural deceleration (easing out).
        transform.position = Vector3.Lerp(
            transform.position,
            target.position,
            smoothness * Time.deltaTime);
    }
}

Note: Using smoothness * Time.deltaTime for t is a very common pattern, but strictly speaking, the deceleration curve varies slightly with frame rate. It's fine for most games, but if you need it to be perfectly consistent, Vector3.SmoothDamp is another option.

Example 2: Use MoveTowards for Constant Speed

When you want to specify a speed, like "move toward the target at 3 meters per second," Vector3.MoveTowards is the right answer. It advances a fixed distance each frame and stops dead when it reaches the target.

// File name: ConstantMove.cs
using UnityEngine;

public class ConstantMove : MonoBehaviour
{
    public Transform target;
    public float speed = 3f; // Movement speed (units per second)

    void Update()
    {
        if (target == null) return;

        // Move exactly speed * Time.deltaTime toward the target each frame (constant speed)
        transform.position = Vector3.MoveTowards(
            transform.position,
            target.position,
            speed * Time.deltaTime);
    }
}

Example 3: Smooth Turning with Slerp

Use Slerp for rotation-following behavior, like an enemy character slowly turning to face the player.

// File name: SlerpLookAt.cs
using UnityEngine;

public class SlerpLookAt : MonoBehaviour
{
    public Transform target;

    [Range(0.1f, 10f)]
    public float rotationSmoothness = 5f;

    void Update()
    {
        if (target == null) return;

        // Compute the target rotation for facing the target
        Vector3 direction = target.position - transform.position;
        Quaternion targetRotation = Quaternion.LookRotation(direction);

        // Smoothly rotate from the current rotation toward the target rotation along the arc.
        // Like Example 1, this pattern also eases out (slows down at the end).
        transform.rotation = Quaternion.Slerp(
            transform.rotation,
            targetRotation,
            rotationSmoothness * Time.deltaTime);
    }
}

If you want constant-speed rotation, use Quaternion.RotateTowards (rotate at N degrees per second) — the rotational counterpart of MoveTowards.

Common Mistake: Manipulating Quaternion Values Directly

Unity manages rotation internally with a mathematical structure called a Quaternion. It holds four values — x, y, z, and w — but you should never modify them directly.

To create rotations, use Quaternion.Euler() (convert from Euler angles) or Quaternion.LookRotation() (build from a direction), and for interpolation, use Slerp / RotateTowards. Stick to this combination and you'll rarely need to think about what's inside a Quaternion.

Hands-On: Comparing Three Ways to Move a Follow Camera

To wrap up, let's put everything into a single experiment. The subject: moving a camera toward a goal position. A camera pan in a top-down ARPG, a follow camera in a 2D platformer, a view switch in a racing game — every genre needs this motion. And even though all three approaches "move toward the same goal," how you build t completely changes the character of the motion.

Here's the key premise: Lerp is not a "smoothing function." It's simply a function that returns the point at ratio t between A and B. What determines the motion is how you construct t each frame. The following script is a lab rig that lets you switch between three approaches in the Inspector and compare them.

// File name: CameraFollowLab.cs
using UnityEngine;

public class CameraFollowLab : MonoBehaviour
{
    public enum Mode { FixedTimeLerp, RatioLerp, SmoothDamp }

    public Transform target;          // The goal to move toward (player or boss position)
    public Mode mode = Mode.RatioLerp;

    [Header("For (1) fixed-time Lerp")]
    public float duration = 2f;       // Always arrive in exactly this many seconds
    private Vector3 startPos;
    private float elapsed;

    [Header("For (2) ratio Lerp")]
    public float smoothness = 3f;

    [Header("For (3) SmoothDamp")]
    public float smoothTime = 0.3f;   // Rough "seconds to catch up"
    private Vector3 velocity;         // Velocity memory. MUST be a field (see failure #3)

    void Start()
    {
        startPos = transform.position;
    }

    void LateUpdate()
    {
        if (target == null) return;
        Vector3 goal = target.position + new Vector3(0f, 0f, -10f);

        switch (mode)
        {
            case Mode.FixedTimeLerp:
                // Build t yourself as "elapsed time / duration". At duration seconds, t = 1 and you always arrive
                elapsed += Time.deltaTime;
                transform.position = Vector3.Lerp(startPos, goal, elapsed / duration);
                break;

            case Mode.RatioLerp:
                // Move a fixed fraction from the current position each frame. Soft, but asymptotic (see below)
                transform.position = Vector3.Lerp(
                    transform.position, goal, smoothness * Time.deltaTime);
                break;

            case Mode.SmoothDamp:
                // Specify "catch up in about smoothTime seconds". Remembers velocity, so even the start is smooth
                transform.position = Vector3.SmoothDamp(
                    transform.position, goal, ref velocity, smoothTime);
                break;
        }
    }
}

Switch between the three modes in Play mode and the difference in character becomes obvious:

  • (1) Fixed-time Lerp: Arrives exactly at duration seconds, dead on. Ideal for "fixed-length" presentation moments like a boss-entrance camera pan or a cutscene
  • (2) Ratio Lerp: Fast out of the gate, softly decelerating at the end. But since it only covers "a fixed fraction of the remaining distance" each frame, in theory it never fully arrives (visually, it appears to stop)
  • (3) SmoothDamp: Remembers its velocity, so it's smooth from the very start even when the goal moves. You tune it in the intuitive unit of "catch up in about smoothTime seconds" — the standard choice for follow cameras
Comparison of the three follow-camera approaches: fixed-time Lerp advances at even spacing and arrives exactly at two seconds, ratio Lerp's spacing shrinks as it asymptotically approaches, and SmoothDamp accelerates and decelerates smoothly into a natural arrival

Break It on Purpose, Then Fix It

This lab rig lets you safely reproduce the classic failures. Try all three:

  1. In (2), "do something on arrival" never fires: Log if (transform.position == goal) and it never becomes true — ratio Lerp is asymptotic. Write arrival checks with a threshold, like Vector3.Distance(transform.position, goal) < 0.01f
  2. In (1), resetting t to zero every frame: Accidentally write elapsed = Time.deltaTime instead of elapsed += Time.deltaTime, and t stays near zero — the camera jitters in place at the start point. With the fixed-time approach, t must accumulate every frame
  3. In (3), making velocity a local variable: Write Vector3 velocity = Vector3.zero; inside LateUpdate and the velocity memory is wiped every frame, making the motion sluggish and sticky. The variable you pass by ref must live as a field

As a final check, set Application.targetFrameRate to 30, 60, and 120 and play. Modes (1) and (3) keep essentially the same motion; mode (2)'s deceleration curve shifts slightly (harmless in most games — as the note says, switch to SmoothDamp if you need it consistent).

Once the experiment is done, pick one movement from your own game and decide which tool builds it. A cutscene with a fixed duration calls for the fixed-time Lerp; following a target that keeps moving calls for SmoothDamp; rotation calls for Slerp. If you can choose based on the personality you just watched — reasons included — you've graduated from this article.

Sponsored

Bonus: Good to Know for Later

Once you're comfortable with interpolation, these topics are worth exploring next.

  • Understanding Quaternions themselves: "Why does rotation need four values?" and "What is gimbal lock?" are covered in the Quaternion article.
  • Fundamentals of movement in Update: Why you multiply by Time.deltaTime and how it relates to frame rate are covered in the Update vs FixedUpdate article — a solid foundation for everything here.
  • Richer animation curves: For complex motion like "start slow, accelerate, then decelerate," draw an AnimationCurve in the Inspector and feed curve.Evaluate(t) into t — you get complete freedom. Tween libraries (such as DOTween) are another popular choice.

Summary

This article took a deep dive into Lerp and Slerp, the two pillars of smooth motion in Unity.

  1. Lerp (linear interpolation) is for linear changes like position and color.
  2. Slerp (spherical linear interpolation) is for Quaternions (rotation), smoothly interpolating along an arc on a sphere.
  3. Moving a fixed fraction of the way from the current value to the target each frame produces easing out (gradual deceleration). This comes from how you use Lerp/Slerp, not from the functions themselves.
  4. For constant-speed motion, use Vector3.MoveTowards / Quaternion.RotateTowards.
  5. The basic recipe for avoiding choppy motion is to approach the target a little bit each frame inside Update, instead of assigning values directly.

"Want a decelerating follow? Use Lerp/Slerp. Want to set a speed? Use MoveTowards/RotateTowards." Master this distinction, and your game's motion will feel a whole level smoother.