EEVEE-Next: Fix depth accumulation and stability in viewport

The display depth is used to composite Gpencil and Overlays. For it to
be stable we bias it using the dFdx gradient functions. This makes
overlays like edit mode not flicker.

The previous approach to save the 1st center sample does not work anymore
since we jitter the projection matrix in a looping pattern when scene
is updated. So the center depth is only (almost) valid 1/8th of the times.
The biasing technique, even if not perfect, does the job of being stable.

This has a few cons:
- it makes the geometry below the ground plane unlike workbench engine.
- it makes overlays render over geometry at larger depth discontinuities.
This commit is contained in:
Clément Foucault
2022-07-24 17:54:09 +02:00
parent a5bcb4c148
commit b1c49b3b2a
3 changed files with 18 additions and 2 deletions

View File

@@ -111,7 +111,7 @@ class Instance {
bool overlays_enabled() const
{
return (!v3d) || ((v3d->flag & V3D_HIDE_OVERLAYS) == 0);
return v3d && ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0);
}
bool use_scene_lights() const

View File

@@ -26,4 +26,6 @@ void main()
}
gl_FragDepth = get_depth_from_view_z(-out_depth);
gl_FragDepth = film_display_depth_ammend(texel_film, gl_FragDepth);
}

View File

@@ -192,7 +192,7 @@ float film_distance_load(ivec2 texel)
/* Repeat texture coordinates as the weight can be optimized to a small portion of the film. */
texel = texel % imageSize(in_weight_img).xy;
if (film_buf.use_history == false) {
if (!film_buf.use_history || film_buf.use_reprojection) {
return 1.0e16;
}
return imageLoad(in_weight_img, ivec3(texel, WEIGHT_lAYER_DISTANCE)).x;
@@ -577,6 +577,20 @@ void film_store_weight(ivec2 texel, float value)
imageStore(out_weight_img, ivec3(texel, WEIGHT_lAYER_ACCUMULATION), vec4(value));
}
float film_display_depth_ammend(ivec2 texel, float depth)
{
/* This effectively offsets the depth of the whole 2x2 region to the lowest value of the region
* twice. One for X and one for Y direction. */
/* TODO(fclem): This could be improved as it gives flickering result at depth discontinuity.
* But this is the quickest stable result I could come with for now. */
#ifdef GPU_FRAGMENT_SHADER
depth += fwidth(depth);
#endif
/* Small offset to avoid depth test lessEqual failing because of all the conversions loss. */
depth += 2.4e-7 * 4.0;
return saturate(depth);
}
/** \} */
/** NOTE: out_depth is scene linear depth from the camera origin. */