Interpolation

Interpolation is a common operation in graphics programming, which is used to blend or transition between two values. Interpolation can also be used to smooth movement, rotation, etc. It's good to become familiar with it in order to expand your horizons as a game developer.

L'idée de base est que vous voulez passer de A à B. Une valeur t, représente les états intermédiaires.

For example, if t is 0, then the state is A. If t is 1, then the state is B. Anything in-between is an interpolation.

Between two real (floating-point) numbers, an interpolation can be described as:

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

Et souvent simplifié à :

interpolation = A + (B - A) * t

The name of this type of interpolation, which transforms a value into another at constant speed is "linear". So, when you hear about Linear Interpolation, you know they are referring to this formula.

Il existe d'autres types d'interpolations, qui ne seront pas traités ici. Il est recommandé de lire ensuite la page Bezier.

Interpolation vectorielle

Les types de vecteurs (Vector2 et Vector3) peuvent aussi être interpolés, ils ont des fonctions pratiques pour le faire Vector2.lerp() et Vector3.lerp().

Pour l'interpolation cubique, il existe aussi Vector2.cubic_interpolate() et Vector3.cubic_interpolate(), qui font une interpolation de style Bezier.

Here is example pseudo-code for going from point A to B using interpolation:

var t = 0.0

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

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

Il produira le mouvement suivant :

../../_images/interpolation_vector.gif

Interpolation par transformation

Il est également possible d'interpoler des transformations entières (s'assurer qu'elles ont soit une échelle uniforme, soit, au moins, la même échelle non uniforme). Pour cela, la fonction Transform3D.interpolate_with() peut être utilisée.

Voici un exemple de transformation d'un singe de Position1 à Position2 :

../../_images/interpolation_positions.png

En utilisant le pseudo-code suivant :

var t = 0.0

func _physics_process(delta):
    t += delta

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

Et encore une fois, il produira le mouvement suivant :

../../_images/interpolation_monkey.gif

Mouvement lisser

Interpolation can be used to smoothly follow a moving target value, such as a position or a rotation. Each frame, lerp() moves the current value towards the target value by a fixed percentage of the remaining difference between the values. The current value will smoothly move towards the target, slowing down as it gets closer. Here is an example of a circle following the mouse using interpolation smoothing:

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)

Voici à quoi cela ressemble :

../../_images/interpolation_follow.gif

This is useful for smoothing camera movement, for allies following the player (ensuring they stay within a certain range), and for many other common game patterns.

Note

Despite using delta, the formula used above is framerate-dependent, because the weight parameter of lerp() represents a percentage of the remaining difference in values, not an absolute amount to change. In _physics_process(), this is usually fine because physics is expected to maintain a constant framerate, and therefore delta is expected to remain constant.

For a framerate-independent version of interpolation smoothing that can also be used in process(), use the following formula instead:

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)

Deriving this formula is beyond the scope of this page. For an explanation, see Improved Lerp Smoothing or watch Lerp smoothing is broken.