Formula to calculate Field of View for Portrait / Landscape orientation

I'm currently trying to create a smooth rotation from Landscape to Portrait and back. When setting Screen.orientation, the Camera.aspect changes - and with it the effect of field of view. So, there should be some formula to calculate the target field of view when going from landscape to portrait (while rotating the camera 90 on Z); and going from portrait to landscape. I'm first doing the rotation and when my rotation is complete, I switch Screen.orientation.

In my experiments, I'm having aspect = 1.5 for landscape and aspect = 0.66... for portrait. It's easy to calculate those values from Screen.width and Screen.height, like this (this assumes that my "standard orientation" is landscape):

float width = (float) Mathf.Max(Screen.width, Screen.height);
float height = (float) Mathf.Min(Screen.width, Screen.height);
portraitAspect = height / width;
landscapeAspect = width / height;

I tried getting those values simply by experimenting and with an original field of view value of 60, I have to go down to around 42.4 when rotating from landscape to portrait; and I have to go up to around 82 when rotating from portrait to landscape. However, that doesn't feel like the smartest way to do this ;-)

So: Any math folks out there that can come up with the correct formulas? "Input values" would be original field of view, portraitAspect and landscapeAspect, result would be either field of view when going to portrait, or field of view when going to landscape.

When the animation is done, and I set Screen.orientation, at the same time I also reset the cam's field of view to its original value.

This is a little script based on the formula that Jessy provided for the field of view part. It also supports orthographic cameras which is the much simpler case ;-)

This script can be used for seamless transitions during rotations. The way this has to be used is with a separate class that checks for Input.deviceOrientation and on orientation changes starts the rotation and the animation this script does. When rotation / animation are complete, Screen.orientation must be set and AnimationComplete() must be called which will set FOV/Size back to their original values.

using UnityEngine;
using System.Collections;

public class CamOrientationFOV : MonoBehaviour {

    // uses object this is attached to when null
    public Camera target;

    private float toPortraitFOV = 42.38F;
    public float ToPortraitFOV {
        get { return toPortraitFOV; }
    }

    private float toLandscapeFOV = 82F;
    public float ToLandscapeFOV {
        get { return toLandscapeFOV; }
    }

    private float toPortraitSize = 66F;
    public float ToPortraitSize {
        get { return toPortraitSize; }
    }

    private float toLandscapeSize = 225F;
    public float ToLandscapeSize {
        get { return toLandscapeSize; }
    }

    private float originalSize;
    private float originalFOV;
    private float portraitAspect;
    private float landscapeAspect;

    private float animationStartTime = 0F;
    private float switchTimeSeconds = 0F;
    private bool animateToPortrait = false;
    private bool animateToLandscape = false;

    public void Awake() {
        if (target == null) {
            target = this.camera;
        }

        // we don't care what the current orientation is, we want the real stuff ;-)
        float width = (float) Mathf.Max(Screen.width, Screen.height);
        float height = (float) Mathf.Min(Screen.width, Screen.height);
        portraitAspect = height / width;
        landscapeAspect = width / height;

        // these values are for "landscape" by definition (I develop in/for landscape only ;-) )
        originalFOV = target.fieldOfView;
        originalSize = target.orthographicSize;

        if (target.orthographic) {
            // calculating the Sizes (orthographic)
            toPortraitSize = portraitAspect * originalSize;
            toLandscapeSize = landscapeAspect * originalSize;
        } else {
            // calculating the FOVs (perspective)
            float magicFromPortrait = Mathf.Sqrt(portraitAspect) * Mathf.Tan(originalFOV * Mathf.Deg2Rad * 0.5F);
            toPortraitFOV = Mathf.Atan(magicFromPortrait / Mathf.Sqrt(landscapeAspect)) * Mathf.Rad2Deg * 2;

            float magicFromLandscape = Mathf.Sqrt(landscapeAspect) * Mathf.Tan(originalFOV * Mathf.Deg2Rad * 0.5F);
            toLandscapeFOV = Mathf.Atan(magicFromLandscape / Mathf.Sqrt(portraitAspect)) * Mathf.Rad2Deg * 2;
        }
    }

    public void AnimateTowards(bool towardsLandscape, float switchTimeSeconds) {
        this.switchTimeSeconds = switchTimeSeconds;
        animateToLandscape = towardsLandscape;
        animateToPortrait = !towardsLandscape;
        animationStartTime = Time.time;
    }

    public void AnimationComplete() {
        // force finish
        animateToLandscape = false;
        animateToPortrait = false;
        if (target.orthographic) {
            target.orthographicSize = originalSize;
        } else {
            target.fieldOfView = originalFOV;
        }
    }

    public void LateUpdate() {
        if (animateToLandscape || animateToPortrait) {
            float frac = (Time.time - animationStartTime) / switchTimeSeconds;
            if (frac >= 1F) {
                frac = 1F;
            }
            if (target.orthographic) {
                if (animateToLandscape) {
                    target.orthographicSize = Mathf.Lerp(originalSize, toLandscapeSize, frac);
                } else if (animateToPortrait) {
                    target.orthographicSize = Mathf.Lerp(originalSize, toPortraitSize, frac);
                }
            } else {
                if (animateToLandscape) {
                    target.fieldOfView = Mathf.Lerp(originalFOV, toLandscapeFOV, frac);
                } else if (animateToPortrait) {
                    target.fieldOfView = Mathf.Lerp(originalFOV, toPortraitFOV, frac);
                }
            }

            if (frac == 1F) {
                animateToLandscape = false;
                animateToPortrait = false;
            }
        }
    }
}