在将我的延迟渲染器改为使用对数深度缓冲后,我无论如何都解决不了如何从深度缓冲区的值中重建世界空间深度。
当我使用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;
}
然后得到了一个看起来相当正确的结果:
但是现在,获得简单的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位置的正确方法是什么?