To boil my question down to the simplest form, I fear I am oversimplifying how mat4 perspective works. I am using

mat4.perspective(45, 2, 0.1, 1000.0)

(the binding is WebGL fwiw). With a fovy of 45, and an aspect ratio of 2, I expect to have a fovx of 90. Thus, if I position my camera at (0, 0, 50), looking towards the origin, I expect to see a cube positioned at (50, 0, 0) (45 degrees) right at the very periphery of my screen, half on, half off,. Instead, a cube at (50, 0, 0) is totally off screen, and my actually periphery occurs at about (41.1, 0, 0).

What am I missing here?

Thanks, nick


You can't multiply the angle by the aspect ratio directly; the aspect ratio is the ratio of pixels horizontally vs. vertically, not the ratio of the angles.

To demonstrate the problem: Assume we have a window that's 100 pixels tall, and 1000 pixels wide. That's a 10:1 aspect ratio. If we have a 90 degree vertical field of view, then naively multiplying the vertical angle by the field of view would imply that we had a 900 degree horizontal field of view. Which is clearly nonsense.

To get the horizontal field of view, you need to convert the angle into pixels, multiply the pixels by the aspect ratio, and then convert back into an angle. It'd look something like this:

float halfVerticalFOV = verticalFOV * 0.5f;
float verticalPixels = tan( halfVerticalFOV );
float horizontalPixels = aspectRatio * verticalPixels;
float halfHorizontalFOV = atan( horizontalPixels );
float horizontalFOV = halfHorizontalFOV * 2.0f;

(Note that trigonometry functions like tan() and atan() will expect your angles to be expressed in radians, not in degrees)

(Also note that I haven't bothered to calculate actual numbers of pixels; just converted our numbers into pixel-relative units so we can legally multiply them by the aspect ratio, before converting back into angles)

Running your example through this code shows that with a vertical FOV angle of 45 degrees and an aspect ratio of 2:1, your horizontal FOV angle will be approximately 79.278 degrees.

Comparing that back to your hand-placed cube, if we calculate atan2(41.1,50.f) (the offset from your camera to the cube you placed manually at the edge of the screen), that returns an angle of 39.42 degrees from forward. The 79.278 FOV value we calculated earlier gives us 39.639 degrees to either side of the camera. So your eyeballing gave an approximate 39.42 degrees from center to edge, and our calculation gives us 39.64 degrees. So your eyeballing was pretty close.

In fact, you'd actually want to place your cube at tanf( halfHorizontalFOV ) * 50.f == 41.4213 in order to place its center point precisely on the edge of the screen, with the camera placed 50 units back from the object, as in your situation.

  • \$\begingroup\$ Wow, thanks a lot. you'd think by now I'd have learned that that when you spend to much time trying to fix an equation, you're probably starting on faulty assumptions. \$\endgroup\$ – Nick Nov 18 '12 at 17:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.