Placing a scene, in perspective projection

Hello all,

I have had a problem that has been torturing me for a day now. I have many objects that I draw together in the screen. They have a standard z Axis length of 10 units, a variable width length and a variable height length. My goal was to make sure that before drawing the scene, the modelview matrix was translated properly to view the scene centered no matter the width and height of the viewport/window.

So basically the point was to figure out how to calculate the glTranslatef(0,0,Z) value.

The perspective projection was set up like this:

``````        gluPerspective(angle,e->width/e->height,1,e->pixelLength);
``````

Where width and height is the width and height of the viewport and is updated with resizing, and pixel length is basically the width of the whole scene in units. Angle was always 45.0.

I blame my lack of precise understanding of the math behind the perspective projection for this, but I went through a lot of trial and error and figured out this value.

``````glTranslatef(0,0,(-e->pixelLength*1.22)/aspectRatio)
``````

Aspect ratio above is the e->width/e->height of the viewport. The above seemed to be working for every scene and made me quite happy but still I did not understand why.

Then I noticed that it stopped working whenever the angle changed, so I realized 1.22 depends on the angle. That lead me to remember that 1.22 is the 90 deg - the arctan of 45.
So that lead to the final results of:

``````
float val = 90.0 - (atanf(angle))*(180.0/_PI_);
glTranslatef(0,0,(-e->pixelLength*val)/ascpectRatio);

``````

And this seems to work all the time for any angle. It is quite interesting how I was lead to this result, but still I do not understand the perspective projection mathematics totally and am not actually sure why this works.

Can anyone enlighten me with the math behind the perspective projection and maybe help explain why this works? And of course if there is a better way to do it, (which I suspecte exists) can you explain it to me?

Thanks a lot for your time.

For a thorough mathematical derivation of the perspective projection in OpenGL you may look at http://www.songho.ca/opengl/gl_projectionmatrix.html.

Also, if you have access to Lengyel’s 3D math textbook there’s a very good derivation as well.

What would interest me is why you’re updating the model matrices and not simply adjust the position/orientation of the camera and the view frustum?

Thanks a lot for your reply. I made a typo in the original post. I wanted to mean move the perspective matrix, not the modelview and hence adjust the camera.

Thanks for the links, I will check them out and hopefully get a better understanding

Since I can’t edit the original post let me rephrase the question.

Much like this msdn article (but I guess converted to openGL)

I would like to manage to position the camera to view all objects in a scene. But the problem I have is the viewport aspect ratio. I want the camera to be always positioned in any viewport (so any resize of the window) to just encompass the whole scene, no more no less.

Quoting the article:

Determine the distance from the center of the BoundingSphere that the camera needs to be to view the entire scene. This distance is equal to the hypotenuse of the triangle formed by the center of the sphere, the desired camera position, and the point where the sphere touches the view frustum. One angle of the triangle is known to be the field of view of the camera divided by two. One leg of the triangle is known to be the radius of the sphere. Given these two measurements, you can calculate the hypotenuse as the radius of the sphere divided by the sine of half the field of view.

``````
float distanceToCenter = sceneSphere.Radius / (float)Math.Sin( FOV / 2 );
``````

That seems to be the correct distance from the center of the scene, but in the article they have a set aspect = 800/600. What I need is the position that the camera should be (let’s call it the distance from the center ) so that it will encompass the whole scene, no matter the aspect ratio. So whenever we resize the window what we are viewing should always be the entire scene.

So if we assume that the scene is built around the origin I want the value of Z in gluLookAt(0,0,Z, 0,0,0, 0,1,0);
Anyone has any ideas?

I’m looking into the same issue.
I can easily position the model into the centre of the view fustrum. The problem is that it does not take the view port dimensions into account, thus some of the model is clipped when using a smaller viewport.

Here’s the psedo code to do the first part - render to the centre of the view fustrum.

//Assuming a simple shift parallel to the positive z-axis in world coordinates, one possible camera position and direction can be computed by:
camera_distance := avg_BBOX_radius / tan(fov / 2);
cam_eye = bbox_centre + camera_distance * (0, 0, 1)
cam_view = bbox_centre - cam_eye / |bbox_centre - cam_eye| (normalized)

Now, how to take the viewport into account?

It’s not the viewport that matters so much as the aspect ratio of your frustum (which in many cases matches the aspect ratio of the viewport). So in the above calculation, the angle fov needs to be the smaller of the vertical or horizontal fov angles.

Hmm this seems to be an interesting problem then. I am a bit confused though. Let’s try to reiterate what has been said.

BionicBytes, in your calculations what is cam_view? And where is it used exactly?

Taking into account all that has been said, let’s see some code again. We have a a viewport with same aspect ratio as the perspective projection. We have a scene with a calculated bounding box radius.

The goal is to make sure that at all times, and all resizes of the window/viewport we always see the full scene, as far as it can be zoomed in to be encompassed by the view.

``````
//setting up the angle as carsten neuman suggested
float angleY = 45.0f;
float aspect = e->width/e->height;
float angleX = aspect*angleY;
float angle = angleX;
if(FLCMP_L(angleY,angleX))//just a float comparison macro
angle = angleY;

//perspective setup
glMatrixMode(GL_PROJECTION)
gluPerspective(angleY,aspect,1,farZ);

glMatrixMode(GL_MODELVIEW);
0,0,0,
0,1,0);

``````

The above does not seem to be working correctly. What is it that I do not understand? Also if some transformations happens to the view, just right after gluLookAt(), say a rotation of the view around the x axis, would the calculated result for gluLookAt() still be usable or not?

BionicBytes, in your calculations what is cam_view? And where is it used exactly?

Cam_view is the camera view vector, which is used in
gluLookat (Cam_eye.x,Cam_eye.y,Cam_eye.z,
cam_view.x,cam_view.y,cam_view.z,
0,1,0)

camera_distance := avg_BBOX_radius / tan(fov / 2);
cam_eye = bbox_centre + camera_distance * (0, 0, 1)
cam_view = bbox_centre - cam_eye / |bbox_centre - cam_eye| (normalized)

cam_eye is the eye position of the camera, ie the world space position.

The above does not seem to be working correctly. What is it that I do not understand

What seems to be happening? You need to have ensured you are calculating all those variables correctly.
EG, camera_distance := avg_BBOX_radius / tan(fov / 2);
where FOV = camera FOV * DEG_TO_RAG

Also if some transformations happens to the view, just right after gluLookAt(), say a rotation of the view around the x axis, would the calculated result for gluLookAt() still be usable or not?

Not following you. You say you have calculated the camera with glulookat (using the above calculations?), then you are changing the camera’s view vector. If that’s the case, then you won’t be looking directly at the model any more.

Oh I see, sorry I am used to referring to this vector as the point we are watching so I misunderstood what you were referring to.

As for it not working, I meant that it does not work for all the different viewports and as you said some of the scene is clipped in smaller viewports.

Not following you. You say you have calculated the camera with glulookat (using the above calculations?), then you are changing the camera’s view vector. If that’s the case, then you won’t be looking directly at the model any more.

Yeah you are right, sorry. Just was pondering a certain translation of my scene, but after writing that post I realized it has to do with translating the model itself so it’s totally irrelevant. Just forget I even asked that