depth buffer got by glReadPixels is always 1
Asked Answered
R

2

6

I'm using glReadPixels to get depth value of select pixel, but i always get 1, how can i solve it? here is the code:

    glEnable(GL_DEPTH_TEST);
    ..
    glReadPixels(x, viewport[3] - y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, z);

Do I miss anything? And my rendering part is shown below. I use different shaders to draw different part of scene, so how should i make it correct to read depth value from buffer?

void onDisplay(void)
{
// Clear the window and the depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// calculate the view matrix.
GLFrame eyeFrame;
eyeFrame.MoveUp(gb_eye_height);
eyeFrame.RotateWorld(gb_eye_theta * 3.1415926 / 180.0, 1.0, 0.0, 0.0);
eyeFrame.RotateWorld(gb_eye_phi * 3.1415926 / 180.0, 0.0, 1.0, 0.0);
eyeFrame.MoveForward(-gb_eye_radius);
eyeFrame.GetCameraMatrix(gb_hit_modelview);
gb_modelViewMatrix.PushMatrix(gb_hit_modelview);

// draw coordinate system
if(gb_bCoord)
{
    DrawCoordinateAxis();
}

if(gb_bTexture)
{

    GLfloat vEyeLight[] = { -100.0f, 100.0f, 150.0f };
    GLfloat vAmbientColor[] = { 0.2f, 0.2f, 0.2f, 1.0f };
    GLfloat vDiffuseColor[] = { 1.0f, 1.0f, 1.0f, 1.0f};

    glUseProgram(normalMapShader);
    glUniform4fv(locAmbient, 1, vAmbientColor);
    glUniform4fv(locDiffuse, 1, vDiffuseColor);
    glUniform3fv(locLight, 1, vEyeLight);
    glUniform1i(locColorMap, 0);
    glUniform1i(locNormalMap, 1);
    gb_treeskl.Display(SetGeneralColor, SetSelectedColor, 0);
}
else
{
    if(!gb_bOnlyVoxel)
    {
        if(gb_bPoints)
        {
            //GLfloat vPointColor[] = { 1.0, 1.0, 0.0, 0.6 };
            GLfloat vPointColor[] = { 0.2, 0.0, 0.0, 0.9 };
            gb_shaderManager.UseStockShader(GLT_SHADER_FLAT, gb_transformPipeline.GetModelViewProjectionMatrix(), vPointColor);
            gb_treeskl.Display(NULL, NULL, 1);
        }
        if(gb_bSkeleton)
        {
            GLfloat vEyeLight[] = { -100.0f, 100.0f, 150.0f };
            glUseProgram(adsPhongShader);
            glUniform3fv(locLight, 1, vEyeLight);
            gb_treeskl.Display(SetGeneralColor, SetSelectedColor, 0);
        }
    }
    if(gb_bVoxel)
    {
        GLfloat vEyeLight[] = { -100.0f, 100.0f, 150.0f };
        glUseProgram(adsPhongShader);
        glUniform3fv(locLight, 1, vEyeLight);
        SetVoxelColor();
        glPolygonMode(GL_FRONT, GL_LINE);
        glLineWidth(1.0f);
        gb_treeskl.DisplayVoxel();
        glPolygonMode(GL_FRONT, GL_FILL);
    }
}
//glUniformMatrix4fv(locMVP, 1, GL_FALSE, gb_transformPipeline.GetModelViewProjectionMatrix());
//glUniformMatrix4fv(locMV, 1, GL_FALSE, gb_transformPipeline.GetModelViewMatrix());
//glUniformMatrix3fv(locNM, 1, GL_FALSE, gb_transformPipeline.GetNormalMatrix());
//gb_sphereBatch.Draw();
gb_modelViewMatrix.PopMatrix();

glutSwapBuffers();

}

Reynoso answered 27/5, 2013 at 7:14 Comment(1)
I added an answer with C++ example how I do it ...Maiduguri
M
4

I think you are reading correctly the only problem is that you are not linearize the depth from buffer back to <znear...zfar> range hence the ~1 value for whole screen due to logarithmic dependence of depth (almost all the values are very close to 1).

I am doing this like this:

double glReadDepth(double x,double y,double *per=NULL)                  // x,y [pixels], per[16]
    {
    GLfloat _z=0.0; double m[16],z,zFar,zNear;
    if (per==NULL){ per=m; glGetDoublev(GL_PROJECTION_MATRIX,per); }    // use actual perspective matrix if not passed
    zFar =0.5*per[14]*(1.0-((per[10]-1.0)/(per[10]+1.0)));              // compute zFar from perspective matrix
    zNear=zFar*(per[10]+1.0)/(per[10]-1.0);                             // compute zNear from perspective matrix
    glReadPixels(x,y,1,1,GL_DEPTH_COMPONENT,GL_FLOAT,&_z);              // read depth value
    z=_z;                                                               // logarithmic
    z=(2.0*z)-1.0;                                                      // logarithmic NDC
    z=(2.0*zNear*zFar)/(zFar+zNear-(z*(zFar-zNear)));                   // linear <zNear,zFar>
    return -z;
    }

Do not forget that x,y is in pixels and (0,0) is bottom left corner !!! The returned depth is in range <zNear,zFar>. The function is assuming you are using perspective transform like this:

void glPerspective(double fovy,double aspect,double zNear,double zFar)
    {
    double per[16],f;
    for (int i=0;i<16;i++) per[i]=0.0;
    // original gluProjection
//  f=divide(1.0,tan(0.5*fovy*deg))
//  per[ 0]=f/aspect;
//  per[ 5]=f;
    // corrected gluProjection
    f=divide(1.0,tan(0.5*fovy*deg*aspect));
    per[ 0]=f;
    per[ 5]=f*aspect;
    // z range
    per[10]=divide(zFar+zNear,zNear-zFar);
    per[11]=-1.0;
    per[14]=divide(2.0*zFar*zNear,zNear-zFar);
    glLoadMatrixd(per);
    }

Beware the depth accuracy will be good only for close to camera object without linear depth buffer. For more info see:

If the problem persist there might be also another reason for this. Do you have Depth buffer in your pixel format? In windows You can check like this:

Missing depth buffer could explain why the value is always 1 (not like ~0.997). In such case you need to change the init of your window enabling some bits for depth buffer (16/24/32). See:

For more detailed info about using this technique (with C++ example) see:

Maiduguri answered 2/7, 2018 at 7:21 Comment(0)
D
2

Well, you missed to past the really relevent parts of the code. Also the status of the depth testing unit has no influence on what glReadPixels delivers. How about you post your rendering code as well.

Update

After a buffer swap SwapBuffers the contents of the back buffer are undefined and the default state for frame buffer reads is to read from the back buffer. Technically double buffering happens on only the color component, not the depth and stencil component. But you might run into a driver issue with that.

I suggest two tests to rule out those:

  • Do a read of the depth buffer with glReadBuffer(GL_BACK); right before the SwapBuffers.

  • Select the front buffer with glReadBuffer(GL_FRONT); for reading after SwapBuffers

Also please specify in which context (program, not OpenGL, well the later, too) you did your glReadPixels when this problem occours. Also check if you can read color value correctly.

Diluvial answered 27/5, 2013 at 10:5 Comment(2)
hi, i've post my rendering code, could you please check it for me?Reynoso
hi, i use glReadPixels when i do the hit test(mouse click and select a point). And I've test it, the color value can be read correctly, but depth value is still 1.Reynoso

© 2022 - 2024 — McMap. All rights reserved.