Sunday, April 19, 2015

Constructing the camera frustum planes

The camera frustum is defined by the orientation and field of view of the camera and looks like a pyramid with the peak located at the camera and everything inside is visible on the screen.

Each edge of the the screen can be represented by a plane and in addition the near and far distances cap the frustum. Creating planes of the surface of the frustum is not the only way to represent it but it is convenient for many tests and placements.

A typical camera frustum with plane normals pointing outwards.

Before jumping in to formulas the value of field of view needs to be described.
The most common way to describe field of view in games is an angle between the top and bottom or between the left and right side of the screen, and most math uses the half field of view.

Note that it is not obvious that the field of view angle relates to the vertical or the horizontal span of the screen, but defining it as the vertical span is more common. For film cameras the diagonal is often used.

Another way field of view is defined is in focal length mm, which relate to specific real-world lenses and is typically a diagonal rather than horizontal or vertical which adds to the confusion. This wikipedia page explains a lot of the intricacies with focal length to angle of view conversions, and is calculated with angle = 2 arctan(d/2f) where d represents the dimension (film width or height or diagonal) and f is the focal distance (distance from the film to the point behind it where the rays converge into a single point).

I prefer to define the camera frustum planes as facing outwards from the visible space, which means if I want to move a camera plane to fit a point outside it should move in the direction of the normal. It can be reasoned that the bounding planes should point inwards but the difference is just a sign change for any test.

Camera frustum and relationship with field of view and near plane.

If the camera orientation is defined by angles it can be trivial to find the normals, but usually you start with a camera matrix or quaternion.

Assuming that your field of view is defined as the vertical span of the screen and extracting the camera Forward and Up directions the up and down normals can be calculated as:

nup = cos(fovvert/2) Cup - sin(fovvert/2) Cfwd
ndown = -cos(fovvert/2) Cup - sin(fovvert/2) Cfwd

If you don’t have camera Right it is just a cross product of Forward and Up, but depending on the handedness of your coordinate system and the order of the matrix it is one of:

Cright = CfwdCup  or  Cright = CupCfwd

The horizontal field of view can be calculated by multiplying the screen height of the field of view with the screen aspect ratio:

tan(fovhoriz/2) = tan(fovvert/2) * width / height

To get the cosine and sine from the tangent of the angle without the inverse tangent substitute cosine and sine with:

cos(angle) = 1/√(tan2(angle)+1)
sin(angle) = tan(angle)*cos(angle)

With the side direction the left and right frustum planes are:

nleft = -cos(fovhoriz/2) Cright - sin(fovhoriz/2) Cfwd
nright = cos(fovhoriz/2) Cright - sin(fovhoriz/2) Cfwd

In case you started with a horizontal field of view, the vertical field of view can be found as easily.

If the near and far planes are useful those normals are just the camera Forward direction

nnear = -Cfwd
nfar = Cfwd

The distance value for each of the side planes in the vector notation for planes is simply the dot product of the normal for each with the camera position.

dside = nside ᐧ camera position

The distance value for the near plane is dnear = nnear ᐧ camera position - near distance and for the far plane dfar = nfar  ᐧ camera position + far distance.

No comments:

Post a Comment