Ver también esta respuesta .
Hay dos formas comunes de usar Lerp
:
1. Mezcla lineal entre un inicio y un final
progress = Mathf.Clamp01(progress + speedPerTick);
current = Mathf.Lerp(start, end, progress);
Esta es la versión con la que probablemente estés más familiarizado.
2. Facilidad exponencial hacia un objetivo
current = Mathf.Lerp(current, target, sharpnessPerTick);
Tenga en cuenta que en esta versión el current
valor aparece como salida y como entrada. Desplaza la start
variable, por lo que siempre comenzamos desde donde nos mudamos en la última actualización. Esto es lo que le da a esta versión de Lerp
una memoria de un cuadro a otro. Desde este punto de partida en movimiento, luego movemos una fracción de la distancia hacia lo target
dictado por un sharpness
parámetro.
Este parámetro ya no es una "velocidad", porque nos acercamos al objetivo de una manera similar a Zeno . Si así sharpnessPerTick
fuera 0.5
, en la primera actualización nos moveríamos a la mitad de nuestro objetivo. Luego, en la próxima actualización, moveríamos la mitad de la distancia restante (un cuarto de nuestra distancia inicial). Luego, en el siguiente, nos moveríamos la mitad otra vez ...
Esto proporciona una "facilidad exponencial" en la que el movimiento es rápido cuando está lejos del objetivo y se ralentiza gradualmente a medida que se acerca asintóticamente (aunque con números de precisión infinita nunca lo alcanzará en un número finito de actualizaciones, para nuestros propósitos se acerca lo suficiente). Es ideal para perseguir un valor objetivo en movimiento o para suavizar una entrada ruidosa usando un " promedio móvil exponencial ", generalmente usando un sharpnessPerTick
parámetro muy pequeño como 0.1
o más pequeño.
Pero tienes razón, hay un error en la respuesta votada que vinculas. No está corrigiendo de deltaTime
la manera correcta. Este es un error muy común al usar este estilo de Lerp
.
El primer estilo de Lerp
es lineal, por lo que podemos ajustar linealmente la velocidad multiplicando por deltaTime
:
progress = Mathf.Clamp01(progress + speedPerSecond * Time.deltaTime);
// or progress = Mathf.Clamp01(progress + Time.deltaTime / durationSeconds);
current = Mathf.Lerp(start, end, progress);
Pero nuestra flexibilización exponencial no es lineal , por lo que simplemente multiplicando nuestro sharpness
parámetro por deltaTime
no dará la corrección de tiempo correcta. Esto se mostrará como un factor decisivo en el movimiento si nuestro framerate fluctúa, o un cambio en la nitidez de flexibilización si pasa de 30 a 60 de manera constante.
En cambio, necesitamos aplicar una corrección exponencial para nuestra facilidad exponencial:
blend = 1f - Mathf.Pow(1f - sharpness, Time.deltaTime * referenceFramerate);
current = Mathf.Lerp(current, target, blend);
Aquí referenceFramerate
hay una constante como 30
mantener las unidades para sharpness
lo mismo que estábamos usando antes de corregir el tiempo.
Hay otro error discutible en ese código, que está utilizando Slerp
: la interpolación lineal esférica es útil cuando queremos una velocidad de rotación exactamente consistente a través de todo el movimiento. Pero si vamos a utilizar una facilidad exponencial no lineal de todos modos, Lerp
dará un resultado casi indistinguible y es más barato. ;) Los cuaterniones son mucho mejores que las matrices, por lo que esta suele ser una sustitución segura.