gluPerspective and rotation

This topic is 2945 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

I have my projection matrix setup the following way:

#define FOV 15.0f #define NEAR_PLANE 1.0f #define FAR_PLANE 20.0f gluPerspective(FOV, g_displayScreen->DisplaySize.width / g_displayScreen->DisplaySize.height, NEAR_PLANE, FAR_PLANE);

My problem is when the device rotates from portrait mode to landscape the width and height are swapped changing the aspect ratio. While my camera is still at the same distance from Z=0 it appears to zoom out. If I use the same aspect the display is stretched.

How do I manage the rotation but have the display appear to be the same distance from the camera visually?

I've tried

glViewport(0, 0, g_displayScreen->DisplaySize.height, g_displayScreen->DisplaySize.height);

But it doesn't make any difference.

Share on other sites

I have my projection matrix setup the following way:

#define FOV                    15.0f #define NEAR_PLANE            1.0f #define FAR_PLANE            20.0f gluPerspective(FOV, g_displayScreen->DisplaySize.width / g_displayScreen->DisplaySize.height, NEAR_PLANE, FAR_PLANE);

My problem is when the device rotates from portrait mode to landscape the width and height are swapped changing the aspect ratio. While my camera is still at the same distance from Z=0 it appears to zoom out. If I use the same aspect the display is stretched.

I've tried

glViewport(0, 0, g_displayScreen->DisplaySize.height, g_displayScreen->DisplaySize.height);

But it doesn't make any difference.

I'm sure your "g_displayScreen->DisplaySize.width" and "g_displayScreen->DisplaySize.height" are integer types. But you must know that dividing integers and floating points units in C++ like (1/2) are not equal... where (integer returns 0 and floating point with 1.0f/2.0f returns 0.5f). So, you need to convert these types from integer to floating point:

gluPerspective(FOV, double(g_displayScreen->DisplaySize.width) / double(g_displayScreen->DisplaySize.height), NEAR_PLANE, FAR_PLANE);
Is your camera setting starts from identity matrices? (projection, modelview)

-me

Share on other sites

I'm sure your "g_displayScreen->DisplaySize.width" and "g_displayScreen->DisplaySize.height" are integer types.

The're actually floating point types (a SizeF struct made of width and height floats to be exact)

Is your camera setting starts from identity matrices? (projection, modelview)

Yes the camera starts from an identity matrix which is then just a glTranslatef in the modelview matrix.

So when I rotate the iPhone from portrait to landscape the device rotates the view and I swap the DisplaySize width and height values. The display is fine apart from it being "zoomed out" more.

Some hardware specific information.. I am using a UIViewController to rotate the view. If I custom rotate using glRotate I can keep the ratio in the gluPerspective() call the same. So rotating that way is fine; the camera appears at the same distance when I rotate the device from portrait to landcape. But I need to add a view over the top of my EAGLView (OpenGL view) and so I want the UIViewController to take care of rotation. This means the actual view is rotating and so I need to modify the ratio accordingly. This causes the display to appear "zoomed out" more in landscape mode even though the distance of the camera is the same as it was in portrait. It must be the calculation of ratio as I don't modify the viewport or anything else. I'm just wondering if there is a simple way to maintain the viewable distance after the rotation preferably without manually translating the camera further out in landscape mode.

Share on other sites
I think you just need to adjust your fov for each mode, since the view height changes.

Share on other sites

I think you just need to adjust your fov for each mode, since the view height changes.

It seems like it would be something like that. So I wonder what formula I could use to calculate the new FOV?

Share on other sites
You can look at the figure 3-12 in the Red Book as a reference. If you know your trigonometry, you can see that the field of view is twice the angle of the ratio between the near plane distance and half the near plane height. So, to step through the process with that in mind, it goes like this
1. Calculate the half-height of the near plane given the near plane distance and the FOV: height=near*tan(FOV/2)
2. The new height of the rotated screen is scaled by the aspect ratio: newheight=aspect*height
3. Calculate the new FOV from the new height and the near plane distance: newFOV=atan(newheight/near)*2
That should be it, though I may have some division or multiplication the wrong way. Just double check the formulas. Note that you can cancel the multiplication and the division by near, the angles must be of the correct unit (radians vs. degrees), and that you need to reverse the aspect ratio calculation to gluPerspective as well (the aspect ratios between landscape and portrait are reciprocal).

Share on other sites
Thanks Brother Bob you were a great help. Out of interest here is the solution.

[source]float aspect = g_displayScreen->DisplaySize.width / g_displayScreen->DisplaySize.height;

if(g_displayScreen->IsVertical)
{
gluPerspective(FOV, aspect, NEAR_PLANE, FAR_PLANE);
}
else
{
float tangent = tanf(FOV * PI / 180.0f / 2.0f);
float height = NEAR_PLANE * tangent;
float width = height * aspect;
float fov = 2.0f * atanf(width * 0.5f / NEAR_PLANE) / PI * 180.0f;
gluPerspective(fov, aspect, NEAR_PLANE, FAR_PLANE);
}[/source]

• Game Developer Survey

We are looking for qualified game developers to participate in a 10-minute online survey. Qualified participants will be offered a \$15 incentive for your time and insights. Click here to start!

• 13
• 30
• 9
• 16
• 12