Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2019-10-16 19:53:19 +0300
committerClément Foucault <foucault.clem@gmail.com>2019-10-16 19:58:20 +0300
commit131ac2ec82b9e810dd6e0153009a71276b6d6f13 (patch)
treed96401e740a40d9caab5baa3b61092c2a908ea78 /source/blender/draw
parent4ddf3215a7df3ac4a0cfceccb283414510078ba5 (diff)
Fix T70249 EEVEE: Light bleeding on SSS translucency
This was caused by 2 things: Shadow map bias and aliasing. It made the expected depth of the shadowmap further than the surface itself in some cases. In normal time this leads to light leaking on normal shadow mapping but here we need to always have the shadowmap depth above the shading point. To fix this, we use a 5 tap inflate filter using the minimum depth of all 5 samples. Using these 5 taps, we can deduce entrance surface derivatives and there orientation towards the light ray. We use these derivatives to bias the depth to avoid wrong depth at depth discontinuity in the shadowmap. This bias can lead to some shadowleaks that are less distracting than the lightleaks it fixes. We also add a small bias to counteract the shadowmap depth precision.
Diffstat (limited to 'source/blender/draw')
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl8
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl76
-rw-r--r--source/blender/draw/engines/eevee/shaders/lights_lib.glsl1
3 files changed, 73 insertions, 12 deletions
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
index 1f68935403c..511c243b474 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
@@ -140,6 +140,10 @@ float min_v3(vec3 v)
{
return min(v.x, min(v.y, v.z));
}
+float min_v4(vec4 v)
+{
+ return min(min(v.x, v.y), min(v.z, v.w));
+}
float max_v2(vec2 v)
{
return max(v.x, v.y);
@@ -148,6 +152,10 @@ float max_v3(vec3 v)
{
return max(v.x, max(v.y, v.z));
}
+float max_v4(vec4 v)
+{
+ return max(max(v.x, v.y), max(v.z, v.w));
+}
float sum(vec2 v)
{
diff --git a/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl
index 86f53522bc6..6531ceb8dbe 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl
@@ -70,6 +70,18 @@ float light_translucent_power_with_falloff(LightData ld, vec3 N, vec4 l_vector)
#define scube(x) shadows_cube_data[x]
#define scascade(x) shadows_cascade_data[x]
+float shadow_cube_radial_depth(vec3 cubevec, float tex_id, int shadow_id)
+{
+ float depth = sample_cube(sssShadowCubes, cubevec, tex_id).r;
+ /* To reverting the constant bias from shadow rendering. (Tweaked for 16bit shadowmaps) */
+ const float depth_bias = 3.1e-5;
+ depth = saturate(depth - depth_bias);
+
+ depth = linear_depth(true, depth, sd(shadow_id).sh_far, sd(shadow_id).sh_near);
+ depth *= length(cubevec / max_v3(abs(cubevec)));
+ return depth;
+}
+
vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, vec2 rand, float sss_scale)
{
int shadow_id = int(ld.l_shadowid);
@@ -79,12 +91,12 @@ vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, vec2 rand, f
/* We use the full l_vector.xyz so that the spread is minimize
* if the shading point is further away from the light source */
/* TODO(fclem) do something better than this. */
- // vec3 T, B;
- // make_orthonormal_basis(L.xyz / L.w, T, B);
- // rand.xy *= data.sh_blur;
- // W = W + T * rand.x + B * rand.y;
+ vec3 T, B;
+ make_orthonormal_basis(L.xyz / L.w, T, B);
- float s, dist;
+ vec3 n;
+ vec4 depths;
+ float d, dist;
int data_id = int(sd(shadow_id).sh_data_index);
if (ld.l_type == SUN) {
vec4 view_z = vec4(dot(W - cameraPos, cameraForward));
@@ -105,20 +117,62 @@ vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, vec2 rand, f
return vec3(0.0);
}
- float tex_id = scascade(data_id).sh_tex_index;
- s = sample_cascade(sssShadowCascades, shpos.xy, tex_id + id).r;
- s *= range;
+ float tex_id = scascade(data_id).sh_tex_index + id;
+
+ /* Assume cascades have same height and width. */
+ vec2 ofs = vec2(1.0, 0.0) / float(textureSize(sssShadowCascades, 0).x);
+ d = sample_cascade(sssShadowCascades, shpos.xy, tex_id).r;
+ depths.x = sample_cascade(sssShadowCascades, shpos.xy + ofs.xy, tex_id).r;
+ depths.y = sample_cascade(sssShadowCascades, shpos.xy + ofs.yx, tex_id).r;
+ depths.z = sample_cascade(sssShadowCascades, shpos.xy - ofs.xy, tex_id).r;
+ depths.w = sample_cascade(sssShadowCascades, shpos.xy - ofs.yx, tex_id).r;
+
+ /* To reverting the constant bias from shadow rendering. (Tweaked for 16bit shadowmaps) */
+ float depth_bias = 3.1e-5;
+ depths = saturate(depths - depth_bias);
+ d = saturate(d - depth_bias);
+
+ /* Size of a texel in world space.
+ * FIXME This is only correct if l_right is the same right vector used for shadowmap creation.
+ * This won't work if the shadow matrix is rotated (soft shadows).
+ * TODO precompute */
+ float unit_world_in_uv_space = length(mat3(scascade(data_id).shadowmat[int(id)]) * ld.l_right);
+ float dx_scale = 2.0 * ofs.x / unit_world_in_uv_space;
+
+ d *= range;
+ depths *= range;
+
+ /* This is the normal of the occluder in world space. */
+ // vec3 T = ld.l_forward * dx + ld.l_right * dx_scale;
+ // vec3 B = ld.l_forward * dy + ld.l_up * dx_scale;
+ // n = normalize(cross(T, B));
}
else {
+ float ofs = 1.0 / float(textureSize(sssShadowCubes, 0).x);
+
vec3 cubevec = transform_point(scube(data_id).shadowmat, W);
dist = length(cubevec);
cubevec /= dist;
/* tex_id == data_id for cube shadowmap */
float tex_id = float(data_id);
- s = sample_cube(sssShadowCubes, cubevec, tex_id).r;
- s = length(cubevec / max_v3(abs(cubevec))) *
- linear_depth(true, s, sd(shadow_id).sh_far, sd(shadow_id).sh_near);
+ d = shadow_cube_radial_depth(cubevec, tex_id, shadow_id);
+ /* NOTE: The offset is irregular in respect to cubeface uvs. But it has
+ * a much more uniform behavior than biasing based on face derivatives. */
+ depths.x = shadow_cube_radial_depth(cubevec + T * ofs, tex_id, shadow_id);
+ depths.y = shadow_cube_radial_depth(cubevec + B * ofs, tex_id, shadow_id);
+ depths.z = shadow_cube_radial_depth(cubevec - T * ofs, tex_id, shadow_id);
+ depths.w = shadow_cube_radial_depth(cubevec - B * ofs, tex_id, shadow_id);
}
+
+ float dx = depths.x - depths.z;
+ float dy = depths.y - depths.w;
+
+ float s = min(d, min_v4(depths));
+
+ /* To avoid light leak from depth discontinuity and shadowmap aliasing. */
+ float slope_bias = (abs(dx) + abs(dy)) * 0.5;
+ s -= slope_bias;
+
float delta = dist - s;
float power = light_translucent_power_with_falloff(ld, N, l_vector);
diff --git a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
index b1c78cae54f..6427f02ed25 100644
--- a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
@@ -70,7 +70,6 @@ vec2 cubeFaceCoordEEVEE(vec3 P, float face, sampler2DArrayShadow tex)
vec4 sample_cube(sampler2DArray tex, vec3 cubevec, float cube)
{
/* Manual Shadow Cube Layer indexing. */
- /* TODO Shadow Cube Array. */
float face = cubeFaceIndexEEVEE(cubevec);
vec2 uv = cubeFaceCoordEEVEE(cubevec, face, tex);