来自对数深度缓冲区的 World-space 位置
World-space position from logarithmic depth buffer
在将我当前的延迟渲染器更改为使用 logarithmic depth buffer 之后,我无法解决,对于我的生活,如何从深度缓冲区值重建世界-space 深度。
当我写入 OpenGL 默认 z/w 深度时,我可以通过从 window-space 转换为 NDC-space 然后执行逆透视来轻松计算该值转型。
我在第二遍片段着色器中完成了这一切:
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
: perspective devide
前gl_Position.z
的值
return 值:gl_Position.z
当然,那只是我的工作。我不确定这些值最终实际持有什么,因为我认为我搞砸了一些数学或者没有正确理解正在进行的转换。
从这个对数深度缓冲区获取我的世界-space Z 位置的正确方法是什么?
最后我的做法全错了。使用日志缓冲区获取 world-space 位置的方法是:
- 从纹理中检索深度
- 重构gl_Position.w
- 线性化重建深度
- 翻译成世界space
这是我在 glsl 中的实现:
in vec2 uv_f;
uniform float nearz;
uniform float farz;
uniform mat4 inv_view_proj_mat;
float linearize_depth(in float depth){
float a = farz / (farz - nearz);
float b = farz * nearz / (nearz - farz);
return a + b / depth;
}
float reconstruct_depth(){
float depth = texture(depth_tex, uv_f).r;
return pow(2.0, depth * log2(farz + 1.0)) - 1.0;
}
vec3 reconstruct_world_pos(){
vec4 wpos =
inv_view_proj_mat *
(vec4(uv_f, linearize_depth(reconstruct_depth()), 1.0) * 2.0 - 1.0);
return wpos.xyz / wpos.w;
}
这给我的结果与我使用默认 OpenGL 深度缓冲区时相同(但精度更高)。
在将我当前的延迟渲染器更改为使用 logarithmic depth buffer 之后,我无法解决,对于我的生活,如何从深度缓冲区值重建世界-space 深度。
当我写入 OpenGL 默认 z/w 深度时,我可以通过从 window-space 转换为 NDC-space 然后执行逆透视来轻松计算该值转型。
我在第二遍片段着色器中完成了这一切:
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
: perspective devide
gl_Position.z
的值
return 值:gl_Position.z
当然,那只是我的工作。我不确定这些值最终实际持有什么,因为我认为我搞砸了一些数学或者没有正确理解正在进行的转换。
从这个对数深度缓冲区获取我的世界-space Z 位置的正确方法是什么?
最后我的做法全错了。使用日志缓冲区获取 world-space 位置的方法是:
- 从纹理中检索深度
- 重构gl_Position.w
- 线性化重建深度
- 翻译成世界space
这是我在 glsl 中的实现:
in vec2 uv_f;
uniform float nearz;
uniform float farz;
uniform mat4 inv_view_proj_mat;
float linearize_depth(in float depth){
float a = farz / (farz - nearz);
float b = farz * nearz / (nearz - farz);
return a + b / depth;
}
float reconstruct_depth(){
float depth = texture(depth_tex, uv_f).r;
return pow(2.0, depth * log2(farz + 1.0)) - 1.0;
}
vec3 reconstruct_world_pos(){
vec4 wpos =
inv_view_proj_mat *
(vec4(uv_f, linearize_depth(reconstruct_depth()), 1.0) * 2.0 - 1.0);
return wpos.xyz / wpos.w;
}
这给我的结果与我使用默认 OpenGL 深度缓冲区时相同(但精度更高)。