Question

I have an OpenGL application which implements navigation functions such as Orbit, Walk, Pan, Rotate, etc. for navigating a 3D environment. All this works flawlessly and is fairly straighforward to set up using gluPerspective and gluLookAt.

glMatrixMode GL_PROJECTION
   glLoadIdentity
   gluPerspective m_ViewAngle, m_AspectRatio, m_ClipDistance_Near, m_ClipDistance_Far          

   glMatrixMode GL_MODELVIEW
   glLoadIdentity
   gluLookAt m_Eye.X, m_Eye.Y, m_Eye.Z, m_Focus.X, m_Focus.Y, m_Focus.Z, m_ViewUP.X, m_ViewUP.Y, m_ViewUP.Z

   glCallList DisplayListIndex

Similar to a typical ZoomExtents or ZoomToFit command in CAD software, from any arbitrary viewpoint (view direction), I would like to be able to zoom so that (1) The entire 3D environment is visible, and (2) The 3D environment model fills the entire viewport (is as large as possible given the current size of the viewport).

I know the bounding box (extents) of the environment (min XYZ, max XYZ). However, I have been unable to derive what the Eye and Focus positions should be for the given ViewAngle and AspectRatio and environment extents.

Perhaps there's an easier way to accomplish this, than with gluLookAt. Any help is appreciated!

Was it helpful?

Solution

Actually it can be done much 'easier'.

What you need to do is a projection of your model to a plane. Then, determine the highest and lowest points (top y, bottom y, leftmost x, rightmost x), and finally determine how much scaling you need to fit this rectangle in the rectangle you'd actually need.

The plane you need to project on is the screen plane.

Luckily for you, you are already doing this.

So, transform every point of your model using the matrices you already have set, and determine the maximum points.

Calculate how much scaling you'd need to fit it on the screen. And apply this scaling to the zoom of the object

Thats it

OTHER TIPS

Approximate the whole thing to be a sphere and apply the following formula multiplied divided by pixel-to-model-unit ratio. You can calculate the pixel-to-model-unit ratio by rendering a unit sphere at known z coordinate. Good thing about a sphere is that its width is always going to be diameter regardless of where you look from. See perspective projection for details.

alt text

Edit: The good thing about sphere is that it's independent from directions. Regardless of box or sphere you need to specify the direction of camera vector and the up vector. Once you have that, the only unknown is the depth z from the eye's point of view. From there you can calculate the position of the eye by:

 eye := (center.x, center.y, center.z) - depth * (camera.x, camera.y, camera.z)

From the formula, Bx := Ax * Bz / Az You can derive Bz := Bx * Az / Ax.

Let me define a model coordinate 1.0 to be 1.0m. Suppose sphere of radius 1.0m from distance 100.0m looks 20 pixels wide.

Bz := 1.0 * 100.0 / 10
Bz := 10.0

Now let's say your bounding box is 200.0m wide, which makes Ax to be 100.0, and your screen width is 1024pixel, which makes Bx 512pixel.

Az := (Ax / Bx) * Bz
Az := (100.0/512.0) * 10.0
Az := 1.953m

In the above the unit conversion betwen m and pixel is being absorbed by Bz.

Suppose the up vector is (0, 0, 1), camera vector is (1, 0, 0), and the center is (0, 0, 0).

eye := center - depth * camera
eye := (0, 0, 0) - 1.953 * (1, 0, 0)
eye := (-1.953, 0, 0)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top