对数深度缓冲区的世界空间位置

时间:2016-11-02 05:41:49

标签: opengl glsl depth-buffer deferred-rendering

将我当前的延迟渲染器更改为使用logarithmic depth buffer后,我无法解决,在我的生活中,如何从深度缓冲区值重建世界空间深度。

当我编写OpenGL默认z / w深度时,我可以通过从窗口空间转换到NDC空间来轻松计算此值,然后执行逆透视变换。

我在第二遍片段着色器中完成了这一切:

uniform sampler2D depth_tex;

uniform mat4 inv_view_proj_mat;

in vec2 uv_f;

vec3 reconstruct_pos(){
    float z = texture(depth_tex, uv_f).r;
    vec4 pos = vec4(uv_f, z, 1.0) * 2.0 - 1.0;
    pos = inv_view_proj_mat * pos;

    return pos.xyz / pos.w;
}

并得到了看起来非常正确的结果:

Cube rendered with correct world-space position reconstruction

但现在通往简单z值的道路并不那么容易(看起来它也不应该那么难)。

我的第一次传递的顶点着色器具有日志深度:

#version 330 core
#extension GL_ARB_shading_language_420pack : require

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

uniform mat4 mvp_mat;

uniform float FC;

out vec2 uv_f;
out float logz_f;
out float FC_2_f;

void main(){
    gl_Position = mvp_mat * vec4(pos, 1.0);

    logz_f = 1.0 + gl_Position.w;

    gl_Position.z = (log2(max(1e-6, logz_f)) * FC - 1.0) * gl_Position.w;

    FC_2_f = FC * 0.5;
}

我的片段着色器:

#version 330 core
#extension GL_ARB_shading_language_420pack : require

// other uniforms and output variables

in vec2 uv_f;
in float FC_2_f;

void main(){
    gl_FragDepth = log2(logz_f) * FC_2_f;
}

我尝试了几种不同的方法来正确地恢复z位置,都失败了。

如果我在第二遍中重新定义reconstruct_pos为:

vec3 reconstruct_pos(){
    vec4 pos = vec4(uv_f, get_depth(), 1.0) * 2.0 - 1.0;
    pos = inv_view_proj_mat * pos;

    return pos.xyz / pos.w;
}

这是我目前重建Z的尝试:

uniform float FC;

float get_depth(){
    float log2logz_FC_2 = texture(depth_tex, uv_f).r;
    float logz = pow(2, log2logz_FC_2 / (FC * 0.5));
    float pos_z = log2(max(1e-6, logz)) * FC - 1.0; // pos.z
    return pos_z;
}

说明:

log2logz_FC_2:写入深度缓冲区的值,log2(1.0 + gl_Position.w) * (FC / 2)

logz:只需1.0 + gl_Position.w

pos_z:透视图之前gl_Position.z的值

返回值:gl_Position.z

当然,那只是我的工作。我不确定这些价值到底是什么意思,因为我认为我搞砸了一些数学或者没有正确理解正在发生的转变。

从此对数深度缓冲区获取世界空间Z位置的正确方法是什么?

1 个答案:

答案 0 :(得分:0)

最后我发现这一切都错了。使用日志缓冲区返回世界空间位置的方法是:

  1. 从纹理中检索深度
  2. 重建gl_Position.w
  3. 线性化重建深度
  4. 翻译为世界空间
  5. 这是我在glsl中的实现:

    String str = "GenericRequest.param[i]&SpecificRequest.param[i]=XYZ&GenericRequest.param[i]";
    String result = Arrays.asList(str
                          .split("&"))
                          .filter(s -> s.endsWith("[i]");
                          .magic(?);
    

    当我使用默认的OpenGL深度缓冲区时,它给出了相同的结果(但精度更高)。