help with orthographic zoom

Hi all,

I have been trying to support zooming operations in an orthographic projection. I have gotten most of the way in the beginners forum, I’m hoping someone can clarify how to finish this zooming.

I am displaying a bitmap as a texture mapped quad. I want to be able to have the mouse movements over the quad show what actual pixel back in the original bitmap that mouse location corresponds to.

I am using glTranslate() for panning the quad, and glScalef() for ‘fake’ zooming of the quad. I can get the bitmap pixel location by taking the actual windows mouse location and subtracting the pan offset and then dividing by the scale factor, this works really nicely.

So my last problem here is that when I use glScalef(), the scaling happens from the origin (bottom left) of my worldview, so the zooming doesn’t look quite nice (quad grows from lower left corner of the viewport). I would like scale operations to be done around the center of the viewport if possible. Should I just call glTranslate() after each scaling operation to move the quad so it looks like it is remaining in place during the zoom?

Posts in this forum have suggested using glOrtho() to zoom in an orthographic projection instead of glScalef(), which I am not opposed to, but if I use that, how can I still correctly query the original pixel locations when the mouse goes over the quad?

Thanks,
Mark

For your problem of scaling, couldn’t you do Triangle strips and set the orgin at the center, and create the triangle outward. You could even make it in a function or a list then just scale it from there.

glOrtho is your friend, adjust the numbers you call it with.

Are there any pointers how to use glOrtho() to zoom? Right now I only call it once when my viewport gets resized like:

glOrth(0,viewportWidth, 0,viewportHeight, -1,1);

So if I wanted to zoom in 50%, how should I modify that?

And now if I use glOrtho() to zoom, how will I still find what bitmap pix location the mouse is over (when mouse is over the quad) since I am abandoning glScalef()? (Before to get the pix location i would just do ((mouseloc - pan) / scale);

Thanks

glOrtho( -width/2zoom, width/2zoom, -height/2zoom, height/2zoom, -1, 1 );

This will give you a symmetric projection. Width and height are arbitrary with zoom so use whatever makes sense.

If you want to zoom in on the mouse click, you could adjust the eye position by the difference in zoomed clicks.

Hi Hlz,

Ok I swapped in glOrtho() instead, but it too gives the same effect as glScale() in that it looks like everything is being expanded towards the upper right of my viewport from the origin!
I do glOrtho() before all my translations and stuff, is that right?

So if this doesn’t work, is there some way I can issue a glTranslate() after glScale or glOrtho to make it appear as if the zooming in is occurring directly on the center of the viewport, instead of from the origin?

Thanks so much

Can you post the projection and modelview code you have? That’s a lot easier than trying to guess at what’s wrong. This should just work, unless there is something silly afoot…

Hi Hlz,

Thanks for taking a look… I included the one time initialization of my scene, the code that handles resizing of the viewport (always called at least once right at startup), and then my drawing handler. I ommited a lot of code for brevity:

int CMyApp::OnCreate()
{
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
}

void CMyApp::OnSize()
{
    GetClientRect(&m_rc);
    glViewport(0,0,m_rc.right,m_rc.bottom);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, m_rc.right, 0, m_rc.bottom);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void CMyApp::OnDraw()
{
    // ...
    glLoadIdentity();

    // this should account for my scaling...
    glOrtho(-m_rc.right * m_zoom, 
             m_rc.right * m_zoom, 
            -m_rc.bottom * m_zoom,
             m_rc.right * m_zoom, 
             -1, 1); 

    // this accounts for my panning...
    glTranslate(m_xpan, -m_ypan, 1);

    // now i finally draw the quad...
    glBegin(GL_QUADS);
      glVertex3f(0,0,0);
      glVertex3f(256,0,0);
      glVertex3f(256,256,0);
      glVertex3f(0,256,0);
    glEnd();

    SwapBuffers(m_hgldc);
}

So everything gets scaled from the origin when I start zooming,

Thanks again

You’re applying the ortho projection matrix twice, once on the projection matrix stack, again on the modelview stack. Try to keep these things separate, to avoid confusion. You also had a pan in the z (?), and a “right” where a “bottom” would have been better in your ortho call (typo?)…

void CMyApp::OnSize()
{
	GetClientRect(&m_rc);
	glViewport(0,0,m_rc.right,m_rc.bottom);
}

void CMyApp::OnDraw()
{
	// Clear...
 
	// Zoomed projection
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(-m_rc.right * m_zoom, m_rc.right * m_zoom, 
		-m_rc.bottom * m_zoom, m_rc.bottom * m_zoom, 
		-1, 1 ); 
 	
	// Pan camera on modelview
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glTranslate(m_xpan, -m_ypan, 0);
 
	// Now draw the world...
}

Hi Hlz,

Yes your fixes worked perfectly and now the zoom looks like it is really occurring at the center of the viewport.

My mouse over doesn’t work anymore though (this is where if the mouse is over the textured quad, i figure out what pixel the mouse is over in the quad)

I previously had:

void CMyApp::OnMouseMove(int ptX, int ptY)
{
    // for x loc, divide by scale then subtract the panning offset.
    int nMouseLocX = (int)((((float)ptX / m_xScale) - m_xpan));
}

and that worked great when I applied glScalef() then glTranslate().

Now that I am using glOrtho() then glTranslate(), is there anyway to do the same thing? I think my earlier version worked because the quad was drawn from the lower left corner of the viewport, now it is drawn near the center at startup, with 0 pan and 1 zoom.

Thanks

To get the mouse position in world space, use gluUnProject. This will reverse the entire projection process. There’s enough info in the redbook to create such a function yourself, if you should get a hair.