- Home /
How to find world coordinates of screen corners with a camera angle
Hi, I'm trying to find a way to correctly calculate the world width and height of my screen in world units. To do that I need to calculate 2 corners and then calculate the distance in width and height.
I know about the Camera.main.ViewportToWorldPoint(Vector3(1,1,CameraDist));
BUT...I have a camera that looks down on the Y axis on a 3D plane AND it's rotated slightly to give the plane below a perspective view.
First of all...if my camera position is (0, 10, 0) and looks down the Y axis should I use:
Camera.main.ViewportToWorldPoint(Vector3(1, CameraDist, 1))
for the top-right corner?
And second, how do I take in account the fact that the camera is a bit rotated? (it doesn't look down straight to the Y axis).
Thanks
I am having trouble to understand what exactly you want. There is no such thing as a "world coordinate for a given screen position". There is a ray going through the scene at a screen position and you get it by Camera.main.ScreenPointToRay.
So.. am I right that you actually want to know the angle setting you have to put in your camera so it fully "sees" a given section of a 3D plane?
If so, the by far fastest way to do this is to just try it out in the editor until it fits, no? :)
maybe I didn't explain myself very well...using the Camera.ViewportToWorldPoint (http://docs.unity3d.com/Documentation/ScriptReference/Camera.ViewportToWorldPoint.html) you can get the bottom-left and top-right points of the viewport (or of the screen if you want since in my case they're the same) and those points are in World Coordinates. Depending on the device I deploy the visible area of my scene differs (because of the different resolution) so the top-right corner coordinate in world units on an iPad3 is different than the one of an iPhone4 for example.
$$anonymous$$y problem is how to calculate those points correctly since my camera looks down the Y axis and has an angle set to it.
There's a similar question here: http://answers.unity3d.com/questions/195324/viewporttoworldpoint-doesnt-work-as-expected.html but it doesn't have the issue of having an angled camera.
Any idea?
using the Camera.ViewportToWorldPoint ... you can get the bottom-left and top-right points of the viewport
You lost me again. :(. There is no "point of the viewport". You can get the point in a plane at a certain distance from the camera (ViewportToWorldPoint). Or you can get a ray going though your world along the corner of your viewport (ViewportPointToRay).
So the question about "how to calculate these points" just doesn't work. As it is now, it is totally confusing to me what you want to achieve. :(
Or let me put it this way: You simple cannot "calculate the world width and height of my screen in world units" since this would depend on the distance to the camera.
$$anonymous$$aybe you could edit your original question and state what your actual goal is to make things clear? (Rotate the camera to fit some screen? Finding the angle in the camera for a given rotation? Finding the position of the camera to see some area of a plane?)
Answer by aldonaletto · Jul 03, 2013 at 03:49 PM
If the camera isn't perfectly perpendicular to the ground plane, the distances between the corners will be different! Any screen point (2D) corresponds in the 3D world to a line that passes through the point and the camera position. You must specify which point in this line you're interested in. A common approach is to define a logical plane and use Plane.Raycast to get the distance from the camera. If you want to find the camera corners on an horizontal plane positioned at (0,0,0), for instance, you could use something like this:
// create logical plane perpendicular to Y and at (0,0,0):
var plane = new Plane(Vector3.up, Vector3(0,0,0));
var ray: Ray;
var distance: float;
ray = Camera.main.ViewportPointToRay(Vector3(0,0,0)); // bottom left ray
if (plane.Raycast(ray, distance)){
var botLeft: Vector3 = ray.GetPoint(distance);
}
ray = Camera.main.ViewportPointToRay(Vector3(0,1,0)); // top left ray
if (plane.Raycast(ray, distance)){
var topLeft: Vector3 = ray.GetPoint(distance);
}
ray = Camera.main.ViewportPointToRay(Vector3(0,1,0)); // top left ray
if (plane.Raycast(ray, distance)){
var topLeft: Vector3 = ray.GetPoint(distance);
}
ray = Camera.main.ViewportPointToRay(Vector3(1,0,0)); // bottom right ray
if (plane.Raycast(ray, distance)){
var botRight: Vector3 = ray.GetPoint(distance);
}
ray = Camera.main.ViewportPointToRay(Vector3(1,1,0)); // top right ray
if (plane.Raycast(ray, distance)){
var topRight: Vector3 = ray.GetPoint(distance);
}
This was very helpful for me, in my case I was using a sideview rather than a top-down view, and all I had to do was change the first line to use Vector3.back
ins$$anonymous$$d of Vector3.up
Answer by DavidDebnar · Jul 03, 2013 at 03:24 PM
You need to calculate 3 points: bottom-left, bottom-right, and top-right and then check the distances between them. Distance between b-l and b-r is the width and the distance between b-r and t-r is the height. I wrote a simple function to demonstrate.
function CalculateScreenSizeInWorldCoords () : Vector2 {
var cam = Camera.main;
var p1 = cam.ViewportToWorldPoint(Vector3(0,0,cam.nearClipPlane));
var p2 = cam.ViewportToWorldPoint(Vector3(1,0,cam.nearClipPlane));
var p3 = cam.ViewportToWorldPoint(Vector3(1,1,cam.nearClipPlane));
var width : float = (p2 - p1).magnitude;
var height : float = (p3 - p2).magnitude;
var dimensions : Vector2 = Vector2(width,height);
return dimensions;
}
Usage:
function Start () {
var dimensions : Vector2 = CalculateScreenSizeInWorldCoords();
Debug.Log("Width = " + dimensions.x + "; Height is = " + dimensions.y);
}
--David--