I am working on a project that requires that I create a 2D interface rendered "on top" or a 3D world. On some other forums, I read that you could use "GluOrtho2D()" for the job, and switch back to GluPerspective() once you were done. The only thing is, my test code I wrote for it only displays the 3D world, not the 2D quad. When I disable the 3D rendering code, however, the quad appears where it was supposed to be. I trimmed down the code to openGL only statements, which I wrote down below. The code is written in Python using the Pyglet library.
The scene initialization code:
glViewport(0, 0, width, height)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(60.0, float(width)/height, .1, 10000.)
glMatrixMode(GL_MODELVIEW)
glClearDepth(1.0)
glShadeModel(GL_FLAT)
glEnable(GL_DEPTH_TEST)
glDepthFunc(GL_LEQUAL)
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
The frame rendering code. The call to builder.buildMap() creates the 3D scene, and the glBegin-glEnd pair draws a 2D quad:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
stage.set3DMode(window.width, window.height)
builder.buildMap()
stage.set2DMode(window.width, window.height)
glBegin (GL_QUADS)
glVertex2i(0, 0)
glVertex2i(0, 200)
glVertex2i(200, 200)
glVertex2i(200, 0)
glEnd()
the stage.set3DMode function:
glDisable(GL_DEPTH_TEST)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluOrtho2D(0, width, 0, height)
glMatrixMode(GL_MODELVIEW)
and the stage.set3DMode function:
glEnable(GL_DEPTH_TEST)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(60.0, float(width)/float(height), .1, 10000.)
glMatrixMode(GL_MODELVIEW)
I really hope someone can point out my mistake! And thank you for helping me :)
It looks like you don't call glLoadIdentity()
after switching to GL_MODELVIEW. The simplest way to remember is to call it every time you change the projection matrix, switch to GL_MODELVIEW and call glLoadIdentity()
(unless you really want to retain the old one).
I use the following matrices for 2d rendering:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, w, h, 0, 0, 1);
glViewport(0, 0, w, h);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.375f, 0.375f, 0);
A lot of people get it wrong how to use glViewport and the like. They always place it in the reshape callback which is simply wrong.
You always to the full setup in your rendering function, just before you need those settings. So your code should be (pesudocode):
render_scene():
// first clear the whole window
glViewport(0, 0, window.width, window.height)
glClearDepth(1.0)
glClearColor(1., 1., 1., 1.);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
glViewport(3Dstuff.x, 3Dstuff.y, 3Dstuff.w, 3Dstuff.h)
// maybe also set scissor to clip
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(60.0, float(width)/height, .1, 10000.)
glMatrixMode(GL_MODELVIEW)
setup3DstuffModelview()
glDepthFunc(...)
glEnable(GL_DEPTH_TEST)
// other state stuff
render3Dstuff()
// now the 2D stuff
glViewport(2Dstuff.x, 2Dstuff.y, 2Dstuff.w, 2Dstuff.h)
// clear depth and stencil -- if you need parts of the 3D depth / stencil
// for some algorithm retain it or save and restore by FBO renderbuffers or
// glReadPixels, glDrawPixels
glClearDepth(1.0)
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(...)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
setup2DstuffModelview()
glDepthFunc(...)
glDisable(GL_DEPTH_TEST)
// other state stuff
render2Dstuff()
// repeat for all the layers you need
This is really important: OpenGL is a state machine. Unless you can prove that no undetermined state changes happen you always re-/set all the states you need prior to rendering a certain geometry.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With