| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 | .. _doc_interpolation:Interpolation=============Interpolation is a common operation in graphics programming, which is used toblend or transition between two values. Interpolation can also be used to smoothmovement, rotation, etc. It's good to become familiar with it in order to expandyour horizons as a game developer.The basic idea is that you want to transition from A to B. A value ``t``, represents the states in-between.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 * tAnd often simplified to:::    interpolation = A + (B - A) * tThe 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.There are other types of interpolations, which will not be covered here. A recommended read afterwards is the :ref:`Bezier <doc_beziers_and_curves>` page.Vector interpolation--------------------Vector types (:ref:`Vector2 <class_Vector2>` and :ref:`Vector3 <class_Vector3>`) can also be interpolated, they come with handy functions to do it:ref:`Vector2.lerp() <class_Vector2_method_lerp>` and :ref:`Vector3.lerp() <class_Vector3_method_lerp>`.For cubic interpolation, there are also :ref:`Vector2.cubic_interpolate() <class_Vector2_method_cubic_interpolate>` and :ref:`Vector3.cubic_interpolate() <class_Vector3_method_cubic_interpolate>`, which do a :ref:`Bezier <doc_beziers_and_curves>` style interpolation.Here is example pseudo-code for going from point A to B using interpolation:.. tabs:: .. code-tab:: gdscript GDScript    var t = 0.0    func _physics_process(delta):        t += delta * 0.4        $Sprite2D.position = $A.position.lerp($B.position, t) .. code-tab:: csharp    private float _t = 0.0f;    public override void _PhysicsProcess(double delta)    {        _t += (float)delta * 0.4f;        Marker2D a = GetNode<Marker2D>("A");        Marker2D b = GetNode<Marker2D>("B");        Sprite2D sprite = GetNode<Sprite2D>("Sprite2D");        sprite.Position = a.Position.Lerp(b.Position, _t);    }It will produce the following motion:.. image:: img/interpolation_vector.gifTransform interpolation-----------------------It is also possible to interpolate whole transforms (make sure they have either uniform scale or, at least, the same non-uniform scale).For this, the function :ref:`Transform3D.interpolate_with() <class_Transform3D_method_interpolate_with>` can be used.Here is an example of transforming a monkey from Position1 to Position2:.. image:: img/interpolation_positions.pngUsing the following pseudocode:.. tabs:: .. code-tab:: gdscript GDScript    var t = 0.0    func _physics_process(delta):        t += delta        $Monkey.transform = $Position1.transform.interpolate_with($Position2.transform, t) .. code-tab:: csharp    private float _t = 0.0f;    public override void _PhysicsProcess(double delta)    {        _t += (float)delta;        Marker3D p1 = GetNode<Marker3D>("Position1");        Marker3D p2 = GetNode<Marker3D>("Position2");        CSGMesh3D monkey = GetNode<CSGMesh3D>("Monkey");        monkey.Transform = p1.Transform.InterpolateWith(p2.Transform, _t);    }And again, it will produce the following motion:.. image:: img/interpolation_monkey.gifSmoothing motion----------------Interpolation can be used to smoothly follow a moving target value, such as aposition or a rotation. Each frame, ``lerp()`` moves the current value towardsthe 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 getscloser. Here is an example of a circle following the mouse using interpolation smoothing:.. tabs:: .. code-tab:: gdscript GDScript    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) .. code-tab:: csharp    private const float FollowSpeed = 4.0f;    public override void _PhysicsProcess(double delta)    {        Vector2 mousePos = GetLocalMousePosition();        Sprite2D sprite = GetNode<Sprite2D>("Sprite2D");        sprite.Position = sprite.Position.Lerp(mousePos, (float)delta * FollowSpeed);    }Here is how it looks:.. image:: img/interpolation_follow.gifThis 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:    .. tabs::        .. code-tab:: gdscript GDScript            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)        .. code-tab:: csharp            private const float FollowSpeed = 4.0f;            public override void _Process(double delta)            {                Vector2 mousePos = GetLocalMousePosition();                Sprite2D sprite = GetNode<Sprite2D>("Sprite2D");                float weight = 1f - Mathf.Exp(-FollowSpeed * (float)delta);                sprite.Position = sprite.Position.Lerp(mousePos, weight);            }        Deriving this formula is beyond the scope of this page. For an explanation,     see `Improved Lerp Smoothing <https://www.gamedeveloper.com/programming/improved-lerp-smoothing->`__    or watch `Lerp smoothing is broken <https://www.youtube.com/watch?v=LSNQuFEDOyQ>`__.
 |