Computing camera field of view from frustum planes

June 11, 2015

In one of our VR platforms at Unity today we needed to compute the camera field of view from a set of 6 frustum planes. The previous way to calculate that was pretty slow – it was using 1 acos, 2 tans and an atan. Using a few trig tricks, the new cost of that is a reciprocal sqrtf ( which is faster than a normal sqrtf and it’s tons faster than an acos) and an atanf.

First some identities:

1) cos(\beta) = \vec{N}_{top} \cdot \vec{N}_{near}

2) \alpha = \frac{\pi}{2} - \beta, \ and \ \beta=\frac{\pi}{2}-\alpha

3) tan(\alpha) = \frac{sin(\alpha)}{cos(\alpha)}

4) sin^2(\alpha) + cos^2(\alpha)  = 1

The image represents the geometrical construct to help visualize the problem a bit better. Nt is the normal of the top frustum plane, Nn is the normal of the near frustum plane, a is fov/2 and b is the angle between the Nn and Nt.

frustum

From (2) and (1) we get

5)  cos(\beta) = sin(\alpha)  ( this can be derived by substituting (2) into (1) as follows:  cos(\beta) = cos(\frac{\pi}{2}-\alpha)=cos(\frac{\pi}{2})cos(\alpha)+sin(\frac{\pi}{2})sin(\alpha) = sin(\alpha) )

Using (4) and (5) we can rewrite (3) as follows:

6)  tan(\alpha)=\frac{cos(\beta)}{\sqrt{1-cos^2(\beta)}}

Note that the sqrtf in the bottom can be replaced with a reciprocal sqrtf which is usually way faster than a normal sqrtf

 

To get the field of view, it’s enough to just do \alpha=2 * arctan(\frac{cos(\beta)}{\sqrt{1-cos^2(\beta)}})

 

The code ended up look something like this:

float cosb = DotProduct(frustum[kTop].n, frustum[kNear].n);
float fov = 2.0f * atanf(cosb * rsqrtf(1.0f-cosb*cosb));

 

Share this:

#c0decafe

Leave a Reply

Your email address will not be published. Required fields are marked *


*