- Home /
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.
Answer by siege911 · Jan 21, 2013 at 05:38 PM
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);
}
$$anonymous$$athematics isn't my first langage, I searched a way to do that for HOURS. Thanks a bunch.
Answer by MasterKelli · Jul 16, 2014 at 09:09 AM
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);
}
thank you for the clean version of the code, works as a charm.
Excellent, thanks for this short & clean code! It prevented a bad headache
Very old but thanks for this. Just to say, to prevent movement when at zoom limits, you can clamp amount to [size - maxZoom, size - $$anonymous$$Zoom], where size is the camera's orthographic size.
Answer by Vivien_Lynn · Oct 29, 2020 at 12:45 PM
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;
}
}
I noticed a general issue with just changing the orthographic size (os) in fixed steps. Let's say our start os is 20 and we zoom in by 2. That is a difference of 10%. So we just zoomed in a little.
Now, let's do the same while we are already far zoomed in. Current os is 4, and we zoom in by 2. That is a difference of 50%. Basically everything on the screen is now twice as big as it was with the os value of 4.
To fix that, we need to zoom in percent-steps, e.g. 10%-steps.
For zoo$$anonymous$$g in, we would need to decrease the current os by 10%.
For zoo$$anonymous$$g out we would need to increase the current os by 11,11~%.
In the above example we would need to change line 19 to this:
float newZoomLevel = mouseScrollWheel > 0
? cam.orthographicSize * (1 - (0.1f * mouseScrollWheel))
: cam.orthographicSize * (1 - (0.11111f * mouseScrollWheel));
Answer by robertbu · Jan 21, 2013 at 04:40 PM
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.