为什么在深度缓冲区中将gl_FragCoord.z与opengl进行偏差?

时间:2018-04-26 16:35:36

标签: c++ qt opengl-es glsl opengl-es-3.0

我一直试图找到一种方法来读取特定鼠标坐标(x,y)的深度值。使用opengl 4.x在win10上一切正常,但不适用于opengl es 3.x

我的方法:

  1. glReadPixels()不适用于深度缓冲区的openGL es
  2. 光线投射不适合,因为我使用大型地形模型
  3. 后续的方法就足够了,但不幸的是,在win10上也是不准确的,但为什么呢?

    #version 420
    uniform vec2 screenXy;
    uniform vec2 screenSize;
    
    out vec4 fragColor;
    
    void main(void) {
    
    if((int(gl_FragCoord.x) == int(screenXy.x)) && ((int(screenSize.y) - int(gl_FragCoord.y)) == int(screenXy.y))) {
        fragColor.r = gl_FragCoord.z;
        } else {
            fragColor = vec4(1, 1, 1, 1.0);
        }
    }
    
  4. 我将鼠标xy坐标提交给fragementshader(screenXy)。如果单击的像素在行中,我会在颜色缓冲区中写入深度值。这是有效的,但是值gl_FragCoord.z和深度缓冲区中的值并不完全相同(我知道深度缓冲区中的这个值是正确的)。虽然gl_FragCoord.z和深度缓冲区值是浮点数,所以我认为是32位。

    GLfloat zd; // from depth buffer
    GLfloat zc[4]; // from color buffer
    m_func->glReadPixels(xy.x(), m_pFbo->height() - xy.y(), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &zd);
    m_func->glReadPixels(xy.x(), m_pFbo->height() - xy.y(), 1, 1, GL_RGBA, GL_FLOAT, zc);
    

    原因:

    1. 偏差是通过内部类型转换发生的,但在哪里?
    2. 因为GL_DEPTH_TEST是在片段着色器gl_FragCoord.z不是最近的(相机)之后执行的,而是保存在深度缓冲区中。因此将gl_FragCoord.z保存在分离的Frambuffer中也没有意义,因为它不是正确的值。
    3. 也许有人可以帮助我并解决问题,因为我找不到任何其他解释?

      这里有一些测量值:

      zc  0.984314
      zd  0.985363
      
      zc  0.552941
      zd  0.554653
      
      zc  1 -> extremly critical
      zd  0.999181
      

3 个答案:

答案 0 :(得分:2)

Since 0.984314 * 255.0 is exactly 251.0, I assume the internal format of the color plane is GL_RGBA8. That means there is 1 byte for each color channel and zc can only have 256 different values, from 0.0 to 1.0 in steps of 1/256.

If it is supported by the OpenGL ES version which you use, then you can change the format of the render buffer storage (e,g. GL_R32F - only red color channel, but 32 bit floating point).

Or you can encode the depth to the 4 channels of the 4 * 8 bit color plane:

vec4 PackDepth( in float depth )
{
    depth *= (256.0*256.0*256.0 - 1.0) / (256.0*256.0*256.0);
    vec4 encode = fract( depth * vec4(1.0, 256.0, 256.0*256.0, 256.0*256.0*256.0) );
    return vec4( encode.xyz - encode.yzw / 256.0, encode.w ) + 1.0/512.0;
}

....

fragColor = PackDepth(gl_FragCoord.z);

And you can decode it after reading the value:

GLfloat zc[4]; // from color buffer
m_func->glReadPixels(xy.x(), m_pFbo->height() - xy.y(), 1, 1, GL_RGBA, GL_FLOAT, zc);

float depth = zc[0] + zc[1]/256.0 + zc[2]/(256.0*256.0) + zc[3]/(256.0*256.0*256.0);
depth = depth * (255.0f/256.0f) * (256.0*256.0*256.0) / (256.0*256.0*256.0 - 1.0);

答案 1 :(得分:0)

我仍然不确定gl_FragCoord.z是否与深度测试后的深度缓冲区相同。使用计数器,您可以进行查询

<script>
export default {
  name: "DropdownTemplate",
  props: ["header"],
  template: `<div>
    <div><h3>Sports 1</h3></div>
  </div>`,
  data() {
    return {};
  }
};
</script>
<style scoped>
h3 {
  padding-left: 10px;
}
</style>

基本上是深度测试的作用。但是如何将gl_FragCoord.z_last存储为静态?有没有办法在openGL 3.x中读取深度值无损?根据solidpixel,只有来自opengl 3.2的浮动帧缓冲。

答案 2 :(得分:0)

深度缓冲区中的值似乎与gl_FragCoord.z不完全相同。我认为以下示例演示了它。

#version 420

uniform vec4 color;
uniform vec2 screenXy;
uniform vec2 screenSize;

in vec2 vBC;

out vec4 fragColor;

void main(void) {

fragColor.r = gl_FragCoord.z;

}

C ++

GLfloat zd;
GLubyte zc[4];
m_func->glReadPixels(xy.x(), m_pFbo->height() - xy.y(), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &zd);
m_func->glReadPixels(xy.x(), m_pFbo->height() - xy.y(), 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, zc);

数据:     zc0 = 255(来自gl_FragCoord.z);     zd = 0.996561(来自深度缓冲区)

但它应该是254,因为0.996561 * 255 = 254.123055。