Thursday, March 3, 2016

java - Making a HUD/GUI with OpenGL (LWJGL)


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 :)



Answer



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.


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...