fovy calculation

I’m really tearing my hair out with this one. I’m trying to set fovy (for gluPerspective()) so that an image is centred and just fits in the screen. The problem is that for the geometry I’m testing with the image is clipped by the screen , and I can’t figure out why.

In my test case the image is a square on the XY plane (i.e. z = 0) with corners (2,2,0), (2,-2,0), (-2,2,0) and (-2,-2,0). The virtual camera is located at (0,2,2), and is aimed (with gluLookAt())at (0,0.764,0), using (0,1,0) for the “up” vector. This centres the image on the screen. I am in full screen mode, with aspect ratio = 4/3.

According to my program, the corners of the square are within +/- 49.6 degrees either side of the aim vector in the “horizontal” direction, and within +/- 31.7 degrees of the aim vector in the “vertical” direction. These numbers imply that the image “width” is limiting, and therefore from fovx = 99.2 I get fovy = 74.4.

But using this value of fovy displays the image (now a trapezium) with the top two corners clipped by the sides of the screen. To fit it into the screen I have to scale fovy by about 1.10.
It would be great (although probably asking too much) if someone could check my fovy value. If anyone is interested I could explain exactly how I derive the angles.

I´m not sure if this is what you want to do, but if you only want the image to be centered on the screen and parallel to it you could do this:

Change to orthographic mode at a “resolution” of 100 * 100 (has nothing to do with the screen resolution, but i don´t know how to call it else).
Now draw your image with the vertices (25,25)
(lower left) and (75,75) (upper right), and it will be centered on screen.

Hope that helps.

In case anyone is interested … I finally figured out the explanation, and it reveals a trap for young players.

The aspect ratio applies to the projected dimensions, not the field-of-view angles - my mistake was thinking I could set fovy = fovx/aspect_ratio in the case when the camera view was being clipped by the sides of the screen rather than by the top and bottom of the screen. I was scaling the horizontal field-of-view angle by 3/4 to get fovy (when the horizontal dimension is limiting). What I should have been doing is this (horizontal and vertical field-of-view angles are in radians):

aspect_ratio = 4.0/3.0;
halfwidth = tan(horizontal_angle/2);
halfheight = tan(vertical_angle/2);
if (halfwidth/halfheight > aspect_ratio) {
// use horizontal angle to set fovy
fovy = 2atan(halfwidth/aspect_ratio);
} else {
// use vertical angle to set fovy
fovy = vertical_angle;
fovy = fovy

In other words, first of all the aspect ratio of the object as viewed by the camera is not the ratio of the field-of-view angles, as I carelessly assumed, but rather it is width/height, where these dimensions are those of the object projected onto a view plane that is normal to the aiming vector. The horizontal and vertical field-of-view angles must first be converted to linear dimensions of width and height (I use a view plane at unit distance from the camera). The ratio width/height is compared with the screen aspect ratio to determine whether width is the limiting dimension, then if so the width is scaled by the screen aspect ratio to get the corresponding height, which is converted back to the vertical field-of-view angle fovy. It seems obvious now, but it caused me to completely rewrite my procedure for determining the field-of-view angles (which made no difference, of course).