- Home /
Calculate camera position so the game field is completely visible
I'm making a game where everything happens on a single game field. And in the beginning I would like to calculate the most optimal camera position, i.e. the game field takes as much space on the screen as possible.
So here's an example of almost optimal camera position (almost because I set it manually):
And here's another example where the screen has different aspect ratio. Those paddings on the sides are not optimal:
How to calculate the camera position if I know its rotation and the size of game field? Tried to solve it on paper for a couple of days but can't even draw it properly.
Answer by kidmosey · Sep 25, 2016 at 10:05 PM
I need this for my game, so I went ahead and whipped up something for you. It should probably be changed to just return the target position instead of actually moving the camera, though.
/// <summary>
/// Position the camera so an object's bounding box fills the screen
/// </summary>
/// <param name="zoomToObject">The object that should be focused to</param>
/// <param name="cam">The camera to move</param>
public void ZoomToObject(MeshRenderer zoomToObject, Camera cam)
{
// move the camera to the object
cam.transform.position = zoomToObject.transform.position;
// project a ray from each of the bounding coords to each of the frustum planes
float maxDistance = 0;
Plane[] frustumPlanes = GeometryUtility.CalculateFrustumPlanes(cam);
Plane[] frustumPlanesToUse =
{
// [0] = Left, [1] = Right, [2] = Down,
// [3] = Up, [4] = Near, [5] = Far
frustumPlanes[0], frustumPlanes[1],
frustumPlanes[2], frustumPlanes[3]
};
foreach (Vector3 v in zoomToObject.bounds.GetVertices(true))
{
Ray ray = new Ray(v, cam.transform.forward);
foreach (Plane p in frustumPlanesToUse)
{
float enter;
if (p.Raycast(ray, out enter))
{
if (enter > 0 && enter > maxDistance)
{
maxDistance = enter;
}
}
}
}
// pull the camera back
cam.transform.position -= cam.transform.forward * maxDistance;
}
/// <summary>
/// Return all of the vertices associated with a bounding box
/// </summary>
/// <param name="bounds"></param>
/// <param name="includeCenter">whether to also include the center point</param>
/// <returns></returns>
public static IEnumerable<Vector3> GetVertices(this Bounds bounds, bool includeCenter)
{
Vector3 v1 = bounds.min, v2 = bounds.max;
yield return new Vector3(v1.x, v1.y, v1.z);
yield return new Vector3(v1.x, v2.y, v1.z);
yield return new Vector3(v2.x, v2.y, v1.z);
yield return new Vector3(v2.x, v1.y, v1.z);
yield return new Vector3(v1.x, v1.y, v2.z);
yield return new Vector3(v1.x, v2.y, v2.z);
yield return new Vector3(v2.x, v2.y, v2.z);
yield return new Vector3(v2.x, v1.y, v2.z);
if (includeCenter)
yield return bounds.center;
}
It looks promising, will try it and post the final version here. $$anonymous$$any thanks!
Here's the result. I think there should be some correction depending on the camera angle.