Ortho camera zoom to mouse point

I’ve got a simple script to change the orthographic size of my camera when I scroll in or out on the mouse wheel. The only problem is that it basically zooms straight in and out.

I want to be able to zoom towards the mouse point. So if my mouse is over an object, it zooms right in on that object. I’m unsure how to start on that given that it’s an orthographic camera so the camera itself isn’t moving towards a point.

Even though this thread is very old, here’s my clean version of zooming orthographic camera towards any point:

    // Ortographic camera zoom towards a point (in world coordinates). Negative amount zooms in, positive zooms out
    // TODO: when reaching zoom limits, stop camera movement as well
    void ZoomOrthoCamera(Vector3 zoomTowards, float amount)
    {
        // Calculate how much we will have to move towards the zoomTowards position
        float multiplier = (1.0f / this.camera.orthographicSize * amount);

        // Move camera
        transform.position += (zoomTowards - transform.position) * multiplier; 

        // Zoom camera
        this.camera.orthographicSize -= amount;

        // Limit zoom
        this.camera.orthographicSize = Mathf.Clamp(this.camera.orthographicSize, minZoom, maxZoom);
    }

Example with mouse:

        // Scroll forward
        if (Input.GetAxis("Mouse ScrollWheel") > 0)
        {
            ZoomOrthoCamera(Camera.main.ScreenToWorldPoint(Input.mousePosition), 1);
        }

        // Scoll back
        if (Input.GetAxis("Mouse ScrollWheel") < 0)
        {
            ZoomOrthoCamera(Camera.main.ScreenToWorldPoint(Input.mousePosition), -1);
        }

Instead of using a multiplier like @MasterKelli presented, we take the difference of the cursor position before and after zooming to change the camera position.
I personally find this easier to understand and easier to debug, because we only move the camera if we actually do change the orthographic size of the camera.

So in conclusion there is no need to check if we actually clamped the zoom value. We just do clamp it and if we hit min or max, the difference between the two positions will change accordingly.

using UnityEngine;    
public class CameraZoom : MonoBehaviour
{
    [SerializeField] private Camera cam;
    [SerializeField] private float zoomSpeed = 20f;
    [SerializeField] private float minCamSize = 5f;
    [SerializeField] private float maxCamSize = 20f;

    private void Update()
    {
        Zoom();
    }
    
    private void Zoom()
    {
        // Get MouseWheel-Value and calculate new Orthographic-Size
        // (while using Zoom-Speed-Multiplier)
        float mouseScrollWheel = Input.GetAxis("Mouse ScrollWheel") * zoomSpeed;
        float newZoomLevel = cam.orthographicSize - mouseScrollWheel;

        // Get Position before and after zooming
        Vector3 mouseOnWorld = cam.ScreenToWorldPoint(Input.mousePosition);
        cam.orthographicSize = Mathf.Clamp(newZoomLevel, minCamSize, maxCamSize);
        Vector3 mouseOnWorld1 = cam.ScreenToWorldPoint(Input.mousePosition);

        // Calculate Difference between Positions before and after Zooming
        Vector3 posDiff = mouseOnWorld - mouseOnWorld1;

        // Add Difference to Camera Position
        Vector3 camPos = cam.transform.position;
        Vector3 targetPos = new Vector3(
            camPos.x + posDiff.x,
            camPos.y + posDiff.y,
            camPos.z);

        // Apply Target-Position to Camera
        cam.transform.position = targetPos;
    }
}

After a bunch more reading and playing around with code, I figured out exactly how to do what I’m trying to accomplish. It works for both zoom in and out. It moves the camera so that the mouse stays on the exact same 2D location as you zoom in or out.

Here’s the rough code for whoever may need it. It’s got some redundant code and needs to be cleaned up as some of it is very specific to my application, but it’s a good basic start for anyone who needs it.

//ScrollWheel to zoom in and out.
	if( Input.GetAxis("Mouse ScrollWheel") > 0 && camera.orthographicSize > cameraMin)
	{
		mousePos = camera.ScreenToWorldPoint(Vector3 (Input.mousePosition.x, Input.mousePosition.y, camera.transform.position.z));
		dragOrigin = camera.ScreenToWorldPoint(Vector3 (Screen.width / 2, Screen.height / 2, camera.transform.position.z));
		transform.position.y = transform.position.y + ((mousePos.y - dragOrigin.y) / (camera.orthographicSize * 2));
		transform.position.x = transform.position.x + ((mousePos.x - dragOrigin.x) / (camera.orthographicSize * 2));
		transform.position.z = -15;
		
		camera.orthographicSize -= .5;
		camera.orthographicSize = Mathf.Clamp(camera.orthographicSize, cameraMin, cameraMax);

		
	}
	else if(Input.GetAxis("Mouse ScrollWheel") < 0 && camera.orthographicSize < cameraMax)
	{
		mousePos = camera.ScreenToWorldPoint(Vector3 (Input.mousePosition.x, Input.mousePosition.y, camera.transform.position.z));
		dragOrigin = camera.ScreenToWorldPoint(Vector3 (Screen.width / 2, Screen.height / 2, camera.transform.position.z));
		transform.position.y = transform.position.y - ((mousePos.y - dragOrigin.y) / (camera.orthographicSize * 2));
		transform.position.x = transform.position.x - ((mousePos.x - dragOrigin.x) / (camera.orthographicSize * 2));
		transform.position.z = -15;
		}
		mousePos = camera.ScreenToWorldPoint(Vector3 (Input.mousePosition.x, Input.mousePosition.y, 0 - camera.transform.position.z));
		dragOrigin = camera.transform.position;

		camera.orthographicSize += .5;
		camera.orthographicSize = Mathf.Clamp(camera.orthographicSize, cameraMin, cameraMax);

	}

You’ll need to translate the camera so that its x,y (assuming you are looking down the z axis) matches the x,y of the object. You can use Vector3.Lerp() so that the position changes as you zoom in. You’ll have to figure out what zooming out means…zoom out from the new position or back to some original position.