DEV Community

Cover image for Mathf.Lerp() Making dynamic camera zoom in Unity using Coroutines
Giorgi Eliozashvili
Giorgi Eliozashvili

Posted on

Mathf.Lerp() Making dynamic camera zoom in Unity using Coroutines

The easiest way to show Player how fast his character is moving is by using camera zoom. For example, if Player is going very fast, camera is zoomed out, FOV is increased, and a feeling of swiftness appears.

We want the camera zoom to be smooth, not instantaneous. For this Mathf.Lerp(), Coroutine and while loop come in handy.


The Mathf.Lerp(A, B, t) function stands for linear interpolation. It takes a starting value - A, a final target - B, and returns a point between them based on the t parameter (a percentage of the path from 0 to 1).

If we want the FOV change to take exactly the time we specify (for example, half a second), we can’t simply pass random numbers. We need a strict timer.

To achieve this, a while loop is created inside the Coroutine, which calculates what fraction of the total animation time has elapsed each frame.


Let’s check the realisation:

using System;
using UnityEngine;
using System.Collections;
using Unity.Cinemachine;

public class CameraController : MonoBehaviour
{
    [SerializeField] private float minFOV = 40f;
    [SerializeField] private float maxFOV = 80f;
    [SerializeField] private float zoomDuration = 0.5f;
    [SerializeField] private float zoomSpeedModifier = 2f;

    private CinemachineCamera _camera;
    private Coroutine _zoomCoroutine;

    private void Awake()
    {
        _camera = GetComponent<CinemachineCamera>();
    }

    // Called externally to trigger the camera zoom effect
    // In this project, it's invoked within the level generation script
    public void ChangeCameraFOV(float speedAmount)
    {
        if (_zoomCoroutine != null)
            StopCoroutine(_zoomCoroutine);

        _zoomCoroutine = StartCoroutine(CameraFOVChange(speedAmount));
    }

    private IEnumerator CameraFOVChange(float speedAmount)
    {
        // Store the initial FOV before starting the interpolation
        var startFOV = _camera.Lens.FieldOfView;

        // // Calculate target FOV and clamp it to prevent visual artifacts or unexpected behavior
        var targetFOV = Mathf.Clamp(startFOV + speedAmount * zoomSpeedModifier, minFOV, maxFOV);

        var elapsedTime = 0f;
        while (elapsedTime < zoomDuration)
        {
            elapsedTime += Time.deltaTime;

            // Calculate the normalized time (0 to 1) 
            // by dividing elapsed time by total duration
            float t = elapsedTime / zoomDuration;

            _camera.Lens.FieldOfView = Mathf.Lerp(startFOV, targetFOV, t);
            // Pause execution and resume on the next Update cycle
            yield return null;
        }

        // Ensure the camera snaps precisely to the target FOV
        // avoiding float inaccuracies
        _camera.Lens.FieldOfView = targetFOV;
        _zoomCoroutine = null;
    }
}
Enter fullscreen mode Exit fullscreen mode

The Coroutine + While Loop + Mathf.Lerp combination is a great pattern for implementing any smooth time change in Unity. Once you understand how the time step t is calculated, you can use this pattern for anything from smooth platform movement to dissolving objects upon destruction.

Top comments (0)