从深度缓冲区获取真正的z值 [英] Getting the true z value from the depth buffer

查看:192
本文介绍了从深度缓冲区获取真正的z值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如预期的那样,从着色器中的深度缓冲区采样返回0到1之间的值。
给定相机的近平面和远平面平面,我该如何计算真实的z值,即与相机的距离?

解决方案

From http://web.archive.org/web/20130416194336/http://olivers.posterous.com/linear-depth-in-glsl-for-real

  // ==后期碎片着色器================== ========================= 
uniform sampler2D depthBuffTex;
统一浮动zNear;
统一浮动zFar;
变化vec2 vTexCoord;
void main(void)
{
float z_b = texture2D(depthBuffTex,vTexCoord).x;
float z_n = 2.0 * z_b - 1.0;
float z_e = 2.0 * zNear * zFar /(zFar + zNear - z_n *(zFar - zNear));




$ b $ p所以这里是解释(有2个错误,请参阅下面Christian的评论):



OpenGL透视矩阵如下所示:



将这个矩阵乘以一个同质点[x,y,z,1]时,它会给出:[do not care,don 'A'和B'是矩阵中的两个大组件)。



OpenGl接下来做了透视分区:它将此分开矢量由其w分量组成。这个操作不是在着色器中完成的(除了像shadowmapping这样的特殊情况),而是在硬件中完成的;你无法控制它。 w = -z,所以Z值变为-A / z-B。



现在我们处于Normalized Device Coordinates。 Z值介于0和1之间。由于某些愚蠢的原因,OpenGL要求它应该移动到[-1,1]范围内(就像x和y一样)。应用缩放和偏移量。

这个最终值存储在缓冲区中。上面的代码确实是相反的:

$ ul
z_b是存储在缓冲区中的原始值

  • z_n线性变换z_b从[-1,1]到[0,1]

  • z_e与z_n = -A / z_e -B的公式相同,但是针对z_e求解。它相当于z_e = -A /(z_n + B)。 A和B应该在CPU上计算并作为制服发送,btw。


    相反的功能是:

     变化浮动深度; //线性深度,世界单位
    void main(void)
    {
    float A = gl_ProjectionMatrix [2] .z;
    float B = gl_ProjectionMatrix [3] .z;
    gl_FragDepth = 0.5 *( - A * depth + B)/ depth + 0.5;
    }


    Sampling from a depth buffer in a shader returns values between 0 and 1, as expected. Given the near- and far- clip planes of the camera, how do I calculate the true z value at this point, i.e. the distance from the camera?

    解决方案

    From http://web.archive.org/web/20130416194336/http://olivers.posterous.com/linear-depth-in-glsl-for-real

    // == Post-process frag shader ===========================================
    uniform sampler2D depthBuffTex;
    uniform float zNear;
    uniform float zFar;
    varying vec2 vTexCoord;
    void main(void)
    {
        float z_b = texture2D(depthBuffTex, vTexCoord).x;
        float z_n = 2.0 * z_b - 1.0;
        float z_e = 2.0 * zNear * zFar / (zFar + zNear - z_n * (zFar - zNear));
    }
    

    [edit] So here's the explanation (with 2 mistakes, see Christian's comment below) :

    An OpenGL perspective matrix looks like this :

    When you multiply this matrix by an homogeneous point [x,y,z,1], it gives you: [don't care, don't care, Az+B, -z] (with A and B the 2 big components in the matrix).

    OpenGl next does the perspective division: it divides this vector by its w component. This operation is not done in shaders (except special cases like shadowmapping) but in hardware; you can't control it. w = -z, so the Z value becomes -A/z -B.

    We are now in Normalized Device Coordinates. The Z value is between 0 and 1. For some stupid reason, OpenGL requires that it should be moved to the [-1,1] range (just like x and y). A scaling and offset is applied.

    This final value is then stored in the buffer.

    The above code does the exact opposite :

    • z_b is the raw value stored in the buffer
    • z_n linearly transforms z_b from [-1,1] to [0,1]
    • z_e is the same formula as z_n=-A/z_e -B, but solved for z_e instead. It's equivalent to z_e = -A / (z_n+B). A and B should be computed on the CPU and sent as uniforms, btw.

    The opposite function is :

    varying float depth; // Linear depth, in world units
    void main(void)
    {
        float A = gl_ProjectionMatrix[2].z;
        float B = gl_ProjectionMatrix[3].z;
        gl_FragDepth  = 0.5*(-A*depth + B) / depth + 0.5;
    }
    

    这篇关于从深度缓冲区获取真正的z值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆