1

In my deferred renderer, I've managed to successfully reconstruct my fragment position from the depth buffer.... mostly. By comparing my results to the position stored in an extra buffer, I've noticed that I'm getting a lot of popping far away from the screen. Here's a screenshot of what I'm seeing:

enter image description here

The green and yellow parts at the top are just the skybox, where the position buffer contains (0, 0, 0) but the reconstruction algorithm interprets it as a normal fragment with depth = 0.0 (or 1.0?).

The scene is rendered using fragColor = vec4(0.5 + (reconstPos - bufferPos.xyz), 1.0);, so anywhere that the resulting fragment is exactly (0.5, 0.5, 0.5) is where the reconstruction and the buffer have the exact same value. Imprecision towards the back of the depth buffer is to be expected, but that magenta and blue seems a bit strange.

This is how I reconstruct the position from the depth buffer:

vec3 reconstructPositionWithMat(vec2 texCoord)
{
    float depth = texture2D(depthBuffer, texCoord).x;
    depth = (depth * 2.0) - 1.0;
    vec2 ndc = (texCoord * 2.0) - 1.0;
    vec4 pos = vec4(ndc, depth, 1.0);
    pos = matInvProj * pos;
    return vec3(pos.xyz / pos.w);
}

Where texCoord = gl_FragCoord.xy / textureSize(colorBuffer, 0);, and matInvProj is the inverse of the projection matrix used to render the gbuffer.

Right now my position buffer is GL_RGBA32F (since it's only for testing accuracy, I don't care as much about bandwith and memory waste), and my depth buffer is GL_DEPTH24_STENCIL8 (I got similar results from GL_DEPTH_COMPONENT32, and yes I do need the stencil buffer).

My znear is 0.01f, and zfar is 1000.0f. I'm rendering a single quad as my ground which is 2000.0f x 2000.0f large (I wanted it to be big enough that it would clip with the far plane).

Is this level of imprecision considered acceptable? What are some ways that people have gotten around this problem? Is there something wrong with how I reconstruct the view/eye-space position?

Haydn V. Harach
  • 1,185
  • 14
  • 30
  • Interestingly, the flicker only seems to happen with the ground... The box and the bunny that I render stay gray, even at a longer distance. Might it have something to do with clipping? Right now, the position is transformed by the modelview matrix in the vertex shader (`vPosition = (matView * vec4(inPosition, 1.0));`), interpolated across the polygon, then written directly to the position buffer by the fragment shader. – Haydn V. Harach Mar 10 '14 at 07:45
  • You should use a floating-point depth buffer with the depth range inverted for best results. Floating-point gives more accuracy in the range **0.0** - **1.0** as does perspective depth. If you combine perspective depth with a inverted depth range and a floating-point depth buffer, you can largely cancel out the uneven distribution of precision at distance (of course, you have to flip your depth test and the value you clear your depth buffer to). By the way, there is a floating-point 32-bit depth + 8-bit stencil format available on DX10 class hardware. It has a 64-bit footprint though. – Andon M. Coleman Mar 11 '14 at 19:55
  • Is there a floating-point depth buffer with stencil buffer that _doesn't_ waste 24 bits per pixel? – Haydn V. Harach Mar 12 '14 at 01:27
  • No, not on desktop hardware. The Xbox 360 supports a 24-bit floating-point depth buffer. Actually, some of the ATI desktop GPUs from that era do as well, but the format is not exposed in OpenGL. It is available in D3D provided you have said GPU. – Andon M. Coleman Mar 12 '14 at 01:35
  • Well I implemented the reversed floating-point depth buffer trick (with `GL_DEPTH32F_STENCIL8`), and I'm happy with the precision, I just need to find a way to reconstruct position that's faster than multiplying by the inverse projection matrix... – Haydn V. Harach Mar 17 '14 at 10:12

0 Answers0