UnityでLerp関数とSmoothDamp関数を使用する際の誤解の分析



Analysis Misunderstandings Using Lerp



前に書く
UnityのLerpとSmoothDampは、オブジェクトの動き、段階的な変更、カメラのフォローなどのシーンで一般的に使用されます。 Mathf、Vector2、Vector3などにはこれら2つの機能がありますが、使い方は基本的に同じです。 、使い方は比較的簡単です。ただし、実際の使用では、誤ってピットに落ちることがよくあります。一緒に分析してみましょう。

Lerp関数
Lerp関数の使用における最も一般的な誤解は、弾性運動として直線運動を使用することです(重要なのは、私はまだそれを知らないということです、それは奇妙です、ねえ、それは良い直線運動ではありませんか?少し弾力性があります...)、以下に示すように:



このようなコードは通常、次のように記述されます。
private Vector3 target = new Vector3(0, 0, 5) void Update() { transform.position = Vector3.Lerp(transform.position, target, 0.1f) }

このエラーは主に、Lerpの3番目のパラメーターtの役割を理解できなかったことが原因です。ここでは、理解を容易にするために、Mathf.Lerp関数を使用して分析しますが、考え方は同じです。まず、Mathf.Lerp関数の特定の実装を見てみましょう。
/// /// Clamps value between 0 and 1 and returns value. /// /// public static float Clamp01(float value) { float result if (value 1f) { result = 1f } else { result = value } return result } /// /// Linearly interpolates between a and b by t. /// /// The start value. /// The end value. /// The interpolation value between the two floats. /// /// The interpolated float result between the two float values. /// public static float Lerp(float a, float b, float t) { return a + (b - a) * Mathf.Clamp01(t) }

機能の実現を見れば、誰もが要点を理解できると思われます。直線的に移動したい場合は、tの変化のみを制御する必要があります。 tの値は0-1で、これはポイントaからポイントbまでの範囲を表すパーセンテージ値に似ています。たとえば、aとbの間の3/10の位置に到達する場合、tは0.3である必要があり、1ステップでその位置に到達する場合、tの値は1である必要があります。上記の誤った使用法では、実際の効果は、最初に1/10の位置に到達し、2回目に1/10 + 9/10 * 1/10の位置に到達することです...理論的には、ポイントbに到達することはできません。時間a点とb点の間はすべて1/10なので、移動範囲はどんどん小さくなり、柔軟性感があります。正しい使用方法は次のとおりです。
private Vector3 target = new Vector3(0, 0, 5) private Vector3 startPos private float t1 void Start() { startPos = transform.position } void Update() { t1 += 1f * Time.deltaTime transform.position = Vector3.Lerp(startPos, target, t1) }効果は次のとおりです。




SmoothDamp関数
SmoothDamp関数は、使用中に比較的簡単に表示されます 問題 次のように、コードがより複雑な場合、currentVelocityパラメーターに必要な変数をローカル変数として定義するのは簡単です。
private Vector3 target = new Vector3(0, 0, 5) public float smoothTime = 0.3F void Update() { Vector3 velocity = Vector3.zero transform.position = Vector3.SmoothDamp(transform.position, target, ref velocity, smoothTime) } }

ローカル変数を使用した場合の効果を次の図に示します。どんどん遅くなっています。定義された平滑化時間は明らかに0.3fです。 10秒経ってもまだゆっくり動いているのはなぜですか?



理解を容易にするために、Mathf.SmoothDampの特定の実装を見てみましょう。
public static float SmoothDamp(float current, float target, ref float currentVelocity, float smoothTime, [DefaultValue('Mathf.Infinity')] float maxSpeed, [DefaultValue('Time.deltaTime')] float deltaTime) { smoothTime = Mathf.Max(0.0001f, smoothTime) float num = 2f / smoothTime float num2 = num * deltaTime float num3 = 1f / (1f + num2 + 0.48f * num2 * num2 + 0.235f * num2 * num2 * num2) float num4 = current - target float num5 = target float num6 = maxSpeed * smoothTime num4 = Mathf.Clamp(num4, -num6, num6) target = current - num4 float num7 = (currentVelocity + num * num4) * deltaTime currentVelocity = (currentVelocity - num * num7) * num3 float num8 = target + (num4 + num7) * num3 if (num5 - current > 0f == num8 > num5) { num8 = num5 currentVelocity = (num8 - num5) / deltaTime } return num8 }
特定の実装を通じて、currentVelocity変数が最初に使用され、次に割り当てられていることが明確にわかります。 refを通過することは、前回計算された速度値を取得することです。ローカル変数を使用する場合、速度は毎回ゼロになります。 、最初のスムーズな動きに相当し、スムーズな距離(ターゲットへの変換位置)は常に短くなっていますが、スムーズな時間は変更されていません。スムーズな動きがスムーズな時間内に完了するようにするには、開始速度をますます遅くする必要があるため、上の図の問題が発生します。
currentVelocityをグローバル変数に変更すると、通常の効果を確認できます。
private Vector3 target = new Vector3(0, 0, 5) public float smoothTime = 0.3F private Vector3 velocity = Vector3.zero void Update() { transform.position = Vector3.SmoothDamp(transform.position, target, ref velocity, smoothTime) }

効果は次のとおりです。

04.gif (26.08 KB、ダウンロード:0)

添付ファイルをダウンロードする アルバムに保存



昨日20:48アップロード




最後に書く
さて、今回お話ししたい内容は上記ですので、いつもお役に立てれば幸いです。

この記事のプロジェクトファイル(Unity2017.2.0f3):
リンク:https://pan.baidu.com/s/1kV7rd4bパスワード:vft2