[Bf-blender-cvs] [9e19ec0d181] tmp-eevee-shadowmap-refactor: Eevee: Shadows: Add Receiver Plane Depth Bias

Clément Foucault noreply at git.blender.org
Mon Sep 2 16:53:14 CEST 2019


Commit: 9e19ec0d181444793d26b8d5aa65b3fcc0ef3f1d
Author: Clément Foucault
Date:   Tue Aug 27 21:21:21 2019 +0200
Branches: tmp-eevee-shadowmap-refactor
https://developer.blender.org/rB9e19ec0d181444793d26b8d5aa65b3fcc0ef3f1d

Eevee: Shadows: Add Receiver Plane Depth Bias

This bias replace the previous bias method. The bias is now scalled to
have the correct depth of the triangle at the sample location. This is done
by computing the actual depth that would be recorded in the shadowmap
at the texels locations, if the triangle was extrapolated.

This leads to less shadow acne and it ensure the bias is always the minimum
amount that ensure correct shadowing.

However this technique is not failure free and if the receiver is nearly
parallel to the light, the bias is nearly infinite and light leaking occurs.

For this reason I decided to cap the bias by the bias parameter to tweak
between shadow acne and light leaking.

===================================================================

M	source/blender/draw/engines/eevee/eevee_lights.c
M	source/blender/draw/engines/eevee/eevee_materials.c
M	source/blender/draw/engines/eevee/eevee_subsurface.c
M	source/blender/draw/engines/eevee/shaders/lights_lib.glsl

===================================================================

diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c
index b4c833f4e89..4cebddb7104 100644
--- a/source/blender/draw/engines/eevee/eevee_lights.c
+++ b/source/blender/draw/engines/eevee/eevee_lights.c
@@ -425,7 +425,7 @@ void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
                                                            linfo->shadow_cube_size,
                                                            max_ii(1, linfo->num_cube_layer * 6),
                                                            shadow_pool_format,
-                                                           DRW_TEX_FILTER | DRW_TEX_COMPARE,
+                                                           DRW_TEX_FILTER,
                                                            NULL);
   }
 
@@ -434,7 +434,7 @@ void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
                                                               linfo->shadow_cascade_size,
                                                               max_ii(1, linfo->num_cascade_layer),
                                                               shadow_pool_format,
-                                                              DRW_TEX_FILTER | DRW_TEX_COMPARE,
+                                                              DRW_TEX_FILTER,
                                                               NULL);
   }
 
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index 3b1a6af7a75..f6f9af28975 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -1791,15 +1791,6 @@ void EEVEE_materials_free(void)
 
 void EEVEE_materials_draw_opaque(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl)
 {
-  /* We sample the shadowmaps using shadow sampler. We need to enable Comparison mode.
-   * TODO(fclem) avoid this by using sampler objects.*/
-  GPU_texture_bind(sldata->shadow_cube_pool, 0);
-  GPU_texture_compare_mode(sldata->shadow_cube_pool, true);
-  GPU_texture_unbind(sldata->shadow_cube_pool);
-  GPU_texture_bind(sldata->shadow_cascade_pool, 0);
-  GPU_texture_compare_mode(sldata->shadow_cascade_pool, true);
-  GPU_texture_unbind(sldata->shadow_cascade_pool);
-
   for (int i = 0; i < VAR_MAT_MAX; ++i) {
     if (psl->default_pass[i]) {
       DRW_draw_pass(psl->default_pass[i]);
diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c
index 4d29e597dae..ef1f546fffd 100644
--- a/source/blender/draw/engines/eevee/eevee_subsurface.c
+++ b/source/blender/draw/engines/eevee/eevee_subsurface.c
@@ -356,15 +356,6 @@ void EEVEE_subsurface_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
     }
 
     if (!DRW_pass_is_empty(psl->sss_translucency_ps)) {
-      /* We sample the shadowmaps using normal sampler. We need to disable Comparison mode.
-       * TODO(fclem) avoid this by using sampler objects.*/
-      GPU_texture_bind(sldata->shadow_cube_pool, 0);
-      GPU_texture_compare_mode(sldata->shadow_cube_pool, false);
-      GPU_texture_unbind(sldata->shadow_cube_pool);
-      GPU_texture_bind(sldata->shadow_cascade_pool, 0);
-      GPU_texture_compare_mode(sldata->shadow_cascade_pool, false);
-      GPU_texture_unbind(sldata->shadow_cascade_pool);
-
       GPU_framebuffer_bind(fbl->sss_translucency_fb);
       DRW_draw_pass(psl->sss_translucency_ps);
     }
diff --git a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
index 5ef59e82be1..5558e2ef074 100644
--- a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
@@ -1,6 +1,6 @@
 
-uniform sampler2DArrayShadow shadowCubeTexture;
-uniform sampler2DArrayShadow shadowCascadeTexture;
+uniform sampler2DArray shadowCubeTexture;
+uniform sampler2DArray shadowCascadeTexture;
 
 #define LAMPS_LIB
 
@@ -38,13 +38,12 @@ float cubeFaceIndexEEVEE(vec3 P)
   }
 }
 
-vec2 cubeFaceCoordEEVEE(vec3 P)
+vec2 cubeFaceCoordEEVEE(vec3 P, float face)
 {
-  vec3 aP = abs(P);
-  if (all(greaterThan(aP.xx, aP.yz))) {
+  if (face < 2.0) {
     return (P.zy / P.x) * vec2(-0.5, -sign(P.x) * 0.5) + 0.5;
   }
-  else if (all(greaterThan(aP.yy, aP.xz))) {
+  else if (face < 4.0) {
     return (P.xz / P.y) * vec2(sign(P.y) * 0.5, 0.5) + 0.5;
   }
   else {
@@ -52,19 +51,25 @@ vec2 cubeFaceCoordEEVEE(vec3 P)
   }
 }
 
-vec4 sample_cube(sampler2DArray tex, vec3 cubevec, float cube)
+float cubeFaceDepthEEVEE(vec3 P, float face)
 {
-  /* Manual Shadow Cube Layer indexing. */
-  /* TODO Shadow Cube Array. */
-  vec3 coord = vec3(cubeFaceCoordEEVEE(cubevec), cube * 6.0 + cubeFaceIndexEEVEE(cubevec));
-  return texture(tex, coord);
+  if (face < 2.0) {
+    return abs(P.x);
+  }
+  else if (face < 4.0) {
+    return abs(P.y);
+  }
+  else {
+    return abs(P.z);
+  }
 }
 
-float sample_cube(sampler2DArrayShadow tex, vec3 cubevec, float dist, float cube)
+vec4 sample_cube(sampler2DArray tex, vec3 cubevec, float cube)
 {
   /* Manual Shadow Cube Layer indexing. */
   /* TODO Shadow Cube Array. */
-  vec4 coord = vec4(cubeFaceCoordEEVEE(cubevec), cube * 6.0 + cubeFaceIndexEEVEE(cubevec), dist);
+  float face = cubeFaceIndexEEVEE(cubevec);
+  vec3 coord = vec3(cubeFaceCoordEEVEE(cubevec, face), cube * 6.0 + face);
   return texture(tex, coord);
 }
 
@@ -73,49 +78,160 @@ vec4 sample_cascade(sampler2DArray tex, vec2 co, float cascade_id)
   return texture(tex, vec3(co, cascade_id));
 }
 
-float sample_cascade(sampler2DArrayShadow tex, vec2 co, float dist, float cascade_id)
+/** Convert screenspace derivatives to texture space derivatives.
+ * As described by John R. Isidoro in GDC 2006 presentation "Shadow Mapping: GPU-based Tips and
+ *Techniques". https://developer.amd.com/wordpress/media/2012/10/Isidoro-ShadowMapping.pdf
+ **/
+vec2 texture_space_derivatives(vec3 duvfdx, vec3 duvfdy)
 {
-  return texture(tex, vec4(co, cascade_id, dist));
+  /* Invert texture Jacobian and use chain rule to compute ddist/du and ddist/dv
+   *  |ddist/du| = |du/dx  du/dy|-T  * |ddist/dx|
+   *  |ddist/dv|   |dv/dx  dv/dy|      |ddist/dy| */
+
+  /* // Multiply ddist/dx and ddist/dy by inverse transpose of Jacobian
+   * float invDet = 1 / ((duvdist_dx.x * duvdist_dy.y) - (duvdist_dx.y * duvdist_dy.x));
+   * // Top row of 2x2
+   * ddist_duv.x = duvdist_dy.y * duvdist_dx.w;  // invJtrans[0][0] * ddist_dx
+   * ddist_duv.x -= duvdist_dx.y * duvdist_dy.w; // invJtrans[0][1] * ddist_dy
+   * // Bottom row of 2x2
+   * ddist_duv.y = duvdist_dx.x * duvdist_dy.w;  // invJtrans[1][1] * ddist_dy
+   * ddist_duv.y -= duvdist_dy.x * duvdist_dx.w; // invJtrans[1][0] * ddist_dx
+   * ddist_duv *= invDet;
+   **/
+
+  /* Optimized version. */
+  vec2 a = duvfdx.xy * duvfdy.yx;
+  vec4 b = duvfdy.yzzx * duvfdx.zyxz;
+  return (b.xz - b.yw) / (a.x - a.y);
+}
+
+/** Returns Receiver Plane Depth Bias
+ * As described by John R. Isidoro in GDC 2006 presentation "Shadow Mapping: GPU-based Tips and
+ * Techniques". https://developer.amd.com/wordpress/media/2012/10/Isidoro-ShadowMapping.pdf
+ */
+float shadowmap_bias(vec2 co, vec2 tap_co, vec2 dwduv)
+{
+  return dot(tap_co - co, dwduv);
+}
+
+/**
+ * Parameters:
+ * shadow_tx : shadowmap to sample.
+ * co        : the original sample position.
+ * ref       : the original depth to test (Depth of the surface in shadowmap space).
+ * co_ofs    : the actual offseted sample position.
+ * dwduv     : result of texture_space_derivatives().
+ **/
+float filtered_and_biased_shadow_test(sampler2DArray shadow_tx,
+                                      vec2 co,
+                                      float layer,
+                                      float ref,
+                                      float max_bias,
+                                      vec2 co_ofs,
+                                      vec2 dwduv)
+{
+  vec4 biases, depths;
+  vec2 texture_size = vec2(textureSize(shadow_tx, 0).xy);
+  vec3 texel_size = vec3(1.0 / texture_size, 0.0);
+  /* Center texel coordinate to match hardware filtering */
+  vec2 texel_uv = co_ofs * texture_size.xy - 0.5;
+  vec2 texel_fract = fract(texel_uv);
+  vec2 texel_floor = (floor(texel_uv) + 0.5) * texel_size.xy;
+  /* Calc bias for each sample */
+  biases.x = shadowmap_bias(co, texel_floor + texel_size.zy, dwduv);
+  biases.y = shadowmap_bias(co, texel_floor + texel_size.xy, dwduv);
+  biases.z = shadowmap_bias(co, texel_floor + texel_size.xz, dwduv);
+  biases.w = shadowmap_bias(co, texel_floor + texel_size.zz, dwduv);
+  /* Gather samples */
+#ifdef GPU_ARB_texture_gather
+  /* Note: To make sure that we get the exact same result we use texel center.
+   * This is because Anisotropic filtering is offsetting the coordinate. */
+  depths = textureGather(shadow_tx, vec3(texel_floor + texel_size.xy * 0.5, layer));
+#else
+  depths.x = texture(shadow_tx, vec3(texel_floor + texel_size.zy, layer)).x;
+  depths.y = texture(shadow_tx, vec3(texel_floor + texel_size.xy, layer)).x;
+  depths.z = texture(shadow_tx, vec3(texel_floor + texel_size.xz, layer)).x;
+  depths.w = texture(shadow_tx, vec3(texel_floor + texel_size.zz, layer)).x;
+#endif
+  /* Take absolute of bias to avoid overshadowing in proximity area.
+   * Also limit the bias in case the geom is almost perpendicular to the shadow source
+   * to avoid light leaking. */
+  vec4 refs = saturate(ref - min(vec4(max_bias), abs(biases)));
+  /* Bilinear PCF. */
+  vec4 tests = step(refs, depths);
+  tests.xy = mix(tests.wz, tests.xy, texel_fract.y);
+  return saturate(mix(tests.x, tests.y, texel_fract.x));
 }
 
 float shadow_cubemap(ShadowData sd, ShadowCubeData scd, float texid, vec3 W)
 {
   vec3 cubevec = W - scd.position.xyz;
-  float dist = max_v3(abs(cubevec));
-  float bias = sd.sh_bias;
 
 #ifndef VOLUMETRICS
   vec3 rand = texelfetch_noise_tex(gl_FragCoord.xy).zwy;
   float ofs_len = fast_sqrt(rand.z) * sd.sh_blur * 0.1;
-  bias *= ofs_len * 400.0;
-  cubevec = normalize(cubevec);
+  vec3 cubevec_nor = normalize(cubevec);
   vec3 T, B;
-  make_orth

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list