Smoothly Zooming in and out

Godot Version

Godot 4.4.1

Question

Hello all, I was wondering if anyone managed to get a smooth zoom in and zoom out to work with camera2d? I mean yes there is lerp and you just set the rate, but that assumes the zoom position is at the center of the camera. I am trying to get a nice smooth zoom functionality where the camera zooms with the positions the fingers pressed remaining constant. So if I selected tiles A and B with my fingers and zoomed by some factor, my fingers are still on tiles A and B. I cant get it to work quite right. I am using InputEventMagnifyGesture for getting the zoom factor and simply panning the camera to the given coordinates from the event. This does end up looking quite a bit jerky and the positions arent quite right. I am using lerp for both pan and zoom btw

This won’t get you smooth. Lerp is short for “linear interpolation”, but all the examples I see of people using it are wrong; usually you see something like:

foo = lerp(foo, target, 0.3)

Or something to that effect, which will get you different things depending on your frame rate, but whatever you get will be exponential, not linear.

That’s not how lerp() is meant to be used. If you want actual linear interpolation, you need to keep the inputs positions constant and vary the time value.

Something like:

var start_pos:    Vector2
var end_pos:      Vector2
var interp_time:  float
var interp_end:   float

var lerped_value: Vector2

func _prep_lerp(start: Vector2, end: Vector2, seconds: float) -> void:
    interp_time = 0.0
    interp_end  = seconds
    start_pos   = start
    end_pos     = end

func _process(delta: float) -> void:
    if interp_time < interp_end:
        interp_time  = minf(interp_time + delta, interp_end)
        lerped_value = start_pos.lerp(end_pos, interp_time / interp_end)

If you’re zooming with touch, you’ll also want to make sure that the center of zoom is the center point between the touch points, and adjust your camera appropriately. Unless the center point is dead center in the screen, that will mean moving the camera to compensate, and the distance you’ll need to move it will be based on the offset from the center of the screen at the current scale.

Specifically, you want the distance to the centerpoint from the middle of the screen to remain constant regardless of the zoom level.

How would you make the center of zoom at some point without moving the camera? And I am aware about lerp. The jerkiness is from the camera moving to the center of the pinch position which looks unnatural. And so my problem is more so of making the distance of the position and camera center constant or zooming the camera from an arbitrary position that is not from the center of the camera.

That’s the thing, you do have to move the camera.

Let’s say we’ve got a pinch happening in a corner:

+--------------------------------+  +--------------------------------+
| *              1              2|  | *      1       2               |
|                                |  |    *                           |
|                                |  |                                |
|         *                      |  |3       4       5               |
|                                |  |                                |
|                                |  |                                |
|3              [4]             5|  |6       7      [8]              |
|                                |  |                                |
|                                |  |                                |
|                                |  |                                |
|                                |  |                                |
|                                |  |                                |
|6              7               8|  |                                |
+--------------------------------+  +--------------------------------+

*  - touch points
[] - brackets screen center
#  - fixed map positions

As the points pinch in and the the map zooms out, to keep the touch points under the player’s fingers you need to move the camera from “over 4” to “over 8”. Or, in reverse, as the camera zooms out, the camera needs to move from position 8 to position 4 in order to keep the pinch points in the correct location.

The issue with this is that when I zoom in and out, the camera position doesnt seem to change. Or am I supposed to be considering viewport coordinates? Because if the camera position is constant regardless of zoom, I dont know how I am supposed to move it by how much. Oh wait, lemme try global_position when I get back

You have to move it yourself.

The amount you have to move it is slightly complicated, but not terribly. You have:

  • a center point of your zoom (typically the average of the pinch positions, or the location of the mouse pointer)
  • a camera position

You need to take the difference between the center point and the camera position at the initial zoom, and scale that distance by the same scale you’re applied to the camera. That’ll give you the new camera position.

1 Like

Sorry for the late reply, was busy moving back in to school. But anyways, long story short you are right and I had a missing boolean condition. It’s still a little off when the zooming is done very slowly but its definitely smoother than before

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.