Search code examples
openglperspectivefrustum

How to set up OpenGL perspective correction?


I am dealing with an experimental setup where a simple picture is being displayed to a gene-modified fly. The picture is projected on a screen with certain distances to that fly.

Now it's my turn to set up the perspective correction, so that the displayed image, for example a horizontal bar, appears wider in a longer distance to the fly's point of view (experimental setup) . The code now looks like this:

glMatrixMode(GL_PROJECTION);                        
glLoadIdentity();

if(!USEFRUSTUM)
   gluPerspective(90.0f, 2 * width/height, 0.1f, 100.0f);
else
   glFrustum(92.3f, 2.3f, -25.0f, 65.0f, 50.0f, 1000.0f);

The values were entered by someone a few years ago and we figured out they are not accurate anymore. However, I am confused which values to enter or to change to make the projection work properly, because as you can see in the experimental setup the fly's field of view is a bit tilted.

I thought about those values:

  • fovy = angle between a and c
  • measure width and height on the projection screen
  • but what is zNear? Should I measure the distance from fly to the top or the bottom of the screen? I dont't get why somebody entered 0.1f, cause that seems for me too near.
  • How can I know the value of zFar? Is it the maximum distance of an object to the fly?

I got my information on glPerspective from: https://www.ntu.edu.sg/home/ehchua/programming/opengl/CG_BasicsTheory.html I also checked Simplest way to set up a 3D OpenGL perspective projection , but this post doesn't treat my experimental setup, which is the source of my confusion.

Thank you for any help!


Solution

  • This is one of the prime examples where the frustum method is easier to use than perspective. A frustum is essentially a clipped pyramid. Imagine your fly at the tip of a four sided, tilted pyramid. The near value gives the distance to the pyramid's base and the left, right, bottom and top the perpendicular distance of each side of the pyramids base to the tip. It's perfectly reasonable that the tip is "outside" of the base area. Or in case of your fly the center might be just above the "left" edge.

    So assuming your original picture we have this:

    fly frustum

    "Near" gives the "distance" to the projection screen and right (and of course also top, bottom and left) the respective distances of the tip, err, fly perpendicular to the edges of the screen.

    "far" is not important for the projective features and is used solely for determining the depth range.

    So what you can program into is the following:

    double near   = ${distance to screen in mm};
    double left   = ${perpendicular to left screen edge in mm};
    double right  = ${perpendicular to right screen edge in mm};
    double top    = ${perpendicular to top screen edge in mm};
    double bottom = ${perpendicular to bottom screen edge in mm};
    double s = ${scaling factor from mm into OpenGL units};
    double zrange = ${depth range in OpenGL units the far plane is behind near};
    glFrustum(s*left, s*right, s*bottom, s*top, s*near, s*near + zrange);
    

    Keep in mind that left, right, top and bottom may be negative. So say you want a symmetrical (unshifted) view in one direction, that left = -bottom and a shift is essentially adding/subtracting to both the same offset.