Que es el Lerp y como usarlo correctamente

Lerp o Interpolaciòn lineal, es la linea continua que se genera entre un punto inicial y un punto final. Y se puede sacar cualquier punto de esta recta linea, solo necesitamos un porcentaje donde 0% es el punto inicial y 100% es el punto final. En otras palabras podemos obtener cualquier coordenadas que se encuentre entre estos 2 puntos.

LerpExample

NOTA: en programacion 0% – 100% se representa con 0 – 1

Esto en videojuegos se utiliza para hacer mover un objecto cuando deseamos que vaya de un punto A a un punto B. Pero generalmente suele usarse de una manera incorrecta. Codigo base en Unity: Ejemplo:


float Speed = 5f;
transform.position = Vector3.Lerp.html(transform.position, Destiny, Speed * Time.deltatime);

 

¿Porque es incorrecto esto? Bueno imaginemos que estoy en (0,0,0) y deseo ir a (10,0,0).

Frame 1: El Lerp me devolverá un punto entre el inicio y el final, más o menos como a 0.01f (Speed( que es 5f) * Time.deltatime (Que puede ser como un 0.02f)), esto me moverá a  (0.1, 0, 0) porque es el 1% de 10 que es la distancia a recorrer en X.

Han pasado varios frames después en el que ya voy a mitad del destino, es decir mi GameObject va en(5, 0, 0), sigo pidiendo el punto a 0.01, pero ahora no entre (0, 0, 0) y (10, 0, 0), si no de (5, 0, 0) y (0,0,0), es decir el 1% de 5 que es la distancia en X, sera 0.05, ¡ya la mitad de lo que empece en el primer frame a moverme!, esto genera que el movimiento tenga una velocidad uniforme y se vaya desacerando y tarde algo en llegar al destino. Muchos no lo notan y solo piensan que no es preciso y lo “solucionan” que si esta ya a cierta distancia, ya “llego”.

¿Como usar correctamente Lerp?

Ya entendiendo la teoría y el problema, tenemos siempre que conservar el punto inicio y avanzar a un ritmo. Esto podemos hacer así.


float rateTiempo = 1f/TiempoEnHacer;
float rateVelocity = 1f/ Vector3.Distance(startPos, endPos) * Velocidad;
float t = 0.0f;

if(t <= 1f)
{
 t += Time.deltaTime * rate;
 transform.position = Vector3.Lerp(startPos, endPos, t);
}

‘rate’ solo tenemos que sustituir por ‘rateTiempo’ o ‘rateVelocity’ según si necesitamos que recorra eso siempre en un tiempo exacto o se mueva a una velocidad. Y ‘startPos’ son las coordenadas del punto inicial y ‘endPos’ son las coordenadas donde deseamos terminar.

De esta manera, siempre la distancia es la misma y la velocidad constante. Ahora existen 2 rate en este caso, la  ‘rateTiempo’ cuando deseas que haga el recorrido en un cierto intervalo de tiempo o ‘rateVelocity’ para hacer el recorrido a una velocidad, cualquiera de las 2 se sustituye por ‘rate’ dentro del if.

La misma teoría se aplica para la rotación, Vectores 2, 3, 4 o incluso solo un lerp entre 2 números.

Aquí dejo un paquete de Unity que contiene una escena con un pequeño ejemplo Ejemplo Lerp.

6 Comentarios en “Que es el Lerp y como usarlo correctamente

  1. hola primero que nada gracias por compartir tus conocimientos amigo es de gran ayuda para novatos como yo je.

    actualmente tengo problemas con Lerp ya que mi objeto no recorre el tramo que le indico y el movimiento que realiza es irregular.

    lo que intento hacer es determinar una serie de movimientos ami personaje con Lerp cuando se cumpla la condicion que le indico, por ejemplo

    if (numero >= 257 && numero = 285 && numero <= 297) {

    gameObject.transform.position = Vector3.Lerp (transform.position, new Vector3 (x, 10, 0), velocidadArriba * Time.deltaTime);

    }
    veo que corrigues el parametro de la posicion inicial pero sinceramente no entiendo ese codigo (soy novato)
    en mi videojuego el personaje se mueve constantemente en x hacia adelante por eso tengo que tomar siempre la posicion en X y envirla a vector para la posicion final. no se si me explico
    disculpa mi ignorancia saludos

    • Hola Jose, gracias por comentar, acabo de mandarte a tu correo y al final de este post un paquete de Unity de ejemplo. Saludos.

  2. Entonces el lerp solo mueve un objeto una vez por frame en lugar de todo el tiempo? Pensé que tenía que interpolar linealmente; pero si pones que “Tiempo en hacer” es el delta, entonces se contrarrestará porque (1 / Time.deltaTime) * Time.deltaTime da 1. Y como es 1, solo se hará una vez más y entonces será 2. 1 es 100 %, lo que quiere decir que el objecto se teletransportará hasta la posición final sin interpolar en el frame 1. En el siguiente será 200 %, pero de todos modos ya llegó al destino. Cómo hago que se interpole en 0.016666666 (tiempo delta con 60 fps constantes)?

    • Hola Fernando!, Lerp en si solo es una formula matemática que te regresa un punto entre 2 puntos que va del A(0.0f) a B(1.0f) y puedes usarla para avanza a un ritmo, por ejemplo si tenemos un objeto en el punto A y deseamos que llegue al punto B en 5 segundos calculamos un factor de movimiento ( float rateTiempo = 1f/TiempoEnHacer ) que en el ejemplo se volvería 1f/5f (porque deseamos que tarde 5 segundos) que nos daría 0.2f (lo llamaremos rate), este calculo solo sería necesario hacer una sola vez para todo su movimiento y entonces en cada frame hacemos que avance t += Time.deltaTime * rate y llamamos Lerp transform.position = Vector3.Lerp(puntoA, puntoB, t). Esto genera que avances 20% por segundo de la distancia total para que en 5 segundos llegue a su destino, y al multiplicarlo por “Time.deltaTime” es lo que permite que sea constante a los 60fps.
      NOTA:
      Si deseas que tu factor de movimiento no sea a base del tiempo, si no a una velocidad podemos cambiar calcular rate con: float rate = 1f/ Vector3.Distance(puntoA, puntoB) * Velocidad; y así definir que deseas que se mueva a 3 metros por segundo.
      Espero haber explicado mejor. Salu2!

      • Ok, pero corrige eso el problema de la interpolación? En realidad me interesa esto principalmente para una simulación de física, ya que por determinadas razones no puedo usar por completo el sistema de Unity. Quería que los objetos se interpolaran en lugar de saltarse posiciones en el espacio para corregir esto, pero veo que es más complejo que eso. Moverlo con velocidad ayudaría en algo? En realidad no necesito que se mueva de la misma forma que en el mundo real: solo necesito que se salte menos posiciones en el espacio y además sería útil poder hacer algo así entre frames. También porque noté que un objeto que hacía esto no activaba correctamente el void OnCollisionStay(). Por momentos solo dejaba de funcionar (y sé que no se debe a que los rigidbodies se duerman porque ambos objetos los tienen precisamente para evitar esto). Probé moviendo otro gameObject en la escena solo con el mouse y esto no ocurrió, así que pensé que se debía a la teletransportación de posiciones porque era la única diferencia entre los dos.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.