0

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.

Community
  • 1
  • 1
Andrei
  • 135
  • 5
  • 18
  • 1
    For one thing, you don't want to draw your HUD at z=0 with `gluOrtho2D (...)`. The range of Z values with `gluOrtho2D` is [**-1**,**1**], which puts z=0 square in the middle of the depth buffer. Potentially half of your scene could obstruct the HUD, you would want to draw at z=-1 to ensure the HUD is always on top of everything else. In case you were wondering where Z comes from in this situation, `glVertex2f` applies a constant Z coordinate of **0.0** and W coordinate of **1.0** to all vertices. – Andon M. Coleman May 07 '14 at 00:35
  • 3
    Much more serious, however, you are underflowing your matrix stack with all of those unpaired `glPopMatrix (...)` calls. – Andon M. Coleman May 07 '14 at 00:37
  • @AndonM.Coleman : OK, I've rewritten a line to `gluOrtho2D(-0.5, 0.5, -0.5, 0.5);` and I already see an object that's supposed to be sitting on y=0, but for some reason my camera eye is fixed at y=0. And the HUD is drawn at a different location. However, that's not the kind of view I wanted. I can't see the plane and the pyramid as objects in a 3D scene. Also, I've paired up the push/pop commands as follows: push projection, push model-view, pop matrix, pop projection. Nothing is working so far. – Andrei May 07 '14 at 00:48
  • Are you setting the perspective projection matrix in a different part of the code? If not you need to set a perspective projection when you draw the 3D objects or they won't look 3D. Also I'm not sure how your camera is set up but typically you want to translate by the negative eye position. – user3256930 May 07 '14 at 02:01
  • Also, since I am underflowing the matrix stack, I've decided to use the PushStack class to do some indirect pushing, but my glutil is missing boost/array.hpp . So, now I don't know how I'm supposed to push on and pop off the stack. – Andrei May 07 '14 at 02:39
  • @user3256930 : I already have gluPerspective() in the resizeWindow() callback function, so I guess I don't have to call gluPerspective() again. And the camera is indeed set up with the negative eye position. – Andrei May 07 '14 at 02:49

1 Answers1

3

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.

Drew Hall
  • 28,429
  • 12
  • 61
  • 81
  • I presume after the whole thing I have to set glDepthMask to GL_FALSE, correct? Also, what would you recommend for handling the matrix stack? I've tried PushStack but it didn't work, and I can't underflow the stack. What should I do? – Andrei May 07 '14 at 04:36
  • I've tried your advice of disabling the depth test and buffer writing before rendering and then enabling them. I still can't get my scene back in its original state. – Andrei May 07 '14 at 05:28
  • Correct about glDepthMask--fixed in my answer. Also see my new text re: matrix stacks. Good luck! – Drew Hall May 07 '14 at 05:54
  • 1
    I've read your updated answer, but it seems that I'm left with this code in my OP's update, with which I still don't get a 3D scene, even though the HUD is there. – Andrei May 07 '14 at 16:20
  • @Andrey: I just laid it out for you in my edit. Give it a try and let us know how it goes. – Drew Hall May 07 '14 at 17:05
  • It worked ... but when I allow for enabling/disabling the depth mask in the places you wrote those lines in, everything disappears but the HUD, and when I move my camera eye forward, the pyramid flickers. So I commented out those depth-mask-related lines and left the ones related to depth test. I also updated the code in the OP just in case. – Andrei May 13 '14 at 19:19