Search code examples
c++openglglut

OpenGL depth test is not working


I am trying to create a model using OpenGL, and I tried to enable depth testing.

I use these commands in my main:

glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glEnable(GL_DEPTH_TEST);

And this in my display:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

I even tried adding:

glDepthFunc(GL_LEQUAL);

And it doesn't work. I can still see what I think are depth problems. Here is a video showing the problem: https://www.youtube.com/watch?v=OafrRH4Mzjc

  • Note: In that video, the board is build right to left, top to bottom, so the first angle is OK, but any other angle is bad.

What am I missing?


Edit: Minimal example file of reproduction:

#define _CRT_SECURE_NO_WARNINGS

#define SIZE_MOVES 17

#include <stdio.h>

/* Include the GLUT library. This file (glut.h) contains gl.h and glu.h */
#include <GL\glew.h>
#include <GL\freeglut.h>

static int  left_click = GLUT_UP;
static int  right_click = GLUT_UP;
static int  xold;
static int  yold;
static float rotate_x = 146;
static float rotate_y = -26;

int width, height;

GLfloat light_ambient[] = { 0.0, 0.0, 0.0, 1.0 };
GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat light_position[] = { 0, 5, -10, 0 };

GLfloat mat_specular[] = { 0.3, 0.3, 0.3, 1.0 };
GLfloat mat_shininess[] = { 1 };


// colors
const GLfloat colors[2][4] = {
    { 1.0, 1.0, 1.0, 1.0 }, //white
    { 0.0, 0.0, 0.0, 1.0 } //black
};

// rgb
const GLfloat rgb[3][4] = {
    { 1.0, 0.0, 0.0, 1.0 },
    { 0.0, 1.0, 0.0, 1.0 },
    { 0.0, 0.0, 1.0, 1.0 }
};

void resetMaterial() {
    GLfloat c[] = { 1, 1, 1, 1 };
    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, c);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
}

void drawSquare(int color) {
    glPushMatrix(); {
        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, colors[color]);

        glScalef(1, 0.5, 1);
        glutSolidCube(1);
    } glPopMatrix();
}

void drawBoard() {
    for (int i = 0; i < 8; i++)
        for (int j = 0; j < 8; j++) {
            glPushMatrix(); {
                glTranslatef(i + 0.5, 0, j + 0.5);
                drawSquare((i + j) % 2);
            } glPopMatrix();
        }
}

void drawAxes() {
    glBegin(GL_LINES); {
        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, rgb[0]);
        glVertex3f(-2, 0, 0); glVertex3f(5, 0, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, rgb[1]);
        glVertex3f(0, -2, 0); glVertex3f(0, 5, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, rgb[2]);
        glVertex3f(0, 0, -2); glVertex3f(0, 0, 5);
    } glEnd();
}

void letThereBeLight() {
    /*Add ambient light*/
    GLfloat ambientLight[] = { 0.2f, 0.2f, 0.2f, 1.0f };
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight);

    /*Add positioned light*/
    GLfloat lightColor1[] = { 0.2f, 0.2f, 0.1f, 1.0f };
    GLfloat lightPosition1[] = { -8, 8, 5, 0.0f };

    glLightfv(GL_LIGHT0, GL_SPECULAR, lightColor1);
    glLightfv(GL_LIGHT0, GL_POSITION, lightPosition1);

    /*Add directed light*/
    GLfloat lightColor2[] = { 0.3, 0.3, 0.3, 1.0f };
    GLfloat lightPosition2[] = { 8, 8, -5, 1.0f };
    glLightfv(GL_LIGHT1, GL_AMBIENT, lightColor2);
    glLightfv(GL_LIGHT1, GL_POSITION, lightPosition2);
}

void display(void) {
    // Clear frame buffer and depth buffer
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Set up viewing transformation, looking down -Z axis
    glLoadIdentity();
    gluLookAt(0, 5, -15, 0, 0, 3, 0, 1, 0);

    letThereBeLight();

    resetMaterial();

    // Rotate view:
    glPushMatrix(); {
        glRotatef(rotate_y, 1, 0, 0);
        glRotatef(rotate_x, 0, 1, 0);

        glLightfv(GL_LIGHT0, GL_POSITION, light_position);

        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, colors[0]);

        glPushMatrix(); {
            glTranslatef(-4, 0, -4); // Move to center
            drawBoard();
        } glPopMatrix();

        drawAxes(); // For debuging
    } glPopMatrix();

    /* End */
    glFlush();
    glutSwapBuffers();
}

void mouseFunc(int button, int state, int x, int y) {
    if (GLUT_LEFT_BUTTON == button)
        left_click = state;

    xold = x;
    yold = y;
}

void motionFunc(int x, int y) {
    if (GLUT_DOWN == left_click) {
        rotate_y = rotate_y + (y - yold) / 5.f;
        rotate_x = rotate_x + (x - xold) / 5.f;
        glutPostRedisplay();
    }

    xold = x;
    yold = y;
}


void reshapeFunc(int new_width, int new_height) {
    width = new_width;
    height = new_height;

    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(50, width / height, 1, 20);

    glMatrixMode(GL_MODELVIEW);

    glutPostRedisplay();
}

int main(int argc, char **argv) {
    /* Creation of the window */
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
    glutInitWindowSize(900, 600);
    glEnable(GL_DEPTH_TEST);

    glutCreateWindow("Chess");

    glEnable(GL_CULL_FACE);
    glCullFace(GL_BACK);

    glEnable(GL_POLYGON_SMOOTH);
    glEnable(GL_LINE_SMOOTH);

    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_LIGHT1);
    glShadeModel(GL_SMOOTH);
    glDisable(GL_COLOR_MATERIAL);

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    /* Declaration of the callbacks */
    glutDisplayFunc(&display);
    glutReshapeFunc(&reshapeFunc);
    glutMouseFunc(&mouseFunc);
    glutMotionFunc(&motionFunc);

    /* Loop */
    glutMainLoop();

    /* Never reached */
    return 0;
}

Solution

  • gluPerspective(50, width / height, 0, 20);
                                       ^ wat
    

    zNear needs to be greater than zero (emphasis mine):

    Depth buffer precision is affected by the values specified for zNear and zFar. The greater the ratio of zFar to zNear is, the less effective the depth buffer will be at distinguishing between surfaces that are near each other.

    If r = zFar / zNear roughtly log2(r) bits of depth buffer precision are lost. Because r approaches infinity as zNear approaches 0, zNear must never be set to 0.


    EDIT: Given the newly-posted MCVE:

    int main(int argc, char **argv) {
        /* Creation of the window */
        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
        glutInitWindowSize(900, 600);
        glEnable(GL_DEPTH_TEST);  // too soon
    
        glutCreateWindow("Chess");
        ...
    }
    

    It's just like datenwolf said: You're glEnable()ing before you have a current GL context (glutCreateWindow() creates the context and makes it current).

    Don't call any gl*() functions until after glutCreateWindow().