World space position from logarithmic depth buffer

After changing my current deferred renderer to use the logarithmic depth buffer , I can’t work, for life, how to reconstruct the depth of world space from the depth buffer values.

When I recorded the default depth of z / w OpenGL, I could easily calculate this value by converting from window space to NDC space, then doing the inverse perspective transformation.

I did it all in the shader of the second pass fragment:

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; } 

and got a result that looked pretty correct:

Cube processed with the correct reconstruction of the position in the world space

But now the path to a simple z value is not so simple (it does not seem like it should be so complicated either).

My vertex shader for my first pass with log depth:

 #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; } 

And my fragment shader:

 #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; } 

I tried several different approaches to correctly return the z-position, all fail.

If I redefine my reconstruct_pos in the second pass:

 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; } 

This is my current attempt to restore 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; } 

Explanations:

log2logz_FC_2 : the value written to the depth buffer, so log2(1.0 + gl_Position.w) * (FC / 2)

logz : just 1.0 + gl_Position.w

pos_z : value of gl_Position.z before gl_Position.z perspective

return value: gl_Position.z

Of course, this is just my job. I’m not sure what these values ​​actually hold in the end, because I think I messed up some of the math or misunderstood the transformations that are happening.

What is the right way to get my position in world space from this logarithmic depth buffer?

+7
opengl glsl depth-buffer deferred-rendering
source share
1 answer

In the end, I did all this wrong. A way to return a world space position using the log buffer

  • Get depth from texture
  • Restore gl_Position.w
  • linearize recovered depth
  • translate into world space

Here is my implementation in 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; } 

Which gives me the same result (but with greater accuracy) as when using the standard OpenGL depth buffer.

0
source share

All Articles