Flipped Z Axis in Simple World

Dear all, I have a simple piece of OpenGL code without any elaborate transformations or projections as below. Given the projection matrix is set to identity, and the modelview matrix is also set to identity before drawing the 3 triangles, I would expect the Z axis to be the default Z- axis pointing into the screen. However, upon rendering this code, it shows as if the Z+ axis is pointing into the screen (see rendering screenshot). Please advise, do I misunderstand something? Is the code actually consistent with the rendering screenshot? Thank you!


void initializeGL()
{
    glEnable(GL_CULL_FACE);
    glEnable(GL_DEPTH_TEST);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void resizeGL(int w, int h)
{
    glViewport(0,0,w,h);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glClearColor(0.0, 0.0, 1.0, 1.0);      //blue background

    //test
    glBegin(GL_TRIANGLES);
        glColor4f(1.0f, 0.0f, 0.0f, 1.0f);  //red
        glVertex3f(-1.0f, -1.0f, 0.2f);
        glVertex3f(1.0f, -1.0f, 0.2f);
        glVertex3f(0.0f, 1.0f, 0.2f);

        glColor4f(0.0f, 1.0f, 0.0f, 1.0f);  //green
        glVertex3f(-1.0f, -1.0f, 0.5f);
        glVertex3f(1.0f, -1.0f, 0.5f);
        glVertex3f(0.0f, 1.0f, 0.5f);

        glColor4f(1.0f, 1.0f, 0.0f, 1.0f);  //yellow
        glVertex3f(-1.0f, -1.0f, 0.1f);
        glVertex3f(1.0f, -1.0f, 0.1f);
        glVertex3f(0.0f, 1.0f, 0.3f);
    glEnd();
}

[ATTACH=CONFIG]1210[/ATTACH]

No, this looks like Z- axis is pointed into the screen.

Please explain why you don’t think so.

By default, the “depth” value written to the depth buffer and used for depth testing is proportional to the Z coordinate in normalised device coordinates (NDC), i.e. increasing Z results in increasing depth. With the default depth function of GL_LESS, this results in fragments with greater Z being obscured by fragments with lesser Z (i.e. greater Z appears farther away).

Conventionally, eye space has negative Z corresponding to increasing depth, i.e. a lower Z value is farther away. This convention is achieved by having the functions which are commonly used for generating projection matrices (glOrtho, glFrustum, gluOrtho2D and gluPerspective) either negatve the Z coordinate (for orthographic projections) or set the W coordinate to -Z (for perspective projections), effectively “flipping” the direction of the Z axis.

If you want the projection matrix to be an identity matrix except for the “conventional” Z flip, use


glLoadIdentity();
glOrtho(-1,1,-1,1,-1,1);

This will result in the matrix:


[ 1  0  0  0 ]
[ 0  1  0  0 ]
[ 0  0 -1  0 ]
[ 0  0  0  1 ]

[QUOTE=Dark Photon;1277892]No, this looks like Z- axis is pointed into the screen.

Please explain why you don’t think so.[/QUOTE]

For the red triangle, the Z value is 0.2f.
For the green triangle, the Z value is 0.5f.
For the yellow triangle, the Z value ranges from 0.1f to 0.3f.
If the Z- axis is pointed into the screen, I’d expect the triangle with the largest positive Z value to be in front (i.e., only green triangle will be shown), covering up the red and yellow triangles at the back. But in my rendering result, it is the opposite: the green triangle is completely hidden by the red and yellow triangles. Is that not the right way of interpreting it?

[QUOTE=GClements;1277893]By default, the “depth” value written to the depth buffer and used for depth testing is proportional to the Z coordinate in normalised device coordinates (NDC), i.e. increasing Z results in increasing depth. With the default depth function of GL_LESS, this results in fragments with greater Z being obscured by fragments with lesser Z (i.e. greater Z appears farther away).
[/QUOTE]

That makes sense. So in short, could I say that by default, the identity matrix for projection matrix in OpenGL starts a left-handed coordinate system, in contrast to the conventional right-handed coordinate system?

I’m also confused at the fact that even though the default camera/eye location is at (0,0,0) looking down into the screen (Z- axis direction), the rendered screen actually show objects with Z values range from -1 to 1 (e.g., if the Z value of the triangles in my code is changed to between 0 and -1, which is supposed to be behind the camera/eye). In this case for my code, where is actually the location of the camera/eye?

Clip space and “conventional” eye space have opposite handedness (i.e. the conventional projection matrices all have a negative determinant). Anything beyond that is interpretation. E.g. you can make clip space appear right handed by using glDepthRange(1,0) or by using glDepthFunc(GL_GREATER).

[QUOTE=deltayoung;1277895]
I’m also confused at the fact that even though the default camera/eye location is at (0,0,0) looking down into the screen (Z- axis direction), the rendered screen actually show objects with Z values range from -1 to 1 (e.g., if the Z value of the triangles in my code is changed to between 0 and -1, which is supposed to be behind the camera/eye). In this case for my code, where is actually the location of the camera/eye?[/QUOTE]
Using an identity matrix for the projection results in an orthographic projection, where the view doesn’t have a position, only a direction. The near and far planes will be at -1 and 1 respectively.

Thanks for the tips!
I tried glDepthFunc(GL_GREATER), but strangely it resulted in the screen is shown with all background (all blue) only. Does it mean the background is taken into account as the one with most positive Z value?

[QUOTE=deltayoung;1278427]
I tried glDepthFunc(GL_GREATER), but strangely it resulted in the screen is shown with all background (all blue) only. Does it mean the background is taken into account as the one with most positive Z value?[/QUOTE]
If you use glDepthFunc(GL_GREATER), you also need to use glClearDepth(0.0). The initial value is 1.0, which will result in all depth values generated by rendering being less than or equal to the initial value (which is fine for GL_LESS but wrong for GL_GREATER).

That did it. Thanks a lot for your help!