- Home /
How to accurately zoom (not dolly) and pan Camera to mouse click position
I have a perspective camera that I am pointing down (negative Y-axis) at a flat gameboard in the xz-plane. When the user double clicks the camera zooms out to show the entire game board by changing the field of view. This works great no problem.
When the user double clicks again the camera zooms back to the default field of view (in this case 22) and pans to the location of the click in the x and z direction with the y coordinate being set to the default camera height (the same height before we zoomed out).
This is working almost perfectly but there is a slight problem. The problem is that the camera does not center properly over the click location after zooming (it's perfect if I click in the center of the screen and becomes more off the further away from center I click). I can tell because I place an object in the screen, zoom out, then double click on the object. The desired behavior is to have the camera be zoomed in directly on top of the object. However, because I am changing the fov the computed position returned from camera.ScreenToWorldPoint does not seem to be exactly right. If I don't change the fov and just change the position (move the camera to where I clicked without zooming) the camera centers exactly over the click location.
Here is the relevant snippet of code:
//we want to zoom in where the user clicked and reset the default position and fov
//source.Position is the location of the mouse click
//defaultPos is the default position of the camera
Vector3 zoomWorldPointPosition = new Vector3(source.Position.x, source.Position.y, defaultPos.y);
Vector3 newWorldPosition = camera.ScreenToWorldPoint(zoomWorldPointPosition);
newWorldPosition.y = defaultPos.y;
//Animate from the current fov and position to the new fov and position
doFieldOfViewTween(camera.fieldOfView, defaultFov);
doPositionTween(camera.transform.position, newWorldPosition);
Does anyone know how I could solve this problem? I know if I dolly instead of zoom this won't be an issue but I prefer the zoom effect as it looks a little cooler when the skybox distorts a bit =)
Thank you!
---- EDIT ------
Here are a set of three images to illustrate the problem. In image one the camera is centered above the board. In image two the user has double clicked which changes the FOV to 98 zooming out on the board. The user then double clicks where the X is to zoom in and pan the camera. In image three the camera has changed its FOV back to 22 as a result of the zoom in and pan to the location provided by ScreenToWorldPoint. Notice how the white cylinder is not centered even though the user double clicked on the white cylinder. The desired behavior is to have the white cylinder centered.
Answer by DaveA · Mar 05, 2012 at 10:32 PM
How are you getting source.Position?
This is somewhat suspect:
Vector3 zoomWorldPointPosition = new Vector3(source.Position.x, source.Position.y, defaultPos.y);
The Z component is set to a Y component?
I would think it would be something like
Vector3 zoomWorldPointPosition = new Vector3(source.Position.x, defaultPos.y, source.Position.z);
Hi DaveA, thanks for the feedback. "source" is a Vector2 which contains the screen coordinates of the mouse click. The screen coordinates are correctly set based on my testing by clicking at the corners. ScreenToWorldPoint takes a Vector3 where the x and y coordinate of that Vector3 should be the x and y coordinates of the Vector2 screen coordinates. $$anonymous$$y understanding is that the z coordinate of the Vector3 is the distance from the camera to the object (which in my case is defaultPos.y since the camera's forward vector is in the +Y direction. In other words, the camera is floating above the board in the Y direction so the distance from the camera to the board is just defaultPos.Y (the board is at Vector3(0,0,0)).