Trigonometry/cam frustum issue

Context:
I have a grid based puzzle and the camera needs to cover all of it. Every level has a different grid size, it could be 22x8, it could be 6x12, etc.

It’s a perspective camera. The grid is on the XZ plane. The camera is slightly tilted(70, 0, 0).

Current behaviour and goal:
In the first pass, the camera initially positions itself so that the grid covers exactly 65% of the vertical screen, factoring in the camera’s rotation.

Now, depending on the aspect ratio of the device and the grid, it’s possible that some cells are outside of the frustum horizontally since my code does not consider the X axis in the first pass.

In the second pass, which I’m struggling with, I’d like to reposition the camera even further, if and only if there are elements outside of the frustum on the X axis.

The first pass works fine. I can’t figure out how to do the second bit.

Here’s my code for the first pass along with an image to help identify the variables.

private void OnBoardGenerated()
{
    float percentageOfScreenCoveredByGridVertically = 0.65f;


    float A = Camera.main.fieldOfView;
    float B = 90f - transform.rotation.eulerAngles.x + A / 2f; // Top end angle taken from the FoV angle if the FoV triangle was split into 2 right triangles, perpendicular to the ground
    float C = 180f - 90f - B; // Top end angle against the ground
    float D = 180f - A - C; // Bottom end angle against the ground


    float a = Board.Instance.Height / percentageOfScreenCoveredByGridVertically;
    float b = Mathf.Abs(a / Mathf.Sin(A * Mathf.Deg2Rad) * Mathf.Sin(D * Mathf.Deg2Rad)); // Length of the top end side of the frustum from the camera to the ground
    float c = Mathf.Sin(C * Mathf.Deg2Rad) * b; // Length of the small side of the right triangle
    float d = Mathf.Sin(B * Mathf.Deg2Rad) * b; // Right triangle perpendicular to the surface at the camera's position
    float e = d - a / 2f; // The offset for the camera to be centered on the z axis, relatively to the board

    float zCamOffset = a * 0.037f; // Camera is centered. Since it's slightly tilted, the top part will look smaller. This offset is to make both top and bottom look the same.

    transform.position = Board.Instance.CenterPosition + new Vector3(0f, c - 0.5f, -e + zCamOffset); // The vertical origin is at -0.5f since blocks are at 0 with a size of 1
}

The drawing is an orthographic projection viewed from the side, if that makes any sense.
Green = camera
Pink = frustum with rotation factored in
Yellow = ground
Blue = Imaginary line splitting frustum into 2 right triangles perpendicular to the ground
Orange = center of frustum with rotation factored in

Here is a small video showing the current behaviour. You’ll see the cam is always positioned so that the board takes 65% of the screen vertically, no matter the height of the grid. You’ll also notice the issue where cells on the X axis are out of the frustum.

I can’t wrap my head around how to get this to work. Since the camera is tilted, there are more cells fitting in horizontally on the top part of the screen and less on the bottom. Therefore, the width needs to be sampled at a predetermined position, I believe. Thing is, the width is supposed to drive the position, not the other way around. I’m not sure how to get this to work.

This can be tricky and you’ve done a lot of the steps necessary… but!

Have you considered looking into Cinemachine? It’s a free package from Unity.

I think this would do it for you:

https://docs.unity3d.com/Packages/com.unity.cinemachine@2.3/manual/CinemachineTargetGroup.html

I think the inputs you’d give it are the corners of your board.

Or alternately if you look at your board as an aggregate large object, perhaps this:

https://docs.unity3d.com/Packages/com.unity.cinemachine@2.3/manual/CinemachineFollowZoom.html

Whew, sorry for the delay, first time Cinemachine user here. There are a LOT of properties.

Managed to get the desired behaviour working with the cinemachinetargetgroup component that you mentioned, the regular body transposer and aim adjustment mode to dolly. Thank you for the help!

2 Likes

Yeah, Cinemachine is a beast… I have yet to crack all of its properties, kinda like Unity I guess. Glad it worked out for you. Camera stuff is always tough to get right and a bad / glitchy camera is just awful in a game.

1 Like