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.