16
\$\begingroup\$

I'm at the stage in my game development where I need to make a HUD or GUI. I've never gotten to this part, so I don't know how its done. I tried rendering a simple quad at a fixed position on the screen, but there's a problem. To make my camera work with orthographic, I use this:

public void lookThrough()
{
    GL11.glMatrixMode(GL11.GL_PROJECTION);
    GL11.glLoadIdentity();
    GL11.glOrtho(position.x, position.x + Display.getDisplayMode().getWidth()/zoom, position.y + Display.getDisplayMode().getHeight()/zoom, position.y, -1, 1);
    GL11.glMatrixMode(GL11.GL_MODELVIEW);
}

I don't see how I would be able to make something fixed on the screen using this method? Any way around this? Thanks :)

\$\endgroup\$
2

1 Answer 1

13
\$\begingroup\$

This is from an old OpenGL-based game engine I was trying to write about seven years ago written in C++ so bare with me as I try to explain how I handled 3D world and 2D GUI rendering operations within it. I used four primary methods within my OpenGL renderer class (OGLRender) of which are:

  • ready3D() for preparing OpenGL to render the 3D world scene.
  • ready2D() for preparing OpenGL to render the 2D GUI.
  • render3D() for the actual 3D world scene drawing.
  • render2D() for the actual 2D GUI drawing.

    void OGLRender::ready3D()
    {
        glViewport(0, 0, m_Setup.width, m_Setup.height);
        glMatrixMode(GL_PROJECTION);
    
        glLoadIdentity();
        gluPerspective(45, (float) m_Setup.width / m_Setup.height, 0.1, 5000.0);
    
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
    
        glDepthFunc(GL_LEQUAL);
        glEnable(GL_DEPTH_TEST);
    }
    
    void OGLRender::ready2D()
    {
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
    
        gluOrtho2D(0.0f, m_Setup.width, m_Setup.height, 0.0f);
    
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslatef(0.375, 0.375, 0.0);
    
        glDisable(GL_DEPTH_TEST);
    }
    
    void OGLRender::render3D()
    {
        this->ready3D();
    
        // ... draw 3D world scene here ...
    }
    
    void OGLRender::render2D()
    {
        this->ready2D();
    
        // ... draw GUI here ...
    }
    

And then in the main thread loop I would basically just call the methods in the following order:

while(m_drawFrame)
{
    gm_Render->render3D(); // draw 3D scene
    gm_Render->render2D(); // draw GUI

    SDL_GL_SwapBuffers(); // make drawn frame visible
}

So, what I am doing is I draw my 3D world scene first and then I draw my GUI last that way the GUI is always on top of the world scene. ready3D() method gets the 3D world projection ready for world scene drawing and ready2D() method gets the 2D ortho scene ready for GUI drawing. m_Setup.width and m_Setup.height are just the view port screen dimensions.

What is special about the ready2D() method is that gluOrtho2D() function is called with arguments that tell it when we draw the GUI primitives we draw them in the screen coordinates specified to match Windows, Mac, and other desktop screen coordinate systems. Such as top-left is (0,0) in (X,Y) format while bottom-right is (ViewportWidth-1, ViewportHeight-1). And glTranslatef() is used to correct for per-pixel accurate positioning. So that when we draw a line from (0,0) through (0,9) then the line will actually draw from the top-left and straight down ten pixels total in length and one pixel width.

Overall you're most likely just interested in what the ready2D() method is doing. I provided the other methods' source code examples to give you an idea as to generally how most games do 3D world scene and GUI drawing order.

\$\endgroup\$
2
  • \$\begingroup\$ Thanks, I just didn't know if switching between ortho and perspective would be bad for performance, because to me it seems like a big operation (of course I barely know how OpenGL works... still learning!) but everywhere I've seen, and what you said, suggest doing this. So I guess I will :) \$\endgroup\$
    – smoth190
    Commented Oct 14, 2011 at 1:35
  • \$\begingroup\$ I like this answer its kinda what i was thinking of doing. I was just wondering though if it could be done better by pushing you projection matrix on each 2D render then popping it after. That would mean you could just setup 3D once surely? Then you would only need to call your 3D setup again for window size changes if you handle that. \$\endgroup\$
    – Lightbulb1
    Commented Mar 31, 2015 at 11:05

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .