glsl 130 depth testing

I’m trying to do something that was so damn easy with fixed functionality, and now seems impossible with glsl 130

all I want is depth testing, and no matter what values i put into glfrag whatever it doesn’t freakin work:


          in vec3 color;
          out vec4 out_color;

          float ecToFragDepth(float z, float near, float far)
          {
            return far / (far - near) + ((far * near / (near - far)) / z);
          }
          
          void main()
          {            
            //fragment color
            out_color = vec4(color, 1.0f);
            
            //fragment depth, required for depth testing to work
            gl_FragDepth = gl_FragCoord.z;
          }

and yes, depth testing is enabled…

entire program modified from example (example did no depth stuff):


// Globals
int             gLastFrameTime;
GLuint  pyramid_vbo;
GLuint  pyramid_ebo;
GLuint  pyramid_vao;
GLuint  main_shader;
double  gProjectionMatrix[16];
float   gProjectionMatrixf[16];
float   gOrthoProjectionMatrixf[16];
double  gModelViewMatrix[16];
float  gModelViewMatrixf[16];

int screen_width = 640, screen_height = 480;


/* Shader source */
/******************************************************************************/

// Basic shader
const GLchar* basicVertexShaderSource =
GLSL_COMPAT_STRING
TO_STRING(
          in vec4 in_position;
          in vec3 in_color;
          uniform mat4    in_proj_matrix;
          uniform mat4    in_modelview_matrix;
          out vec3 color;
          out vec4 pos;
          void main()
          {
            color = in_color;
            gl_Position = pos = in_proj_matrix * in_modelview_matrix* in_position;
          }
);

const GLchar* basicFragmentShaderSource =
GLSL_COMPAT_STRING
TO_STRING(
          in vec3 color;
          out vec4 out_color;
          in vec4 pos;

          void main()
          {            
            //fragment color
            out_color = vec4(color, 1.0f);
            
            //fragment depth, required for depth testing to work
            //gl_FragDepth = pos.z/pos.w;//gl_FragCoord.z;
          }
);


/* Geometry data */
/******************************************************************************/

#define NUM_PYR_VERTS 5
#define NUM_PYR_TRIS 6

static float pyramid_verts[NUM_PYR_VERTS][3] =
{
  //base
  { -5.0, -5.0, 0.0 }, { 5.0, -5.0, 0.0 }, { 5.0, 5.0, 0.0 }, { -5.0, 5.0, 0.0 },
  
  //pinnacle peak...
  { 0.0, 0.0, 5.0 }
};

static float pyramid_colors[NUM_PYR_VERTS][3] =
{
  //base
  { 1.0, 0.0, 0.0 }, { 0.5, 0.0, 0.0 }, { 1.0, 1.0, 0.0 }, { 0.0, 0.0, 1.0 },
  
  // peak...
  { 0.0, 1.0, 0.0 }
};

static unsigned int pyramid_inds[NUM_PYR_TRIS][3] = 
{
  {0,1,2},{2,3,0},{0,1,4},{1,2,4},{2,3,4},{3,0,4}
};

/******************************************************************************/

void matrixIdentity(double A[16])
{
    size_t bytes = 16*sizeof(double);

    printf("bytes: %d
", bytes );
    bzero(A, bytes);
    A[0] = A[5] = A[10] = A[15] = 1.0;

}
void matrixTranslate(double A[16], double tx, double ty, double tz)
{
    bzero(A, 16*sizeof(double));
    A[0] = A[5] = A[10] = A[15] = 1.0;
    A[12] = tx;
    A[13] = ty;
    A[14] = tz;
}

//http://www.cprogramming.com/tutorial/3d/rotationMatrices.html
void matrixRotateX(double A[16], double angle)
{
    double angled = DEG2RAD(angle);
    bzero(A, 16*sizeof(double));
    A[0] = A[15] = 1.0;

    A[5] = cos(angled);
    A[6] = -sin(angled);
    A[9] = sin(angled);
    A[10] = cos(angled);
}

void matrixRotateY(double A[16], double angle)
{
    double angled = DEG2RAD(angle);
    bzero(A, 16*sizeof(double));
    A[5] = A[15] = 1.0;

    A[0] = cos(angled);
    A[2] = sin(angled);
    A[8] = -sin(angled);
    A[10] = cos(angled);
}

void matrixRotateZ(double A[16], double angle)
{
    double angled = DEG2RAD(angle);
    bzero(A, 16*sizeof(double));
    A[10] = A[15] = 1.0;

    A[0] = cos(angled);
    A[1] = -sin(angled);
    A[4] = sin(angled);
    A[5] = cos(angled);

}

void matrixMultiply(double A[16], double B[16], double C[16])
{
    int i, j, k;
    for ( i=0;i<4;i++ ) {
        for ( j=0;j<4;j++ ) {
            C[MAT4_INDEX(i,j)] =  A[MAT4_INDEX(i,0)] * B[MAT4_INDEX(0,j)];
            for (k=1;k<4;k++) {
                C[MAT4_INDEX(i,j)] += A[MAT4_INDEX(i,k)] * B[MAT4_INDEX(k,j)];
            }

        }
    }
}

void matrixPrint(double mat[16])
{
    int i, j;
    for (j=0;j<4;j++) {
        for (i=0;i<4;i++) {
            printf("%4.2f ", mat[MAT4_INDEX(i,j)]);
        }
        printf("
");
    }

}

void matrixfPrint(float mat[16])
{
    int i, j;
    for (j=0;j<4;j++) {
        for (i=0;i<4;i++) {
            printf("%4.2f ", mat[MAT4_INDEX(i,j)]);
        }
        printf("
");
    }

}

/******************************************************************************/
GLuint utilCompileShader(GLenum shaderType, const GLchar *source)
{
    GLuint shader = glCreateShader(shaderType);
    glShaderSource(shader, 1, &source, NULL);
    glCompileShader(shader);
    GLint status;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
    if (!status) 
    {
        printf("shader compile error: %s ", source );
        return 0;
    }
    return shader;
}

/******************************************************************************/
//http://www.songho.ca/opengl/gl_projectionmatrix.html
void utilCreateFrustum( GLdouble        left,
                       GLdouble     right,
                       GLdouble     bottom,
                       GLdouble     top,
                       GLdouble     nearVal,
                       GLdouble     farVal,
                       GLdouble             *mat)
{
    double A = (right+left)/(right-left);
    double B = (top+bottom)/(top-bottom);
    double C = (farVal+nearVal)/(farVal-nearVal);
    double D = (2.0*farVal*nearVal)/(farVal-nearVal);
    int i;
    for (i=0;i<16;i++) { mat[i] = 0.0; }

    mat[0] = (2.0*nearVal)/(right-left);
    mat[5] = (2.0*nearVal)/(top-bottom);
    mat[8] = A;
    mat[9] = B;
    mat[10] = C;
    mat[11] = -1.0;
    mat[14] = D;
}

/******************************************************************************/

void setup_proj(GLuint width, GLuint height)
{
    int i;
    if (width ==0)
        width = 1;

    float nearPlane = 0.1f;
    float farPlane = 1000.0f;

    GLfloat h = (GLfloat) height / (GLfloat) width;
    glViewport(0, 0, (GLint) width, (GLint) height);

    utilCreateFrustum(-1.0f*nearPlane,
                      nearPlane,
                      -h*nearPlane,
                      h*nearPlane,
                      nearPlane,
                      farPlane,
                      gProjectionMatrix);

    for(i=0;i<16;i++) { gProjectionMatrixf[i] = gProjectionMatrix[i];}

}

/******************************************************************************/
void utilCreateOrtho(float w, float h, GLdouble mat[16])
{
    GLdouble        left = 0;
    GLdouble        right = w;
    GLdouble        bottom = 0;
    GLdouble        top = h;
    GLdouble        near = -1.0;
    GLdouble        far = 1.0;

    GLdouble tx = -(right+left)/(right-left);
    GLdouble ty = -(top+bottom)/(top-bottom);
    GLdouble tz = -(far+near)/(far-near);

    int i=0;
    for (i=0;i<16;i++) { mat[i] = 0.0;}

    mat[0] = (2.0/(right-left));
    mat[5] = (2.0/(top-bottom));
    mat[10] = -(2.0/(far-near));
    mat[12] = tx;
    mat[13] = ty;
    mat[14] = tz;
    mat[15] = 1.0;

}

/******************************************************************************/

//if we wanted 2D...
void setup_ortho(GLuint width, GLuint height)
{
    if (width ==0)
        width = 1;

    double mat[16];
    int i;
    glViewport(0, 0, (GLint) width, (GLint) height);
    utilCreateOrtho(width, height, mat);
    for (i=0;i<16;i++) {gOrthoProjectionMatrixf[i] = mat[i]; }
}

void createShaders()
{
    GLint status;

    // The basic shader for the geometry
    main_shader = glCreateProgram();
    GLuint vertexShader= utilCompileShader(GL_VERTEX_SHADER,
                                           basicVertexShaderSource);
    GLuint fragmentShader = utilCompileShader(GL_FRAGMENT_SHADER,
                                              basicFragmentShaderSource);

    glAttachShader(main_shader, vertexShader);
    glAttachShader(main_shader, fragmentShader);

    glBindFragDataLocationEXT(main_shader, 0, "out_color");

    glLinkProgram(main_shader);

    glGetProgramiv(main_shader, GL_LINK_STATUS, &status);
    if (!status) {
        printf("program link error
");
    }
}

void createVertexBuffers()
{
    int sizeInBytes = 0;

    glGenVertexArrays(1, &pyramid_vao);
    glBindVertexArray(pyramid_vao);
    
    sizeInBytes = sizeof(float)*3*NUM_PYR_VERTS;
    glGenBuffers(1, &pyramid_vbo);
    glBindBuffer(GL_ARRAY_BUFFER, pyramid_vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeInBytes*2, NULL, GL_STATIC_DRAW);
    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeInBytes, pyramid_verts);
    glBufferSubData(GL_ARRAY_BUFFER, sizeInBytes, sizeInBytes, pyramid_colors);
    
    GLuint positionLoc = glGetAttribLocation(main_shader, "in_position");    
    glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(positionLoc);
    
    positionLoc = glGetAttribLocation(main_shader, "in_color");    
    glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 0, sizeInBytes);
    glEnableVertexAttribArray(positionLoc);

    sizeInBytes = sizeof(unsigned int)*3*NUM_PYR_TRIS;
    glGenBuffers(1, &pyramid_ebo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, pyramid_ebo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeInBytes, NULL, GL_STATIC_DRAW);
    glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeInBytes, pyramid_inds);

    glBindVertexArray(0);
}

/******************************************************************************/

void render_3d()
{
    glUseProgram(main_shader);
    
    int i;
    double test[16];
    
    //uniforms are given after selecting the shader program
    //this is how the matrixes are given to the shader
    GLuint projMatrixLoc = glGetUniformLocation(main_shader, "in_proj_matrix");
    glUniformMatrix4fv(projMatrixLoc, 1, GL_FALSE, gProjectionMatrixf);

    GLuint mvMatrixLoc = glGetUniformLocation(main_shader, "in_modelview_matrix");
    glUniformMatrix4fv(mvMatrixLoc, 1, GL_FALSE, gModelViewMatrixf);

    glBindVertexArray(pyramid_vao);
    glDrawElements(GL_TRIANGLES, 3*3, GL_UNSIGNED_INT, BUFFER_OFFSET(0));
    //glDrawElements(GL_TRIANGLES, NUM_PYR_TRIS*3, GL_UNSIGNED_INT, BUFFER_OFFSET(0));
    glBindVertexArray(0);    
}

static void processing()
{
    double T[16];
    double R[16];
    int i;
    static float t = 0.0;

    setup_proj(screen_width, screen_height);
    
    t += 1.0;
    
    // transform the geometry
    matrixTranslate(T , 0, 0, -10);
    matrixRotateX(R, t);
    matrixMultiply(T, R, gModelViewMatrix);

    // copy doubles to float
    for(i=0;i<16;i++) { gModelViewMatrixf[i] = gModelViewMatrix[i];}

}

/******************************************************************************/

void cbDisplay()
{
  glClearColor(0,0,0,1);  
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  render_3d();
  
  glutSwapBuffers();
}

/******************************************************************************/

void cbReshape(int width, int height)
{
    screen_width = width;
    screen_height = height;
}

/******************************************************************************/

void cbIdle()
{
    processing();
    glutPostRedisplay();
}


/******************************************************************************/
int main(int argc, char** argv)
{
    glutInit(&argc, argv);

    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
    glutInitWindowSize(screen_width, screen_height);

    glutCreateWindow("");

    glEnable(GL_DEPTH_TEST);
    glDisable(GL_CULL_FACE);
    
    createShaders();
    createVertexBuffers();

    glutDisplayFunc(cbDisplay);
    glutReshapeFunc(cbReshape);
    glutIdleFunc(cbIdle);

    glutMainLoop();
    return EXIT_SUCCESS;
}
/******************************************************************************/



Man was that frustrating. The projection matrix was incorrect from the tutorial code. Two signs were missing


void utilCreateFrustum( GLdouble        left,
                       GLdouble     right,
                       GLdouble     bottom,
                       GLdouble     top,
                       GLdouble     nearVal,
                       GLdouble     farVal,
                       GLdouble             *mat)
{
    double A = (right+left)/(right-left);
    double B = (top+bottom)/(top-bottom);
    double C = -(farVal+nearVal)/(farVal-nearVal);
    double D = (-2.0*farVal*nearVal)/(farVal-nearVal);
    int i;
    for (i=0;i<16;i++) { mat[i] = 0.0; }

    mat[0] = (2.0*nearVal)/(right-left);
    mat[5] = (2.0*nearVal)/(top-bottom);
    mat[8] = A;
    mat[9] = B;
    mat[10] = C;
    mat[11] = -1.0;
    mat[14] = D;
}

.

perfect reason why the absent features from OpenGL 3.0 should be moved into a toolkit library!!! Matrix generation is the same that its been for 20 years in computer graphics, no reason to make people do it on their own. If I was a newbie trying to learn 3D programming and I was faced with OpenGL 3.0 (and not the prior 2.1) I’d be thoroughly lost. No need to make people that aren’t linear algebra experts suffer.

/rant

Biasing the API towards a single type of matrix usage has caused endless debates & complaints w.r.t. fixed function API. Mainly w.r.t. column vs. row major (one is obviously the transpose of the other) and the implicatios for the notational convention w.r.t. pre vs. post multiplication, but these things are now moot, you roll your own and watch what you output to the next pipeline stage.