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.