この回答も参照してください。
一般的な使用方法は2つありますLerp
。
1.開始と終了の間の線形混合
progress = Mathf.Clamp01(progress + speedPerTick);
current = Mathf.Lerp(start, end, progress);
これは、おそらく最もよく知っているバージョンです。
2.ターゲットに対する指数関数的な緩和
current = Mathf.Lerp(current, target, sharpnessPerTick);
このバージョンでは、current
値は出力と入力の両方として表示されることに注意してください。これはstart
変数を置き換えます。そのため、最後の更新で移動した場所から常に開始します。これが、このバージョンのLerp
メモリをフレーム間で提供するものです。次に、この移動する開始点から、距離の一部をパラメーターで指定target
された方向に移動しsharpness
ます。
Zenoのような方法でターゲットにアプローチするため、このパラメーターはもはや「速度」ではありません。場合sharpnessPerTick
した0.5
場合、最初の更新に我々は我々の目標に途中で移動すると思います。次の更新では、残りの距離の半分を移動します(つまり、最初の距離の4分の1)。次に、次の半分に移動します...
これにより、「指数的な緩和」が得られます。ターゲットから遠い場合は動きが速く、漸近的に近づくにつれて徐々に遅くなります(ただし、無限の精度の数値では、有限数の更新では到達しません-私たちの目的では十分に近づきます)。これは、移動するターゲット値を追跡したり、「指数移動平均」を使用してノイズの多い入力を平滑化したりするのに最適です。通常、以下のsharpnessPerTick
ような非常に小さなパラメーターを使用します0.1
。
しかし、あなたは正しい、あなたがリンクした賛成投票にエラーがあります。それdeltaTime
は正しい方法を修正していません。これは、このスタイルのを使用するときによくある間違いですLerp
。
の最初のスタイルLerp
は線形なので、次のように乗算することで速度を線形に調整できますdeltaTime
。
progress = Mathf.Clamp01(progress + speedPerSecond * Time.deltaTime);
// or progress = Mathf.Clamp01(progress + Time.deltaTime / durationSeconds);
current = Mathf.Lerp(start, end, progress);
ただし、指数関数的なイージングは非線形であるため、sharpness
パラメーターを乗算するだけでdeltaTime
は正しい時刻補正が得られません。これは、フレームレートが変動する場合は動きのジャダーとして表示され、30から60に一貫して進む場合はイージングシャープネスの変化として表示されます。
代わりに、指数関数的な緩和のために指数関数的補正を適用する必要があります。
blend = 1f - Mathf.Pow(1f - sharpness, Time.deltaTime * referenceFramerate);
current = Mathf.Lerp(current, target, blend);
ここreferenceFramerate
のようなだけ一定である30
ために単位を保つためにsharpness
、我々は時間を補正する前に使用していたのと同じで。
そのコードには、他にも議論の余地のあるエラーが1つあります。これは、Slerp
球形線形補間が、動き全体で正確に一定の回転速度が必要な場合に役立ちます。しかし、とにかく非線形の指数関数的な緩和を使用する場合はLerp
、ほとんど区別がつかない結果が得られ、より安価になります。;)四元数は行列よりもはるかによく応答するため、これは通常安全な置換です。