Depth test problem.

I’ve been trying to implement depth testing in my rendering engine, but I’m running into a problem which I can’t seem to figure out!

I’m rendering my entire scene to a FBO texture at a fixed resolution, and this is later scaled to the window framebuffer to achieve quick and easy resolution independence, and I have had this working for quite some time.

Other than that texture, I have now enabled deth tests and added a renderbuffer to this FBO as such:


        glEnable(GL_DEPTH_TEST);

        glDepthMask(GL_TRUE);
        glClearDepth(1.f);

        glDepthRangef(0.f,
                      1.f);

        ….

        glGenRenderbuffers(1,
                           &g_depth_renderbuffer);

        glBindRenderbuffer(GL_RENDERBUFFER,
                           g_depth_renderbuffer);

        glRenderbufferStorage(GL_RENDERBUFFER,
                              GL_DEPTH_COMPONENT,
                              a_resolution.x,
                              a_resolution.y);

        glFramebufferRenderbuffer(GL_FRAMEBUFFER,
                                  GL_DEPTH_ATTACHMENT,
                                  GL_RENDERBUFFER,
                                  g_depth_renderbuffer);

Then I have a function to clear all buffers that looks like this:


void
renderer_clear_all_buffers()
{
        glBindFramebuffer(GL_FRAMEBUFFER,
                          0);

        glClearColor(1.f,
                     0.f,
                     0.f,
                     1.f);

        glClear(GL_COLOR_BUFFER_BIT);

        glBindFramebuffer(GL_FRAMEBUFFER,
                          g_framebuffer);

        glClearColor(0.f,
                     0.f,
                     0.f,
                     1.f);

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}

and then for rendering the scene I do this, in order to avoid having my scene texture that I scale to the screen fail the depth test:


glDepthFunc(GL_LESS);

/*Render scene here*/

glDepthFunc(GL_ALWAYS);

/*Render final framebuffer texture to a quad covering the screen here*/

Now, with depth testing disabled, if I try to render two object of different sizes at the origin, the one rendered last is always shown above the first one, no matter how I rotate the scene, as expected.
But with depth testing enabled the opposite happens, and the first object is always rendered completely above the other, no matter how the scene is rotated, even tho the two object now should be rendered over different parts of each other.

If I change from

glDepthFunc(GL_LESS);

to

glDepthFunc(GL_LEQUAL);

, the scene is rendered as if depth testing is disabled again, leading me to believe that all fragments that are not at the far plane get the same value, and after some more digging it would seam that all fragments get the depth value of 0.5.

I can’t spot my error here, so any help to straighten this out would be greatly appreciated!

[QUOTE=Dregel;1288156]
If I change from

glDepthFunc(GL_LESS);

to

glDepthFunc(GL_LEQUAL);

, the scene is rendered as if depth testing is disabled again, leading me to believe that all fragments that are not at the far plane get the same value, and after some more digging it would seam that all fragments get the depth value of 0.5.

I can’t spot my error here, so any help to straighten this out would be greatly appreciated![/QUOTE]
The error would appear to be in the rendering code or the shaders, not the framebuffer setup.

The fact that [var]glDepthFunc(GL_LESS)[/var] results in the first object having precedence indicates that you do have a depth buffer and that depth testing is working correctly.

How is the Z coordinate generated? Are you using the fixed-function pipeline, or shaders? If it’s the fixed-function pipeline, how are you setting the model-view and projection matrices? If you’re using shaders, how does the vertex shader set gl_Position?

Well yeah, I seem to have functional depth testing in that sense, but It seems as if every single fragment ends up with the same depth value, namely 0.5, and that in turn makes the depth testing not allowing the closest fragment through to the “top”, so i guess it could be the rendering or shader code, so here it goes!

First my vertex shader:


precision highp float;

layout (location = 0) in vec3 pos;
layout (location = 1) in vec2 uv;

uniform mat4 mvp;
uniform vec2 uvOffset;
uniform vec2 uvExtents;

out vec2 TexCoord;

void
main()
{
    gl_Position = mvp * vec4(pos, 1.0f);
    TexCoord = (uv * uvExtents) + uvOffset;
    TexCoord.y = 1.0f - TexCoord.y;
}

my fragment shader:


precision highp float;

uniform sampler2D spriteTexture;
uniform vec4 color;

in vec2 TexCoord;

out vec4 FragColor;

void
main()
{
    FragColor = texture2D(spriteTexture, TexCoord.xy) * color;
}

And here is my rendering code for rendering a simple cube:


        scale = mat4_identity();
        scale.m11 = g_job_queue.jobs[i].scale.x;
        scale.m22 = g_job_queue.jobs[i].scale.y;
        scale.m33 = g_job_queue.jobs[i].scale.z;

        rotation = quaternion__get_matrix(g_job_queue.jobs[i].rotation);

        translation = mat4_identity();
        translation.m41 = g_job_queue.jobs[i].position.x;
        translation.m42 = g_job_queue.jobs[i].position.y;
        translation.m43 = g_job_queue.jobs[i].position.z;

        pivot = mat4_identity();
        pivot.m41 = g_job_queue.jobs[i].pivot.x;
        pivot.m42 = g_job_queue.jobs[i].pivot.y;
        pivot.m43 = g_job_queue.jobs[i].pivot.z;

        model = mat4_identity();

        model = mat4_multiply(model,
                              scale);

        model = mat4_multiply(model,
                              pivot);

        model = mat4_multiply(model,
                              rotation);

        model = mat4_multiply(model,
                              translation);

        mvp = model;

        if(g_job_queue.jobs[i].render_in_world == true)
        {
                mvp = mat4_multiply(mvp,
                                    mat4_invert(g_camera.view));
        }

        mvp = mat4_multiply(mvp,
                            g_camera.projection);

        glActiveTexture(GL_TEXTURE0);

        glBindTexture(GL_TEXTURE_2D,
                      texture_manager_get_texture_gl_name(g_job_queue.jobs[i].texture_id));

        glTexParameterf(GL_TEXTURE_2D,
                        GL_TEXTURE_MIN_FILTER,
                        GL_NEAREST);

        glTexParameterf(GL_TEXTURE_2D,
                        GL_TEXTURE_MAG_FILTER,
                        GL_NEAREST);

        glUniform1i(g_sprite_texture_location,
                    0);

        glUniform4f(g_color_location,
                    g_job_queue.jobs[i].color.x,
                    g_job_queue.jobs[i].color.y,
                    g_job_queue.jobs[i].color.z,
                    g_job_queue.jobs[i].color.w);

        glUniformMatrix4fv(g_mvp_location,
                           1,
                           GL_FALSE,
                           (GLfloat*)&mvp);

        glUniform2f(g_uv_offset_location,
                    g_job_queue.jobs[i].uv_offset.x,
                    g_job_queue.jobs[i].uv_offset.y);

        glUniform2f(g_uv_extents_location,
                    g_job_queue.jobs[i].uv_extents.x,
                    g_job_queue.jobs[i].uv_extents.y);

        glBindBuffer(GL_ARRAY_BUFFER,
                     g_box_vbo);

        glBufferData(GL_ARRAY_BUFFER,
                     sizeof(vertex) * 24,
                     g_box_vertices,
                     GL_STATIC_DRAW);

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
                     g_box_ibo);

        glBufferData(GL_ELEMENT_ARRAY_BUFFER,
                     sizeof(uint32_t) * 36,
                     g_box_indices,
                     GL_STATIC_DRAW);

        glVertexAttribPointer(0,
                              3,
                              GL_FLOAT,
                              GL_FALSE,
                              sizeof(vertex),
                              NULL);

        glVertexAttribPointer(1,
                              2,
                              GL_FLOAT,
                              GL_FALSE,
                              sizeof(vertex),
                              (uint8_t*)NULL + 12);

        glDrawElements(GL_TRIANGLES,
                       36,
                       GL_UNSIGNED_INT,
                       0);

Other than that, the only thing that might be relevant that i can think of is how i create my view and projection matrices, specifically the function i made to create a projection matrix, so here is that cad as well:


mat4
mat4_perspective(const float a_fov,
                 const float a_aspect,
                 const float a_near,
                 const float a_far)
{
        mat4    result;
        float   factor;
        int64_t near_factor;

        factor = 1.0 / tan_float(a_fov / 2.0);
        near_factor = 1 / (a_near - a_far);

        result.m11 = factor / a_aspect;
        result.m12 = 0.0;
        result.m13 = 0.0;
        result.m14 = 0.0;

        result.m21 = 0.0;
        result.m22 = factor;
        result.m23 = 0.0;
        result.m24 = 0.0;

        result.m31 = 0.0;
        result.m32 = 0.0;
        result.m33 = (a_near + a_far) * near_factor;
        result.m34 = -1.0;

        result.m41 = 0.0;
        result.m42 = 0.0;
        result.m43 = (2.0 * a_near * a_far) * near_factor;
        result.m44 = 0.0;

        return result;
}


void
init_opengl()
{
        g_camera.view = mat4_translate(mat4_identity(),
                                       vec3_new(0.f,
                                                0.f,
                                                5.f));

        g_camera.projection = mat4_perspective(120.f,
                                               a_resolution.x / a_resolution.y,
                                               0.1f,
                                               100.f);

 ...

}

When creating your projection matrix what values do you use? This is the kind of undefined behaviour that might happen if you had a near flipping plane of 0.

It is included in the last code part of my last post, but here it is again:


        view = mat4_translate(mat4_identity(),
                              vec3_new(0.f,
                                       0.f,
                                       5.f));
 
        projection = mat4_perspective(120.f,
                                      a_resolution.x / a_resolution.y,
                                      0.1f,
                                      100.f);

But i have also tried with values as high as 90.0 for the near plane with the same results.
But maybe there is something wrong with my function for generating the projection matrix, because unless i have completely misunderstood the function of the far and near plane, i should not be able to see a cube of size (1.0, 1.0, 1.0) at position (0.0, 0.0, 0.0) with a view from position (0.0, 0.0, 5.0) and with a near plane at 90.0 and far plane at 100.0?

And directly after posting my latest post i solved it!
The problem was in my function for creating projection matrices.


mat4
mat4_perspective(const float a_fov,
                 const float a_aspect,
                 const float a_near,
                 const float a_far)
{
        mat4    result;
        float   factor;
        int64_t near_factor;
 
        factor = 1.0 / tan_float(a_fov / 2.0);
        near_factor = 1 / (a_near - a_far);
 
        result.m11 = factor / a_aspect;
        result.m12 = 0.0;
        result.m13 = 0.0;
        result.m14 = 0.0;
 
        result.m21 = 0.0;
        result.m22 = factor;
        result.m23 = 0.0;
        result.m24 = 0.0;
 
        result.m31 = 0.0;
        result.m32 = 0.0;
        result.m33 = (a_near + a_far) * near_factor;
        result.m34 = -1.0;
 
        result.m41 = 0.0;
        result.m42 = 0.0;
        result.m43 = (2.0 * a_near * a_far) * near_factor;
        result.m44 = 0.0;
 
        return result;
}

After re-checking the function to make sure that I was not making any mistakes i noticed that the variable near_factor was declared as an int and not a float, effectively truncating values and resulting in weird relations between far and near planes!
So simply changing the declaration to a float solved the problem!

A slight oversight that gave me a lot of headache weeks after writing the function! :stuck_out_tongue:

Thanks for all the help!