Zobacz także tę odpowiedź .
Istnieją dwa typowe sposoby użycia Lerp:
1. Liniowe mieszanie między początkiem a końcem
progress = Mathf.Clamp01(progress + speedPerTick);
current = Mathf.Lerp(start, end, progress);
Jest to wersja, którą prawdopodobnie znasz.
2. Wykładnicza łatwość w kierunku celu
current = Mathf.Lerp(current, target, sharpnessPerTick);
Zauważ, że w tej wersji currentwartość pojawia się zarówno jako dane wyjściowe, jak i dane wejściowe. Wypiera startzmienną, więc zawsze zaczynamy od miejsca, w którym przeprowadziliśmy się przy ostatniej aktualizacji. To daje tej wersji Lerppamięci od jednej klatki do drugiej. Następnie z tego ruchomego punktu początkowego przesuwamy ułamek odległości w kierunku targetpodyktowanym sharpnessparametrem.
Ten parametr nie jest już „szybkością”, ponieważ zbliżamy się do celu w sposób podobny do Zeno . Gdyby sharpnessPerTickbyły0.5 , to przy pierwszej aktualizacji przenieślibyśmy się w połowie drogi do celu. Następnie przy następnej aktualizacji przesunęlibyśmy się o połowę pozostałej odległości (czyli o jedną czwartą początkowej odległości). Następnie w następnym przejdziemy ponownie o połowę ...
Daje to „wykładniczą ulgę”, w której ruch jest szybki, gdy daleko od celu, i stopniowo zwalnia, gdy zbliża się asymptotycznie (choć przy liczbach o nieskończonej precyzji nigdy go nie osiągnie w żadnej skończonej liczbie aktualizacji - dla naszych celów jest to wystarczająco blisko). Jest świetny do ścigania ruchomej wartości docelowej lub wygładzania głośnego sygnału wejściowego przy użyciu „ wykładniczej średniej ruchomej ”, zwykle przy użyciu bardzo małego sharpnessPerTickparametru, takiego jak 0.1lub mniejszego.
Ale masz rację, w podanej wyżej linku znajduje się błąd. To nie poprawia deltaTimewe właściwy sposób. Jest to bardzo częsty błąd podczas korzystania z tego stylu Lerp.
Pierwszy styl Lerpjest liniowy, więc możemy liniowo dostosować prędkość, mnożąc przez deltaTime:
progress = Mathf.Clamp01(progress + speedPerSecond * Time.deltaTime);
// or progress = Mathf.Clamp01(progress + Time.deltaTime / durationSeconds);
current = Mathf.Lerp(start, end, progress);
Ale nasze łagodzenie wykładnicze jest nieliniowe , więc pomnożenie naszego sharpnessparametru przez deltaTimenie da poprawnej korekty czasu. Będzie to widoczne jako drżenie w ruchu, jeśli nasze tempo klatek będzie się zmieniać, lub zmiana łagodnej ostrości, jeśli konsekwentnie będziesz przechodził z 30 do 60.
Zamiast tego musimy zastosować wykładniczą korektę dla naszej wykładniczej łatwości:
blend = 1f - Mathf.Pow(1f - sharpness, Time.deltaTime * referenceFramerate);
current = Mathf.Lerp(current, target, blend);
Oto referenceFrameratepo prostu stałe 30zachowanie jednostek sharpnesstak, jak używaliśmy przed korektą czasu.
W tym kodzie jest jeszcze jeden możliwy do uzasadnienia błąd Slerp- sferyczna interpolacja liniowa jest przydatna, gdy chcemy dokładnie spójnego tempa obrotu w całym ruchu. Ale jeśli i tak będziemy korzystać z nieliniowej łatwości wykładniczej, Lerpda to prawie nie do odróżnienia wynik i jest tańszy. ;) Quaternions lerp są znacznie lepsze niż macierze, więc jest to zwykle bezpieczna zamiana.