【Unity】LerpとSlerpで実現する滑らかな移動と回転の極意

作成: 2025-12-10最終更新: 2026-07-13

Unityでオブジェクトを滑らかに動かすための必須関数、Lerp(線形補間)とSlerp(球面線形補間)を初心者向けに解説。減速する理由(イージングアウト)や、等速で動かすMoveTowards / RotateTowardsとの使い分けも実践コード付きで紹介します。

「オブジェクトを動かしたい」と思って transform.position = targetPosition; と書いたら、一瞬で目的地にワープしてしまった——Unity初心者なら誰もが通る道です。移動も回転も、直接代入では「カクッ」と切り替わるだけで、プロのゲームのような滑らかさは出せません。

その滑らかさを作るのが、補間関数の Lerp(ラープ)と Slerp(スラープ)です。この記事では2つの関数の仕組みと使い分け、そして「なぜか目標に近づくと遅くなる」現象の正体、等速で動かしたいときの正解(MoveTowards / RotateTowards)までを解説します。

滑らかな補間のイメージ。始点から終点へ、途中の点を埋めながら滑らかに移動する

この記事でわかること

  • Lerp(A, B, t) の仕組みと補間係数 t の意味
  • 回転にはLerpではなく Slerp を使う理由
  • 目標に近づくほど減速する「イージングアウト」が起きる仕組み
  • 等速で動かしたいときの MoveTowards / RotateTowards

Sponsored

Lerp(線形補間)とは?

Lerpは「Linear Interpolation(線形補間)」の略です。二つの値(AとB)の間を、指定した割合(t)で直線的に補間する(埋める)計算手法です。

Unityでは、Vector3.LerpColor.LerpMathf.Lerpなど、様々な型に対してこの関数が用意されています。

関数の基本形:

// A: 開始値, B: 終了値, t: 補間係数 (0.0fから1.0f)
結果 = Lerp(A, B, t);
  • t = 0.0f のとき、結果は A になります。
  • t = 1.0f のとき、結果は B になります。
  • t = 0.5f のとき、結果は AB のちょうど中間になります。
Lerpの仕組み��の図。始点Aと終点Bを結ぶ直線上で、tが0なら A、0.5なら中間、1ならBの位置になる

Lerpは、オブジェクトの移動色の変化数値の滑らかな変化など、直線的な変化が必要な場面で最もよく使われます。

Sponsored

Slerp(球面線形補間)とは?

Slerpは「Spherical Linear Interpolation(球面線形補間)」の略です。Lerpが2点間を直線で結ぶのに対し、Slerpは球面上の弧に沿って補間を行います。

Slerpは主に Quaternion(クォータニオン) 、つまりオブジェクトの回転を扱う際に使用されます。

なぜ回転にSlerpが必要なのか?

回転は「角度の変化」なので、直線ではなく円弧に沿って補間するのが自然です。回転をLerpで補間すると、回転の途中で角速度が不均一になり、動きがわずかに不自然になることがあります。Slerpなら弧に沿って均等に補間されるため、振り向きやカメラの回転が滑らかに見えます。

LerpとSlerpの補間経路の比較図。Lerpは2点を直線で結び、Slerpは球面�上の弧に沿って回転を補間する

LerpとSlerpの決定的な違い

特徴Lerp (線形補間)Slerp (球面線形補間)
補間経路直線球面上の弧
主な用途Vector3 (位置), Color (色), float (数値)Quaternion (回転)
tを0→1で動かした場合直線上を等速で移動弧の上を一定の角速度で回転
計算負荷軽いLerpよりやや重い(回転計算のため)

初心者が躓きやすいポイント:なぜ目標に近づくと遅くなる?

Update()の中で Vector3.Lerp(transform.position, target, 0.1f) のように「現在地から目標へ、毎フレーム一定割合だけ近づける」書き方をすると、目標に近づくにつれて移動速度が遅くなります。

これはLerp自体の性質ではなく、使い方によるものです。毎フレーム「残り距離の10%」を進むので、残りが縮むほど1回の移動量も小さくなる——結果として、最初は速く、最後はゆっくりの イージングアウト になります。

イージングアウトと等速移動の比較図。毎フ��レーム残り距離の一定割合を進むLerpは足跡の間隔が徐々に縮んで減速し、MoveTowardsは足跡が等間隔で等速に進む

追従カメラのような「自然な減速」が欲しい場面ではむしろ理想的な挙動ですが、「一定の速度で動かしたい」場合には不向きです。等速で動かしたいときは、後述の MoveTowards を使いましょう。

Sponsored

実践例

例1:Lerpによる滑らかな追従(イージングアウト)

このコードは、オブジェクトを目標地点に向かって滑らかに移動させます。目標に近づくにつれて速度が落ちる、自然な減速アニメーションを簡単に実現できます。

// ファイル名: LerpFollow.cs
using UnityEngine;

public class LerpFollow : MonoBehaviour
{
    public Transform target;   // 追いかける対象

    // 追従の強さ(大きいほど素早く追いつく)
    [Range(0.1f, 10f)]
    public float smoothness = 3f;

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

        // 現在地から目標へ、毎フレーム一定割合だけ近づける
        // 残り距離が縮むほど移動量も減るため、自然な減速(イージングアウト)になる
        transform.position = Vector3.Lerp(
            transform.position,
            target.position,
            smoothness * Time.deltaTime);
    }
}

補足: tsmoothness * Time.deltaTime を使うのは定番の書き方ですが、厳密にはフレームレートによって減速カーブがわずかに変わります。ほとんどのゲームでは問題になりませんが、完全に揃えたい場合は Vector3.SmoothDamp という選択肢もあります。

例2:等速で動かすなら MoveTowards

「毎秒3メートルで目標へ進む」のように速度を指定したい場合は、Vector3.MoveTowards が正解です。毎フレーム決まった距離だけ進み、目標に着いたらピタッと止まります。

// ファイル名: ConstantMove.cs
using UnityEngine;

public class ConstantMove : MonoBehaviour
{
    public Transform target;
    public float speed = 3f; // 移動速度(単位/秒)

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

        // 毎フレーム speed * Time.deltaTime だけ目標に近づく(等速)
        transform.position = Vector3.MoveTowards(
            transform.position,
            target.position,
            speed * Time.deltaTime);
    }
}

例3:Slerpを使った滑らかな振り向き

敵キャラクターがプレイヤーの方へゆっくり向き直る、といった回転の追従にはSlerpを使います。

// ファイル名: 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;

        // ターゲットの方向を向くための目標回転を計算
        Vector3 direction = target.position - transform.position;
        Quaternion targetRotation = Quaternion.LookRotation(direction);

        // 現在の回転から目標の回転へ、弧に沿って滑らかに近づける
        // この書き方も例1と同じくイージングアウト(最後はゆっくり)になる
        transform.rotation = Quaternion.Slerp(
            transform.rotation,
            targetRotation,
            rotationSmoothness * Time.deltaTime);
    }
}

回転を等速にしたい場合は、位置の MoveTowards に対応する Quaternion.RotateTowards(毎秒◯度で回転)を使います。

よくある間違い:Quaternionの直接操作

Unityの回転は、内部的に Quaternion(クォータニオン) という数学的な構造で管理されています。x, y, z, wの4つの値を持ちますが、この値を直接いじるのはNGです。

回転を作るときは Quaternion.Euler()(オイラー角から変換)や Quaternion.LookRotation()(方向から生成)を使い、補間には Slerp / RotateTowards を使う——この組み合わせを覚えておけば、Quaternionの中身を意識する必要はほとんどありません。

実践:追従カメラの動きを3方式で比べる

仕上げに、ここまでの知識を1つの実験にまとめます。題材は カメラを目標位置へ寄せる動き です。見下ろしARPGのカメラパン、2Dプラットフォーマーの追従カメラ、レースゲームの視点切り替え——どのジャンルでも必ず作る動きですが、実は「同じ目標へ寄せる」でも t の作り方で動きの性格がまるで変わります

大前提として、Lerp は「滑らかにする関数」ではありません。 AとBの間の「t割合の点」を返すだけの関数 です。動きを決めているのは、あなたが毎フレーム t をどう作るか。次のスクリプトは、その作り方3方式をInspectorで切り替えて見比べられる実験装置です。

// ファイル名: CameraFollowLab.cs
using UnityEngine;

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

    public Transform target;          // 寄せる目標(プレイヤーやボス位置)
    public Mode mode = Mode.RatioLerp;

    [Header("① 固定時間Lerp用")]
    public float duration = 2f;       // 必ずこの秒数で到着させる
    private Vector3 startPos;
    private float elapsed;

    [Header("② 割合Lerp用")]
    public float smoothness = 3f;

    [Header("③ SmoothDamp用")]
    public float smoothTime = 0.3f;   // 「だいたい何秒で追いつくか」の目安
    private Vector3 velocity;         // 速度の記憶。フィールドに持つのが必須(失敗③)

    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:
                // tを「経過時間 ÷ 所要時間」で自作する。duration秒でt=1になり必ず到着
                elapsed += Time.deltaTime;
                transform.position = Vector3.Lerp(startPos, goal, elapsed / duration);
                break;

            case Mode.RatioLerp:
                // 現在地から毎フレーム一定割合だけ寄せる。柔らかいが漸近(後述)
                transform.position = Vector3.Lerp(
                    transform.position, goal, smoothness * Time.deltaTime);
                break;

            case Mode.SmoothDamp:
                // 「smoothTime秒くらいで追いつく」を指定。速度を記憶するので出だしも滑らか
                transform.position = Vector3.SmoothDamp(
                    transform.position, goal, ref velocity, smoothTime);
                break;
        }
    }
}

3方式を切り替えて再生すると、性格の違いがはっきり見えます。

  • ① 固定時間Lerp: duration秒ちょうどで ピタッと到着 します。ボス登場のカメラパンやカットシーンなど、「尺が決まっている演出」向きです
  • ② 割合Lerp: 出だしが速く、最後は柔らかく減速します。ただし毎フレーム「残り距離の一定割合」しか進まないため、 理論上は永遠に到着しきりません(見た目には止まります)
  • ③ SmoothDamp: 速度を記憶しているので、目標が動いても出だしから滑らか。「だいたいsmoothTime秒で追いつく」という直感的な単位で調整でき、 追従カメラの定番 です
追従カメラ3方式の比較図。固定時間Lerpは等間隔で進み2秒ちょうどに到着、割合Lerpは間隔が縮みながら漸近、SmoothDampは滑らかに加減速して自然に到着する

わざと壊して、直す

この実験装置は、定番の失敗を安全に再現できます。3つ試してみてください。

  1. ②で「到着したら次の処理」が動かない: if (transform.position == goal) をログしてみると、いつまでもtrueになりません。割合Lerpは漸近するからです。到着判定は Vector3.Distance(transform.position, goal) < 0.01f のように しきい値 で書きます
  2. ①のtを毎フレーム0に戻してしまう: elapsed += Time.deltaTime を誤って elapsed = Time.deltaTime にすると、tがほぼ0のままカメラが出発地点で震え続けます。固定時間方式のt毎フレーム積み上げる のが肝です
  3. ③のvelocityをローカル変数にする: Vector3 velocity = Vector3.zero;LateUpdateの中に書くと、毎フレーム速度の記憶が消えて動きが粘つきます。refで渡す変数は フィールドに持つ こと

仕上げに Application.targetFrameRate を30/60/120に変えて再生してみましょう。①と③はほぼ同じ動きを保ちますが、②は減速カーブがわずかに変わります(多くのゲームでは実害のない差です。補足のとおり、揃えたければSmoothDampへ)。

実験を終えたら、自分のゲームの「あの動き」をどれで作るか、1つ選んでみてください。尺の決まった演出なら固定時間Lerp、動き続ける目標への追従ならSmoothDamp、回転ならSlerp——実験で見た動きの性格から理由ごと選べたら、この記事は卒業です。

Sponsored

おまけ:先に知っておくと良いこと

補間を使いこなせるようになったら、次はこのあたりが視野に入ってきます。

  • Quaternionそのものを理解する: 「なぜ回転だけ4つの値なのか」「ジンバルロックとは何か」は Quaternionの記事 で解説しています。
  • Update内の動きの基礎: Time.deltaTime を掛ける理由やフレームレートとの関係は UpdateとFixedUpdateの記事 が土台になります。
  • より豊かなアニメーションカーブ: 「最初ゆっくり→加速→減速」のような複雑な変化は、AnimationCurve をInspectorで描いて curve.Evaluate(t)t に噛ませると自由自在です。トゥイーンライブラリ(DOTweenなど)も定番の選択肢です。

まとめ

本記事では、Unityで滑らかな動きを実現するための二大巨頭、LerpとSlerpについて深く掘り下げました。

  1. Lerp(線形補間) は、位置や色など、直線的な変化が必要な場面で使われます。
  2. Slerp(球面線形補間)Quaternion(回転) 用で、球面上の弧に沿って滑らかに補間します。
  3. 「現在地から毎フレーム一定割合だけ近づける」使い方をすると、イージングアウト(だんだん減速)になります。これはLerp/Slerp自体の性質ではなく使い方によるものです。
  4. 等速で動かしたいときは Vector3.MoveTowards / Quaternion.RotateTowards を使います。
  5. カクカクした動きを避ける基本は、直接代入ではなくUpdate内で毎フレーム少しずつ目標に近づけることです。

「減速する追従が欲しいならLerp/Slerp、速度を決めて動かしたいならMoveTowards/RotateTowards」——この使い分けができれば、あなたのゲームの動きはワンランク上の滑らかさになります。