Vedi anche questa risposta .
Esistono due modi comuni per utilizzare Lerp
:
1. Fusione lineare tra un inizio e una fine
progress = Mathf.Clamp01(progress + speedPerTick);
current = Mathf.Lerp(start, end, progress);
Questa è la versione con cui probabilmente hai più familiarità.
2. Facilità esponenziale verso un bersaglio
current = Mathf.Lerp(current, target, sharpnessPerTick);
Si noti che in questa versione il current
valore appare sia come output sia come input. Sposta la start
variabile, quindi iniziamo sempre da dove ci siamo spostati sull'ultimo aggiornamento. Questo è ciò che dà questa versione di Lerp
una memoria da un frame all'altro. Da questo punto di partenza mobile, spostiamo quindi una frazione della distanza verso il target
dettato da un sharpness
parametro.
Questo parametro non è più una "velocità", perché ci avviciniamo al bersaglio in modo simile a Zenone . Se lo sharpnessPerTick
fosse 0.5
, al primo aggiornamento ci sposteremmo a metà del nostro obiettivo. Quindi al prossimo aggiornamento avremmo spostato metà della distanza rimanente (quindi un quarto della nostra distanza iniziale). Poi il prossimo ci sposteremmo di nuovo la metà ...
Ciò fornisce un "rilassamento esponenziale" in cui il movimento è veloce quando lontano dall'obiettivo e rallenta gradualmente mentre si avvicina in modo asintotico (sebbene con numeri a precisione infinita non lo raggiungerà mai in nessun numero finito di aggiornamenti - per i nostri scopi esso si avvicina abbastanza). È ottimo per inseguire un valore target mobile o per livellare un input rumoroso usando una " media mobile esponenziale ", di solito usando un sharpnessPerTick
parametro molto piccolo come 0.1
o più piccolo.
Ma hai ragione, c'è un errore nella risposta votata che colleghi. Non si corregge deltaTime
nel modo giusto. Questo è un errore molto comune quando si utilizza questo stile di Lerp
.
Il primo stile di Lerp
è lineare, quindi possiamo regolare linearmente la velocità moltiplicando per deltaTime
:
progress = Mathf.Clamp01(progress + speedPerSecond * Time.deltaTime);
// or progress = Mathf.Clamp01(progress + Time.deltaTime / durationSeconds);
current = Mathf.Lerp(start, end, progress);
Ma il nostro allentamento esponenziale non è lineare , quindi moltiplicare il nostro sharpness
parametro per deltaTime
non darà la corretta correzione temporale. Questo apparirà come un giudice nel movimento se il nostro framerate fluttua o un cambiamento nella nitidezza di attenuazione se passi costantemente da 30 a 60.
Invece dobbiamo applicare una correzione esponenziale per la nostra facilità esponenziale:
blend = 1f - Mathf.Pow(1f - sharpness, Time.deltaTime * referenceFramerate);
current = Mathf.Lerp(current, target, blend);
Ecco referenceFramerate
una costante come 30
mantenere le unità per sharpness
lo stesso che stavamo usando prima di correggere il tempo.
C'è un altro errore discutibile in quel codice, che sta usando Slerp
: l'interpolazione lineare sferica è utile quando vogliamo una velocità di rotazione esattamente coerente attraverso l'intero movimento. Ma se Lerp
utilizzeremo comunque una facilità esponenziale non lineare, si otterrà un risultato quasi indistinguibile ed è più economico. ;) I quaternioni sono molto meglio delle matrici, quindi di solito questa è una sostituzione sicura.