Search code examples
c++opengl3drenderhud

The HUD is drawn but the OpenGL 3D scene disappers


I've been through a number of tutorials but still haven't got the hang of how to draw a 2D HUD with a 3D scene without some sort of a disaster happening. I've gathered some sample code from here and here and worked out the order in which matrices have to be treated in a certain way (see here) to achieve exactly what I've set out for. I've worked out a rendering code as shown below:

void render()
{
    //Clear screen
    glClearColor(0.2f, 0.0f, 0.2f, 1.0f); // Clear the background of our window to red  
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW); //Switch to the drawing perspective
    glLoadIdentity(); //Reset the drawing perspective

    // Movement as response to input:
    glTranslatef( cam.getEye().getX(), cam.getEye().getY(), cam.getEye().getZ() ); // Translate our object along the y axis  
    glRotatef( cam.getTheta(), 0.0f, 1.0f, 0.0f ); // Rotate our object around the y axis 
    // No pushing/popping a matrix and no gluLookAt() used here.

    // ==================== Drawing scene here: ======================
    // ...
    // =================================== HUD: ==================================

    glMatrixMode(GL_PROJECTION);

    glPushMatrix();
    //glPopMatrix();

    glLoadIdentity();
    gluOrtho2D(0, winW, 0, winH); //left,right,bottom,top
    glMatrixMode(GL_MODELVIEW);

    //glPushMatrix();
    glPopMatrix();
    glLoadIdentity();

    // drawing the HUD rect here:
    glBegin(GL_QUADS);
        // ...
    glEnd();

    glPopMatrix();
    glPopMatrix();
    //glPushMatrix();
    //glPushMatrix();

    // ===============================================================================
    glutSwapBuffers(); //Send scene to the screen to be shown
}

... but for some reason it only displays my dark-cyan HUD and the 3D scene simply disappeared. What am I doing wrong? What have I missed? I know I'm supposed to push the projection matrix, then the model-view matrix, then do glOrtho2D(), then pop the two matrices off of the stack. That didn't work. I'm tired of fiddling with pushing and popping matrices in a random order.


Solution

  • If your HUD is an overlay as they usually are, you'll probably want to Disable the depth test & potentially depth writes before drawing the HUD Content:

    glDisable(GL_DEPTH_TEST);
    glDepthMask(GL_FALSE);
    

    This way the Z value of the HUD is irrelevant. Don't forget to re-enable before drawing the scene.

    As others have observed, you have matrix stack issues as well. Separate stacks are associated with the projection & modelview matrices. Right now you are pushing projection matrices and popping modelview matrices, so you're overflowing one and underflowing the other. You need to push & pop in the same mode symmetrically. Given that you're starting with a glLoadIdentity() in each mode, you may not need to use the matrix stacks at all.

    EDIT: A more direct answer

    Here's what your render code should probably look like:

    void render()
    {
      //Clear screen
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
      //*************************************************************************
      //* Prepare to render main scene:
      //*************************************************************************
      glEnable(GL_DEPTH_TEST);
      glDepthMask(GL_TRUE);
    
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      gluPerspective(...);
    
      glMatrixMode(GL_MODELVIEW);
      glLoadIdentity();
      glTranslatef( cam.getEye().getX(), cam.getEye().getY(), cam.getEye().getZ() );
      glRotatef( cam.getTheta(), 0.0f, 1.0f, 0.0f );
    
      //*************************************************************************
      //* Draw Main Scene Here:
      //*************************************************************************
    
      // ... 
    
    
      //*************************************************************************
      //* Prepare to render HUD overlay:
      //*************************************************************************
      glDisable(GL_DEPTH_TEST);
      glDepthMask(GL_FALSE);
    
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      gluOrtho2D(...);
    
      glMatrixMode(GL_MODELVIEW);
      glLoadIdentity();
    
      //*************************************************************************
      //* Draw HUD here:
      //*************************************************************************
    
      // ...
    
    
      // Finish the frame:
      glutSwapBuffers(); //Send scene to the screen to be shown
    }
    

    Now, since you'll be adjusting the projection matrix twice during each render call, you should remove gluPerspective() from your resizeWindow() function. Also, I removed the glClearColor() call from the render function--better to set that once at the beginning of the program and forget it. State changes are expensive so you want to avoid them as much as possible.