4

The code below creates 2 square polygons, red and green.
I'm trying to place a red square on top of the green, but I can't.
The depth buffer is declared, cleaned when necessary, an orthogonal system is configured correctly.
If I specify a value outside the range (2;-2), the polygon disappears as it should.

#include <...>

constexpr auto FPS_RATE = 120;
int windowHeight = 600, windowWidth = 600, windowDepth = 600;

void init();
void idleFunction();
void displayFunction();
double getTime();

double getTime()
{
  using Duration = std::chrono::duration<double>;
  return std::chrono::duration_cast<Duration>(
    std::chrono::high_resolution_clock::now().time_since_epoch()
    ).count();
}

const double frame_delay = 1.0 / FPS_RATE;
double last_render = 0;

void init()
{
  glutDisplayFunc(displayFunction);
  glutIdleFunc(idleFunction);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(-windowWidth / 2, windowWidth / 2, -windowHeight / 2, windowHeight / 2, 2, -2);
  glClearColor(0.0, 0.0, 0.0, 0.0);
}

void idleFunction()
{
  const double current_time = getTime();
  if ((current_time - last_render) > frame_delay)
  {
    last_render = current_time;
    glutPostRedisplay();
  }
}

void displayFunction()
{
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glPushMatrix();
  //move the red square to the foreground
  glTranslatef(-32.5, -32.5, 2);
  glColor3f(1, 0, 0);
  glBegin(GL_POLYGON);
  glVertex3i(-150, 150, 0);
  glVertex3i(150, 150, 0);
  glVertex3i(150, -150, 0);
  glVertex3i(-150, -150, 0);
  glEnd();
  glPopMatrix();
  glPushMatrix();
  //move the green square to the background
  glTranslatef(32.5, 32.5, -2);
  glColor3f(0, 1, 0);
  glBegin(GL_POLYGON);
  glVertex3i(-150, 150, 0);
  glVertex3i(150, 150, 0);
  glVertex3i(150, -150, 0);
  glVertex3i(-150, -150, 0);
  glEnd();
  glPopMatrix();
  glutSwapBuffers();
}

int main(int argc, char* argv[])
{
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
  glutInitWindowSize(windowWidth, windowHeight);
  glutInitWindowPosition((GetSystemMetrics(SM_CXSCREEN) - windowWidth) / 2, (GetSystemMetrics(SM_CYSCREEN) - windowHeight) / 2);
  glutCreateWindow("Window");
  init();
  glutMainLoop();
  return 0;
}
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
German
  • 321
  • 1
  • 7

1 Answers1

4

You've to enable the Depth Test:

glEnable( GL_DEPTH_TEST );

The default depth test function (glDepthFunc) is < (GL_LESS).
If the distance to the far plane is 2.0 and the geometry is drawn with z coordinate of 2.0, then the geometry is clipped by the far plane, because the depth of the geometry is not less than the initialization depth of the depth buffer.

Change the depth function to <= (GL_LEQUAL):

glDepthFunc( GL_LEQUAL );

In a Right-handed system the viewspace z-axis points out of the viewport. So if the z coordinate is "less than", then the object is "behind" an other object.

The projection matrix transforms from view space to normalized device space. In compare to the view space, the normalized device space is a left handed system, where the z-axis points in the viewport. The normalized device z-coordinate in range [-1, 1] (from the front to the back), is mapped to the depth value (in general in range [0, 1]), which is used for the depth test.
To deal with that glOrtho inverts the z-axis, if the near parameter is set less then the far parameter (this is how the function is suggested to be used).
This cause that the depth (z) order doesn't change, when the geometry is transformed form view space to normalized device space.

Note, glOrtho(-w, w, -h, h, -z, z) is the same as glScaled(1.0/w, 1.0/h, -1.0/z)

Since the z-axis is not inverted by the orthographic projection in your example, because near > far,

glOrtho(-windowWidth / 2, windowWidth / 2, -windowHeight / 2, windowHeight / 2, 2, -2);

the z coordinate has to be greater, to be "behind".

If the green rectangle should be behind the red one, then you've to change the orthographic projection (near < far). e.g.:

glOrtho(-windowWidth / 2, windowWidth / 2, -windowHeight / 2, windowHeight / 2, -2, 2);

If you don't want to change the projection, then you've to swap the z-coordinates of the geometry:

glPushMatrix();
//move the red square to the foreground
glTranslatef(-32.5, -32.5, -2.0); // foreground because near > far
// ...
glPopMatrix();

glPushMatrix();
//move the green square to the background
glTranslatef(32.5, 32.5, 2.0);   // background because near > far
// ...
glPopMatrix();
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • @Герман Of course, see the middle section of the answer. – Rabbid76 Jul 09 '19 at 18:26
  • thanks for your help. You said that in my example the Z-axis is inverted, why? I after all pointed out that near(near me part of system) equal 2, and far -2, means - than the number of Z less, those object further from me. Why not? – German Jul 09 '19 at 18:46
  • @Герман The view space is a right handed system. -z is in the back and +z in the front. In this system the object is drawn. The projection matrix transforms from view space to normalized device space. The normalized device is a right handed system. When you set a projection by `glOrtho` where near < far, then the z axis is inverted and the depth order doesn't change. But when near > far, then the z axis is not inverted and the depth order changes. – Rabbid76 Jul 09 '19 at 18:55
  • @Герман The explanation was incomplete. I extended that part of the answer and tired to explain that non intuitive and probably unexpected behaviour. – Rabbid76 Jul 09 '19 at 19:09