4
\$\begingroup\$

q1. After passing stencil test, depth test, etc. what version of "depth" of fragments after primitive rasterisation will be written to depth buffer? With shifted values or without? (Due to documentaion as I see it will be shifted version)

q2. Code in fragment shader will receive shifted version of gl_FragCoord.z, isn't it?

\$\endgroup\$

1 Answer 1

6
\$\begingroup\$

The short answer is: Don't use glPolygonOffset.

It's not portable in the sense that you have no control over how the values are applied by the driver, so even on the same platform (eg Windows), different drivers will give different results.

sadly glDepthRange is also not usable for this purpose due to clamping.

You should shift the depth yourself using the projection matrix or a uniform value in your vertex shader. Avoid doing it in the pixel shader as it disables early-Z and hi-Z GPU optimizations.

One good way to shift depth is to multiply it by a factor slightly above or below 1 ( eg 1.015625 or 0.984375 (1.0 +/- (1.0/64.0)), depending on which direction you want to shift your pixels and direction of your depth buffer) this works well with both fixed and floating point depth buffer rounding issues as the "shift" scales up and down with depth values.

in your vertex shader:

vtx *= pvm_matrix; // transformation to screen-space
vtx.z *= 1.0 + shift_value * abs(vtx.w); // counter w division for shift

or just pre-calculate the shift value into pvm_matrix without the vtx.w correction.

Ideally you want to use a shift increment value that is 1.0/N where N is a power of two (eg 1/64 = 0.015625) this plays better with binary rounding errors.

float shift_value = int_layer / 1024.0f;
glUniform1f(loc, shift_value);

the value to use depends on the depth buffer's precision, most are 24bits fixed point (1/65536 is a decent value to shift on these) but some platforms use 24bit float which leaves only 15~16 bits of mantissa precision (1/1024 or 1/512 is a good value for those).

You need to leave enough bits of precision "below" your shift value unless you're rendering flat 2D UI planes. The less perpendicular to the camera the more bits you need to leave "below" your shift value (larger shift value) in the depth buffer.

It's possible to adjust the shift amount in the vertex shader according to the angle of the triangle by using the normals.


But really, as much as possible the best way is to completely avoid having to shift depth values by using multi-texturing, or 2nd pass using 100% identical triangles (merged vertex) and a depth test of equal.

If the vertices are identical the interpolation will also be identical and won't cause any depth fighting but this may not be possible in all situations.

\$\endgroup\$
2
  • \$\begingroup\$ It's really weird, but when I do this in my vertex shader and apply an offset of 1/1024 after applying the mvp matrix, my polygons disappear. I first draw a polygonal mesh (with an offset of 1/1024), then draw the same mesh using GL_LINE (with an offset of 0). It works well if I only apply the shift, but when multiplying the shift with vtx.w, the filled polygon disappears. I really can't figure out why... \$\endgroup\$
    – AzP
    Commented Jan 2, 2017 at 17:47
  • \$\begingroup\$ "It's not portable in the sense that you have no control over how the values are applied by the driver, so even on the same platform (eg Windows), different drivers will give different results." do you have any examples of this? \$\endgroup\$
    – nmr
    Commented Jun 9, 2022 at 19:34

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .