「オブジェクトを動かしたい」と思って transform.position = targetPosition; と書いたら、一瞬で目的地にワープしてしまった——Unity初心者なら誰もが通る道です。移動も 回転も、直接代入では「カクッ」と切り替わるだけで、プロのゲームのような滑らかさは出せません。
その滑らかさを作るのが、補間関数の Lerp(ラープ)と Slerp(スラープ)です。この記事では2つの関数の仕組みと使い分け、そして「なぜか目標に近づくと遅くなる」現象の正体、等速で動かしたいときの正解(MoveTowards / RotateTowards)までを解説します。
この記事でわかること
Lerp(A, B, t)の仕組みと補間係数tの意味- 回転にはLerpではなく
Slerpを使う理由- 目標に近づくほど減速する「イージングアウト」が起きる仕組み
- 等速で動かしたいときの
MoveTowards/RotateTowards
Lerp(線形補間)とは?
Lerpは「Linear Interpolation(線形補間)」の略です。二つの値(AとB)の間を、指定した割合(t)で直線的に補間する(埋める)計算手法です。
Unityでは、Vector3.Lerp、Color.Lerp、Mathf.Lerpなど、様々な型に対してこの関数が用意されています。
関数の基本形:
// A: 開始値, B: 終了値, t: 補間係数 (0.0fから1.0f)
結果 = Lerp(A, B, t);
t = 0.0fのとき、結果はAになります。t = 1.0fのとき、結果はBになります。t = 0.5fのとき、結果はAとBのちょうど中間になります。

Lerpは、オブジェクトの移動や色の変化、数値の滑らかな変化など、直線的な変化が必要な場面で最もよく使われます。
Slerp(球面線形補間)とは?
Slerpは「Spherical Linear Interpolation(球面線形補間)」の略です。Lerpが2点間を直線で結ぶのに対し、Slerpは球面上の弧に沿って補間を行います。
Slerpは主に Quaternion(クォータニオン) 、つまりオブジェクトの回転を扱う際に使用されます。
なぜ回転にSlerpが必要なのか?
回転は「角度の変化」なので、直線ではなく円弧に沿って補間するのが自然です。回転をLerpで補間すると、回転の途中で角速度が不均一になり、動きがわずかに不自然になることがあります。Slerpなら弧に沿って均等に補間されるため、振り向きやカメラの回転が滑らかに見えます。

LerpとSlerpの決定的な違い
| 特徴 | Lerp (線形補間) | Slerp (球面線形補間) |
|---|---|---|
| 補間経路 | 直線 | 球面上の弧 |
| 主な用途 | Vector3 (位置), Color (色), float (数値) | Quaternion (回転) |
| tを0→1で動かした場合 | 直線上を等速で移動 | 弧の上を一定の角速度で回転 |
| 計算負荷 | 軽い | Lerpよりやや重い(回転計算のため) |
初心者が躓きやすいポイント:なぜ目標に近づくと遅くなる?
Update()の中で Vector3.Lerp(transform.position, target, 0.1f) のように「現在地から目標へ、毎フレーム一定割合だけ近づける」書き方をすると、目標に近づくにつれて移動速度が遅くなります。
これはLerp自体の性質ではなく、使い方によるものです。毎フレーム「残り距離の10%」を進むので、残りが縮むほど1回の移動量も小さくなる——結果として、最初は速く、最後はゆっくりの イージングアウト になります。

追従カメラのような「自然な減速」が欲しい場面ではむしろ理想的な挙動ですが、「一定の速度で動かしたい」場合には不向きです。等速で動かしたいときは、後述の MoveTowards を 使いましょう。
実践例
例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);
}
}
補足:
tにsmoothness * 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つ試してみてください。
- ②で「到着したら次の処理」が動かない:
if (transform.position == goal)をログしてみると、いつまでもtrueになりません。割合Lerpは漸近するからです。到着判定はVector3.Distance(transform.position, goal) < 0.01fのように しきい値 で書きます - ①のtを毎フレーム0に戻してしまう:
elapsed += Time.deltaTimeを誤ってelapsed = Time.deltaTimeにすると、tがほぼ0のままカメラが出発地点で震え続けます。固定時間方式のtは 毎フレーム積み上げる のが肝です - ③のvelocityをローカル変数にする:
Vector3 velocity = Vector3.zero;をLateUpdateの中に書くと、毎フレーム速度の記憶が消えて動きが粘つきます。refで渡す変数は フィールドに持つ こと
仕上げに Application.targetFrameRate を30/60/120に変えて再生してみましょう。①と③はほぼ同じ動きを保ちますが、②は減速カーブがわずかに変わります(多くのゲームでは実害のない差です。補足のとおり、揃えたければSmoothDampへ)。
実験を終えたら、自分のゲームの「あの動き」をどれで作るか、1つ選んでみてください。尺の決まった演出なら固定時間Lerp、動き続ける目標への追従ならSmoothDamp、回転ならSlerp——実験で見た動きの性格から理由ごと選べたら、この記事は卒業です。
おまけ:先に知っておくと良いこと
補間を使いこなせるようになったら、次はこのあたりが視野に入ってきます。
- Quaternionそのものを理解する: 「なぜ回転だけ4つの値なのか」「ジンバルロック とは何か」は Quaternionの記事 で解説しています。
- Update内の動きの基礎:
Time.deltaTimeを掛ける理由やフレームレートとの関係は UpdateとFixedUpdateの記事 が土台になります。 - より豊かなアニメーションカーブ: 「最初ゆっくり→加速→減速」のような複雑な変化は、
AnimationCurveをInspectorで描いてcurve.Evaluate(t)をtに噛ませると自由自在です。トゥイーンライブラリ(DOTweenなど)も定番の選択肢です。
まとめ
本記事では、Unityで滑らかな動きを実現するための二大巨頭、LerpとSlerpについて深く掘り下げました。
- Lerp(線形補間) は、位置や色など、直線的な変化が必要な場面で使われます。
- Slerp(球面線形補間) は Quaternion(回転) 用で、球面上の弧に沿って滑らかに補間します。
- 「現在地から毎フレーム一定割合だけ近づける」使い方をすると、イージングアウト(だんだん減速)になります。これはLerp/Slerp自体の性質ではなく使い方によるものです。
- 等速で動かしたいときは
Vector3.MoveTowards/Quaternion.RotateTowardsを使います。 - カクカクした動きを避ける基本は、直接代入ではなく
Update内で毎フレーム少しずつ目標に近づけることです。
「減速する追従が欲しいならLerp/Slerp、速度を決めて動かしたいならMoveTowards/RotateTowards」——この使い分けができれば、あな たのゲームの動きはワンランク上の滑らかさになります。