1. なぜ lerp(線形補間)はダメなのか?
lerp は「直線」で回転しようとする
Quaternion を lerp(線形補間)すると、一見すると滑らかに見える。 しかし挙動を丁寧に見ると、明確な問題がある。
- 回転は滑らかだが 速度が一定にならない
- 動き始めは遅く、途中で急に速くなる
- 角度が大きくなるほど破綻が目立つ
- 特に 180°近い回転で不自然さが極端に出る
見た目の違和感がすぐ分かるはずだ。
回転の世界は「球の上」で動いている
Quaternion は数値的には4次元ベクトルだが、 “長さ1のQuaternion”は球面(Unit Sphere)の上に存在する。
つまり、回転の変化は本来
球面の上を移動する動き
として扱うべきもの。
ところが lerp はこの球面を無視し、
A と B を 直線でショートカット して混ぜる
という動きをする。
その結果:
- 角度が小さい → 球面と平面がほぼ一致するため問題が出ない
- 角度が大きい → 球と直線が大きくズレて破綻する
- 180°付近 → “真逆”に近くなるため最も壊れやすい
要するに 球面上の移動を、平面の直線で近似しようとすることが問題の根本。
あなたが Three.js で列車カーブを作った時、 「直線補間の違和感」を体感したと思う。 Quaternion でもまったく同じ理由で lerp は壊れる。
2. Slerp が「一定速度に見える」理由(直感のみ)
Slerp は「球の上を一定角速度で歩く」
lerp が A→B を直線で近道する動き だとすると、 Slerp は
球面上の最短経路(大円)を、一定の角速度で進む動き
になる。
Quaternion の世界では、 「姿勢の距離」は 角度 で測られる。 座標の距離ではない。
そのため Slerp は:
- t=0 → 1 の間で
- 角度を同じ割合で増やす
という動きをする。
これがあるので、見た目としては
ずっと同じ速度で回転し続けているように見える
というわけ。
Three.js の quaternion.slerp()
Unity の Quaternion.Slerp()
どれもこの挙動に従っている。
回転の本質は「座標の補間」ではなく「角度の補間」
lerp → 座標(数値)をそのまま直線で混ぜているだけ
slerp → 球面上の角度の距離を均等に進んでいる
この違いが決定的。
だから:
- lerp は、速くなったり遅くなったり動きが乱れる
- slerp は、常に自然で一定速度に見える
Quaternion の補間は “角度の世界の話” だと理解すると、一気に腑に落ちる。
3. 最短経路とは何か?(数式なしの感覚)
Quaternion の補間を理解する上で、 “最短経路”の概念が腑に落ちるかどうか が大きな分岐点になる。 ここさえ押さえれば、Slerp を「正しく使える技術者」になる。
Quaternion は「球の反対側に同じ姿勢が存在する」
Quaternion には有名な性質がある。
q と -q は、まったく同じ回転を表す
つまり Quaternion は、 単純な点ではなく “向きだけが重要な球の上の点” だと考えると理解しやすい。
そして姿勢 A と姿勢 B の間には、必ず
- 短いルート
- 長いルート
の2つが存在する。
Slerp はこの2つのうち
- より近い方
- より短い方
- 動きとして自然な方
この “最短経路” を自動的に選択して補間してくれる。
これが Slerp が正しい補間になる最大の理由。
180°を越えると“裏側”の方が近い場合がある
Quaternion 空間では、 姿勢 B が姿勢 A の「ほぼ180°向こう側」にある場合、
表側から行くより、裏側(-q 側)を通った方が短い
という状況が発生する。
このとき Slerp は自動で「裏側の最短ルート」を選ぶが、 lerp はこの判断ができない。
その結果:
- lerp:長くて変な方向へ曲がっていく
- slerp:一番短くて自然な方向に進む
という違いがはっきり現れる。
これは lerp が破綻する最大の理由でもある。
Quaternion の「2つの経路」の感覚を掴むと、 Slerp が必要な理由が一気に明確になる。
4. Slerp を “実務でどう使うか”
Slerp の仕組みを理解したところで、 実際の開発でどう使うか を簡潔にまとめる。
Quaternion の補間は、 「どの場面で何を使うか」 が分かっていれば迷わない。
lerp を使っていい場面
実は、完全に使っちゃダメなわけではない。
- 角度差が小さい(10〜20°程度)
- 自動補間ではなく単なる混合値(ブレンド)
- カメラ揺れなどの細かい揺らぎ
このくらいなら lerp でも破綻しない。
ただし 姿勢そのものを補間する用途には使わない方がいい。
Slerp を使うべき場面(重要)
「姿勢そのものを補間する場合は、すべて Slerp でいい」
特に:
- カメラの回転(FPS視点・TPS視点)
- プレイヤーの向き補正(方向転換)
- オブジェクトの回転モーション
- Three.js の lookAt の補間
- Unity のキャラ・乗り物の旋回
- 視線ターゲット(Head Look, Aim Offset)
これらは 軸がズレると一瞬で違和感が出る。
Slerp を使えば、
- 速度一定に見える
- 最短経路で曲がる
- 補間が破綻しない
という “自然な回転” が得られる。
実務的な注意点
Slerp の呼び出しは「毎フレーム t を小さく」
Three.js:
quat.slerp(targetQuat, 0.1);
Unity:
rotation = Quaternion.Slerp(rotation, target, t);
t を 0.1〜0.2 くらいの“割合”で進めるのが一般的。
t = 時間 / 経過時間 のように累計で管理すると破綻しやすい。
180° 反転問題は Slerp が自動で解消してくれる
自分で判断しなくていい。 「最短経路で回してくれる」のが最大のメリット。
スムーズに止めたいなら Damp(指数減衰)と併用
回転が近づくにつれて自然に減速させたい場合は、
- SmoothDampAngle(Unity)
- damp → slerp(Three.js)
などを併用する。
Slerp は「一定速度」。 止まるときは別の処理を足す。
5. 総まとめ
最後にこの回の要点を最短でまとめる。
- lerp は直線。回転の本質(球面)を無視する
- だから速度が不自然になり、角度が大きいと壊れる
- Quaternion の補間は 球面上の角度移動 が本質
- Slerp は角度を一定割合で進めるため自然
- さらに q と -q の“2つの経路”問題を自動で回避
- 実務で回転補間に使うべきは基本すべて Slerp
💬 コメント