Unity - Vector3.Lerp、SlerpとVector3.LerpUnclamped、SlerpUnclamped
初めに
本記事では、二点間を線形に移動させる Lerp、球面線形に移動させる Slerp について説明します。また、Lerpと LerpUnclamped、Slerp と SlerpUnclamped の違いについてまとめます。
Lerp
Vector3.Lerp は2点間を線形補間、すなわち2点間の内分点を取得する関数になります。
public static Vector3 Lerp (Vector3 a, Vector3 b, float t); //aが始点, bが終点, tが0から1までのパラメータ
Lerp は a + (b - a) * t で与えられえる Vector3 を返す関数になります。直線のベクトル方程式や内分点の公式が分かると、式の意味が理解できます。
パラメータ t の値 | 返り値 |
---|---|
t=0 | a |
t=0.2 | 2点a, bを0.2:0.8に内分する点 |
t=0.5 | (a+b)/2 (a と b の中点) |
t=0.7 | 2点a, bを0.7:0.3に内分する点 |
t=1 | b |
Lerp を使うと、2点間を直線移動させることができます。
下のスクリプトは、Lerp を使った2つのオブジェクト間を直線移動させるためのスクリプトです。
using UnityEngine; public class LerpMovement : MonoBehaviour { public Transform startMarker; // 始点オブジェクト public Transform endMarker; // 終点オブジェクト public float speed = 1.0f; // 移動速度 private float startTime; // 開始時間 private float journeyLength; // 移動距離 void Start() { startTime = Time.time; journeyLength = Vector3.Distance(startMarker.position, endMarker.position); } void Update() { float distCovered = (Time.time - startTime) * speed; //開始から現在までの移動距離 float fracJourney = distCovered / journeyLength; //始点から終点までの距離を1としたときの始点と現在地の距離の割合 transform.position = Vector3.Lerp(startMarker.position, endMarker.position, fracJourney); //線形移動 } }
(実行)
youtu.be
Slerp
Vector3.Slerp は2点間を球面線形補間する関数になります。
※Slerp の S はおそらく Sphere:球 の S
public static Vector3 Slerp (Vector3 a, Vector3 b, float t); //aが始点, bが終点, tが0から1までのパラメータ //Lerpと同じ
Slerp を使うと、2点の中点を中心とする球面上を移動させることができます。
下のスクリプトは、Slerpを使った2つのオブジェクト間を球面上移動させるためのスクリプトです。(先ほどのLerp のスクリプトの Vector3.Lerp を Vector3.Slerp に変更しただけ)
using UnityEngine; public class SlerpMovement : MonoBehaviour { public Transform startMarker; // 始点オブジェクト public Transform endMarker; // 終点オブジェクト public float speed = 1.0f; // 移動速度 private float startTime; // 開始時間 private float journeyLength; // 移動距離 void Start() { startTime = Time.time; journeyLength = Vector3.Distance(startMarker.position, endMarker.position); } void Update() { float distCovered = (Time.time - startTime) * speed; float fracJourney = distCovered / journeyLength; transform.position = Vector3.Slerp(startMarker.position, endMarker.position, fracJourney); //Slerp } }
(実行)
youtu.be
LerpUnclamped、SlerpUnclamped
Lerp、Slerp はパラメータの範囲が0から1に制限されていました。LerpUnclamped、SlerpUnclampedはパラメータの範囲に制限がありません。
LerpUnclamped はパラメータに制限がないため、2点を両端とする線分上ではなく、2点を通る直線上にある 2 つのベクトル間を補間します。SlerpUnclamped もパラメータに制限がないため、2点を直径とする球面上を回り続けます。
public static Vector3 LerpUnclamped (Vector3 a, Vector3 b, float t); public static Vector3 SlerpUnclamped (Vector3 a, Vector3 b, float t); //ともに引数、返り値がLerpと同じ
(LerpUnclamped を使って、2点を通る直線上を動かすスクリプト)
※先ほどの Lerp の部分を LerpUnclamped に変更しただけ
using UnityEngine; public class LerpMovement : MonoBehaviour { public Transform startMarker; // 始点オブジェクト public Transform endMarker; // 終点オブジェクト public float speed = 1.0f; // 移動速度 private float startTime; // 開始時間 private float journeyLength; // 移動距離 void Start() { startTime = Time.time; journeyLength = Vector3.Distance(startMarker.position, endMarker.position); } void Update() { float distCovered = (Time.time - startTime) * speed; float fracJourney = distCovered / journeyLength; transform.position = Vector3.LerpUnclamped(startMarker.position, endMarker.position, fracJourney); } }
(実行)
youtu.be
(SlerpUnclamped を使って、2点を直径とする球面上を動かすスクリプト)
※先ほどの Slerp の部分を SlerpUnclamped に変更しただけ
using UnityEngine; public class SLerpMovement : MonoBehaviour { public Transform startMarker; // 始点オブジェクト public Transform endMarker; // 終点オブジェクト public float speed = 1.0f; // 移動速度 private float startTime; // 開始時間 private float journeyLength; // 移動距離 void Start() { startTime = Time.time; journeyLength = Vector3.Distance(startMarker.position, endMarker.position); } void Update() { float distCovered = (Time.time - startTime) * speed; float fracJourney = distCovered / journeyLength; transform.position = Vector3.SlerpUnclamped(startMarker.position, endMarker.position, fracJourney); } }
(実行)
youtu.be
最後に
- Lerp は線形補間
- Slerp は球面線形補間
- Lerp、Slerp のパラメータは0から1まで
- Unclamped がついているものはパラメータに制限がない