Fixed width, relative height, on different aspect ratio screen?

I am developing a game in portrait view. I encounter a problem when the game running on different aspect ratio. On taller screen the camera clip the horizontal view. I am expecting a fixed horizontal view, and the clip should be on the vertical view. How can I achieve this on perspective camera and ortographic camera?

I think I can calculate the ortographic size to fit the width, and there is some answer about it. But I think the perspective size cannot easily calculated because of frustum and field of view.

Here my solution for perspective cameras:

//Set a fixed horizontal FOV
private float horizontalFOV = 120f;

//somewhere in update if screen is resizable
cam.fieldOfView = calcVertivalFOV(horizontalFOV, Camera.main.aspect);

private float calcVertivalFOV(float hFOVInDeg, float aspectRatio)
    {
        float hFOVInRads = hFOVInDeg * Mathf.Deg2Rad;  
        float vFOVInRads = 2 * Mathf.Atan(Mathf.Tan(hFOVInRads / 2) / aspectRatio);
        float vFOV = vFOVInRads * Mathf.Rad2Deg;
        return vFOV;
    }

Some explanation:

In Unity you can only influence the aspect and the vertical FOV.

From a given vertical FOV and the aspect ratio Unity calculates the horizontal FOV. So depending on the aspect ratio the horizontal FOV will change.

Now to get a fixed horizontal FOV I calculate the vertical FOV to the current aspect ratio and apply it to the camera. This way the horizontal FOV is fixed and the vertical will change.

camera.orthographicSize = camera.orthographicSize * defaultAspect / camera.aspect;

I know it’s an old thread, but people might still end up looking for an answer.

For orthographic cameras it’s much easier and has been answered already. For perspective ones, however, you need some trigonometry. All the necessary info about that is here: Angle of view - Wikipedia

If you want an easy way out, though, here’s a solution that works with all camera types: Camera Fit: Screen Handler | Camera | Unity Asset Store

There’s 2 way you can solve this problem:

By Changing the Camera FOV

It is the easiest solution, what you need to do is to set the Horizontal Camera FOV to The expected FOV or what i prefer “The design FOV”

Ex :

var designAspect = 2/3; // We'll be using 3 by 2 aspect ratio in Portrait mode
// "Aspect" is width divided by height

var cameraVerticalFOV = camera.fieldOfView; // The camera FOV is the verticall one
var cameraHorizontalFOV = camera.aspect * cameraVerticalFOV;

var horizontalDesignFOV = designAspect * cameraVerticalFOV;
// The verticall FOV is the same because the camera fixed height

var multiplier =  (horizontalDesignFOV / cameraHorizontalFOV);
// Multiplies the the vertical camera FOV into the vertical design FOV

camera.fieldOfView *= multiplier; 
// Apply the multiplier

By Zooming the camera by moving it foward or backwards

Here’s an example problem to give you a Concept

The Camera doesn’t see the full Object like you designed before because of the Camera Dynamic Width


You need to calculate The Distance to Move the Camera so it can see the full object

Let’s call the line with dashes on it the Meetup Line

P is the position of the T on the Z-Axis

T is half of the MeetUp Line

and D is the distance between a Camera and the MeetUp Line

You just need to find the Difference of D in Camera A and Design Camera

Here’s how you can find it :

First, calculate the T

using the D in the Designed Camera, let’s say it’s “10 Meters”

var designHorizontalFOV = designAspect * camera.fieldOfView;

var designTheta = designHorizontalFOV / 2;

var T = Mathf.Tan(Mathf.Deg2Rad * (designTheta)) * 10;
// "Deg2Rad" convert Degrees to Radians

Then,

You’ll need to calculate D for Camera A

var horizontalCameraAFOV = camera.aspect * camera.fieldOfView;

var horizontalCameraATheta = horizontalCameraAFOV / 2;

var cameraA_D = T / Mathf.Tan(Mathf.Deg2Rad * horizontalCameraATheta); // Get the "D"

After That,

you just need to Subtract and Move the Camera

var camera_A_Displacement = cameraA_D - designCamera_D;
// The difference betwen Two "D"

camera_A.transform.localPosition = new Vector3(0,0,-camera_A_Displacement);
// Minus sign to Move the Camera Backwards

If you prefer this method you can also Give a parent to the Camera, so you can move the camera or rotate it without Affecting its zoom by moving or rotating the Parent instead of the Camera directly

I Personally prefer the Second One because i don’t need to Mess up with the FOV

The screen orientation on this Answer is Portrait

If there’s a mistake that i made or any explanation that you don’t understand, Please tell me.