Zoom to box

I have been trying to mimick the behaviour of gluPickMatrix() in order to achieve the “zoom to box” effect (I’ve seen this method suggested a few times on opengl newsgroups).

By zoom to box, I mean that I select a rectangular area in the window and everything subsequently rendered inside that area fills the entire window.

gluPickMatrix() implementation is simple (in the sgi reference implementation):

// implicit: glMatrixMode(GL_PROJECTION)
/* Translate and scale the picked region to the entire window */
glTranslate( (xb + w/2 - x)/(dx/2), (yb + h/2 - y)/(dy/2), 0);
glScale( w/dx, h/dy, 1);

where:
(xb, yb) = lower left corner of viewport
(w, h) = width and height of viewport
(x, y) = center of new “box”
(dx, dy) = width and height of new box

Now here’s my question:

I understand that the translation in x should be

     (xb + w/2) - x

i.e., the difference between the center of the original viewport and new one * but why the division by dx/2 * ?

I want to understand what is happening fully because I want to be able to any number of subsequent "zoom to box"es and so I need to
accumulate the translation and scaling amounts correctly.

Alternately, can anyone suggest a better/different method to do zoom-to-box (multiple times)?

Thanks much for any help,
Sandeep

P.S. I cannot use gluPickMatrix() directly because in my code, I accumulate any necessary translation and scaling and modify the projection matrix using these values elsewhere.

Another pick method worth a look. Render all your pickable object no lighting, flat shaded, no texture, no blending, no fog, no stenciling, nothing but depth test. Assign a single colour per object to be picked. I pass the index (even the pointer at some point) of the object to the RGBA colour component. you can even index into 16 bits, and fill the remaining 16 bits with some flags and masks.

Render them as you would normally do with flat coloured polygons, or only their bounding volumes, and into a different buffer if you want. Get the pixels on the screen using your rectangle, then scan the pixel colors, and convert those colors back into indices. You can filter objects further by applying masks on the indices you get and flags used.

It’s very flexible, no need to track objects, accurate to a pixel, and you can filter the object you don’t want to pick and you read the pixels only when you want to reduce overhead (after the mouse drag). It’s kind of a trick, and you have to be careful of the pixel format on screen.

Kind of a trick I use on a mouse pick tool, works for me.

[This message has been edited by oliii (edited 03-12-2003).]

jusst read about the glRenderMode(GL_SELECT);

very nice It’s a cleaner solution

In my opinion, it would be much better to use the glFrustum() or gluOrtho2D() directly. Here, you can specify the planes around your screen, that ‘surround’ your screen.

basically, you have your frustum F(l, r, b, t) (left, right, bottom and top planes) defined.

you start with the mouse rectangle on screen
rect(x, y, w, h)

you need some simple linear interpolations to convert your mouse rectangle into the frustum planes.

ix0 = x / ScreenWidth;
iy0 = y / ScreenHeight;
ix1 = (x+w) / ScreenWidth;
iy1 = (y+h) / ScreenHeight;

then your new frustum will be
l’ = l + ix0 * (r-l);
r’ = l + ix1 * (r-l);
b = b + iy0 * (t-b);
t = b + iy1 * (t-b);

All you have to do is save the frustums(l, r, b, t) into a stack, that you can retrieve when you want to zoom out.

Originally posted by oliii:
[b]
In my opinion, it would be much better to use the glFrustum() or gluOrtho2D() directly. Here, you can specify the planes around your screen, that ‘surround’ your screen.

you need some simple linear interpolations to convert your mouse rectangle into the frustum planes.
[/b]

Ah… I was doing that and worked great for orthographic projection – but I simply couldn’t figure out what to do for perspective. Obviously, I would have to do some trickery with the distance of the camera and its field of view (if I only changed the field of view, the image would soon start getting distorted).

That’s why I chose the gluPickMatrix() method; so that I could deal with both cases uniformly. Only, I realized that when I zoomed more than one time, the translations were messed up (i.e., the camera would no longer focus at the center of the zoom box). The scale looked right, though.

regards,
Sandeep

Originally posted by sp:
[b] Ah… I was doing that and worked great for orthographic projection – but I simply couldn’t figure out what to do for perspective. Obviously, I would have to do some trickery with the distance of the camera and its field of view (if I only changed the field of view, the image would soon start getting distorted).

That’s why I chose the gluPickMatrix() method; so that I could deal with both cases uniformly. Only, I realized that when I zoomed more than one time, the translations were messed up (i.e., the camera would no longer focus at the center of the zoom box). The scale looked right, though.

regards,
Sandeep

[/b]

yeah, soz. It’s obviously very specific to a limited number of applications. A ‘bit’ trickier using gluLookAt(). D’oh!

Another way to look at it would be to try to make the near plane area coincide with the rectangle area on the screen. brrr…

Try this http://www.codeproject.com/useritems/opengl_zooming.asp

you might wanna take a look at gluProject()
and gluUnproject()