[JavaScript] Quaternion 入門 #05 : Slerp は何をしているのか

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