So for starters I should mention that the syntax I will be using for this will be C# for Unity but the math can be applied to any 3D Engine.
The Problem :
I am developing a game which utilizes a perspective camera. Every thing looks great in the initial screen size I designed it for but when I run it on a device with a different aspect ratio or different screen dimensions the page looks really zoomed in or zoomed way out!
Whats Happening :
As you change the viewport of the camera by running the application on devices with different screen sizes you increase or decrease (respectively) the visible area at the bounds of the view frustum.
How To Fix It :
To counter this you need to modify the Field Of View of the camera to ensure the edges of your designed play area perfectly match up with the bounds of the screen. Easier said than done…
First thing to note is that FOV is always relative to the vertical axis. So if you are doing a Landscape game you will find a much simpler calculation to change your FOV but for a Portrait game it is much more difficult, so thats what we are gonna solve for here.
Calculating the Horizontal FOV in radians is done by applying trig to the triangle formed by the [designed] screen width and the distance from the camera to your UI.IMPORTANT: It is important to note you will use the width that you designed for the screen width parameter NOT the current width of the screen.
If you built your UI to look good with a resolution of 640×960 pixels your horiz fov in rad would look like this
float designedScreenWidth = 640f; // I built my UI based on a 640px wide screen float distanceToUI = 500f; // My UI elements are 500 units from the perspective camera float hFOVrad = Mathf.Atan((designedScreenWidth/2f)/distanceToUI);
Now that we have our target hFOV in radians we now want to calculate the corresponding vertical FOV so we can apply it to our cam. (remember: cam FOV is vertical).
float aspect = Screen.width/Screen.height; // capture the CURRENT camera aspect ratio float vFOVdeg = Mathf.Atan(Mathf.Tan(hFOVrad/2f)/aspect) * 2f * Mathf.Rad2Deg;
Awesome! We now have calculated the FOV to apply to the perspective camera to make our UI look perfect on any size device in Portrait orientation.
Finally apply the vFOVdeg to the camera
camera.fieldOfView = vFOVdeg;