Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

Interpolação

A interpolação é uma operação comum na programação gráfica, que é usada para misturar ou fazer transições entre dois valores. Ela também pode ser usada para suavizar movimentação, rotação e etc. É muito bom se tornar familiar com ela para expandir os seus horizontes como desenvolvedor de jogos.

A ideia básica é que você quer fazer uma transição do ponto A para o ponto B. Um valor t, representa os estados intermediários.

Por exemplo, se t or 0, então o estado vai ser igual ao ponto A. Se t for 1 , então o estado é o ponto B. Qualquer coisa entre os dois vai ser uma interpolação.

Entre dois números reais (ponto flutuante), uma interpolação pode ser descrita como:

interpolation = A * (1 - t) + B * t

E é comumente simplificado para:

interpolation = A + (B - A) * t

O nome desse tipo de interpolação, que transforma um valor em outro em uma velocidade constante, é "linear". Então, quando você ouvir falar em Interpolação Linear, saberá que estão se referindo a essa fórmula.

Tem outros tipos de interpolações, que não vão ser discutidas aqui. Uma leitura recomendada depois é a página que fala sobre a Curva de Bézier.

Interpolação vetorial

Tipos de vetores (Vector2 e Vector3) também podem ser interpolados, eles vêm com funções úteis para fazer isso como: Vector2.lerp() e Vector3.lerp().

Para uma interpolação cúbica, também têm Vector2.cubic_interpolate() e Vector3.cubic_interpolate(), que fazem uma interpolação no estilo Bézier.

Aqui está um exemplo de pseudocódigo que vai do ponto A para o ponto B usando uma interpolação:

var t = 0.0

func _physics_process(delta):
    t += delta * 0.4

    $Sprite2D.position = $A.position.lerp($B.position, t)

Isso produzirá o seguinte movimento:

../../_images/interpolation_vector.gif

Transformar interpolação

Também é possível interpolar transformações inteiras (tenha certeza de que eles tenham uma escala uniforme ou, pelo menos, a mesma escala não uniforme). Para isso, pode ser usada a função Transform3D.interpolate_with().

Aqui está um exemplo de transformar um macaco da Posição1 para a Posição2:

../../_images/interpolation_positions.png

Usando o seguinte pseudocódigo:

var t = 0.0

func _physics_process(delta):
    t += delta

    $Monkey.transform = $Position1.transform.interpolate_with($Position2.transform, t)

E de novo, isso vai produzir a seguinte moção:

../../_images/interpolation_monkey.gif

Suavizando o movimento

A interpolação pode ser usada para seguir suavemente um valor alvo em movimento, como uma posição ou uma rotação. A cada frame, lerp() move o valor atual em direção ao valor alvo por uma porcentagem fixa da diferença restante entre os valores. O valor atual se moverá suavemente em direção ao alvo, desacelerando à medida que se aproxima. Aqui está um exemplo de um círculo seguindo o mouse usando suavização por interpolação:

const FOLLOW_SPEED = 4.0

func _physics_process(delta):
    var mouse_pos = get_local_mouse_position()

    $Sprite2D.position = $Sprite2D.position.lerp(mouse_pos, delta * FOLLOW_SPEED)

Aqui está como fica:

../../_images/interpolation_follow.gif

Isso é útil para suavizar o movimento da câmera, para aliados seguindo o jogador, e também para muitos outros padrões que comumente aparecem nos jogos.

Nota

Apesar de usar delta, a fórmula usada acima é dependente da taxa de quadros, porque o parâmetro weight (peso) da função lerp() representa uma porcentagem da diferença restante nos valores, e não uma quantidade absoluta para mudar. Em _physics_process(), isso normalmente é aceitável já que é esperado que a física mantenha uma taxa de quadros constante, e portanto delta é esperado que se mantenha constante.

Para uma versão de interpolação suave que é independente da taxa de quadros que também possa ser usada em process(), use a seguinte fórmula ao invés disso:

const FOLLOW_SPEED = 4.0

func _process(delta):
    var mouse_pos = get_local_mouse_position()
    var weight = 1 - exp(-FOLLOW_SPEED * delta)
    $Sprite2D.position = $Sprite2D.position.lerp(mouse_pos, weight)

Derivar essa fórmula está além do escopo dessa página. Para uma explicação, veja Improved Lerp Smoothing ou assista Lerp smoothing is broken.