Lerping関数でTime.deltaTimeを使用する理由


12

私の理解では、Lerp関数は、との間の3番目の値()を使用して、2つの値(ab)の間を補間します。で、値aがで、返される値は、返されます。値0.5で、途中の間とが返されます。t01t = 0t = 1bab

(次の図は、滑らかなステップで、通常は3次補間です)

ここに画像の説明を入力してください

私はフォーラムを閲覧していて、この回答で次のコード行を見つけました。transform.rotation = Quaternion.Slerp(transform.rotation, _lookRotation, Time.deltaTime);

「なんてばかだ、彼にはわからない」と私は思ったが、40以上の賛成票があったので、試してみて、十分に機能した。

float t = Time.deltaTime;
transform.rotation = Quaternion.Slerp(transform.rotation, toRotation, t);
Debug.Log(t);

との間0.01でランダムな値を取得し0.02ましたt。関数はそれに応じて補間すべきではありませんか?これらの値が重なるのはなぜですか?Lerpについて私が理解していないのは何ですか?


1
Aは通常位置であり、変化するため、1/60(60 fps)でサンプリングすると、0.16の補間によってオブジェクトが移動するだけで、AとBの間の距離が連続的に狭くなります(したがって、サンプルは次第に小さくなります)。
Sidar

あなたはtを記録し、ttで容認しました...それらは異なる変数です。
user253751 2017年

回答:


18

この回答も参照してください

一般的な使用方法は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、ほとんど区別がつかない結果が得られ、より安価になります。;)四元数は行列よりもはるかによく応答するため、これは通常安全な置換です。


1

欠けているコアコンセプトはこのシナリオにあると思いますAは修正されていません。Aは各ステップで更新されますが、Time.deltaTimeの補間に沿っています。

したがって、各ステップでAがBに近づくと、補間の合計スペースは各Lerp / Slerp呼び出しで変化します。実際の計算を行わずに、効果はSmoothstepグラフと同じではないが、AがBに近づくにつれて減速を概算する安価な方法であると思います。

また、Bも静的でない可能性があるため、これは頻繁に使用されます。典型的なケースは、プレーヤーに続くカメラです。カメラをある場所または回転にジャンプさせることで、ジャーキネスを回避したい。


1

そうです、この方法は、Quaternion Slerp(Quaternion a, Quaternion b, float t)ab量で補間しtます。ただし、最初の値に注意してください。これは開始値ではありません。

ここで、メソッドに与えられる最初の値は、現在のオブジェクトの回転transform.rotationです。したがって、フレームごとに、現在の回転とターゲットの回転_lookRotationを量だけ補間しTime.deltaTimeます。

それがスムーズな回転を生み出す理由です。


2
今私は馬鹿のように感じています
AzulShiva

@AzulShiva誰にでも起こることを心配しないでください;)
Ludovic
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.