Дивіться також цю відповідь .
Є два поширених способи використання 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
параметром.
Цей параметр вже не зовсім "швидкий", тому що ми наближаємось до цілі, як у Зенона . Якби вони sharpnessPerTick
були 0.5
, то під час першого оновлення ми б рухалися на півдорозі до своєї мети. Тоді під час наступного оновлення ми перемістимо половину відстані, що залишилася (тобто чверть нашої початкової відстані). Тоді на наступному ми знову переїдемо наполовину ...
Це дає "експоненціальне полегшення", коли рух швидкий, коли знаходиться далеко від мети і поступово сповільнюється, коли він наближається асимптотично (хоча з нескінченною точністю чисел він ніколи не досягне його в будь-якій кінцевій кількості оновлень - для наших цілей це наближається досить). Він відмінно підходить для переслідування рухомого цільового значення або згладжування галасливого введення, використовуючи " експоненціальну ковзну середню ", зазвичай, використовуючи дуже невеликий 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
само, як ми використовували, перш ніж виправляти час.
У цьому коді є ще одна аргументована помилка, яка використовується Slerp
- сферична лінійна інтерполяція є корисною, коли ми хочемо точно послідовної швидкості обертання через весь рух. Але якщо ми все одно Lerp
будемо використовувати нелінійну експоненціальну легкість, це дасть майже нерозрізний результат і дешевше. ;) Кватерніони лерп набагато краще, ніж матриці, тому зазвичай це безпечна заміна.