EEVEE-Next: Remove slope and quantization biases

This avoid self intersection during tracing which expect
unbiased depth. We compensate by adding a 1.5 shadow pixel
offset in the normal direction which is enough to fix
most remaining self shadowing. But another bias parameter
will likely need to be added anyway.

Fixes #121194
This commit is contained in:
Clément Foucault
2024-04-29 17:03:54 +02:00
parent 387df16755
commit 760a641023
3 changed files with 20 additions and 16 deletions

View File

@@ -107,6 +107,21 @@ float light_attenuation_common(LightData light, const bool is_directional, vec3
return 1.0;
}
float light_shape_radius(LightData light)
{
float radius;
if (is_sun_light(light.type)) {
return light_sun_data_get(light).radius;
}
else if (is_area_light(light.type)) {
return length(light_area_data_get(light).size);
}
else {
return light_spot_data_get(light).radius;
}
}
/**
* Fade light influence when surface is not facing the light.
* This is needed because LTC leaks light at roughness not 0 or 1
@@ -126,18 +141,8 @@ float light_attenuation_facing(LightData light,
return 1.0;
}
float radius;
if (is_sun_light(light.type)) {
radius = light_sun_data_get(light).radius;
}
else if (is_area_light(light.type)) {
radius = length(light_area_data_get(light).size);
}
else {
radius = light_spot_data_get(light).radius;
}
/* Sine of angle between light center and light edge. */
float sin_solid_angle = radius / distance_to_light;
float sin_solid_angle = light_shape_radius(light) / distance_to_light;
/* Sine of angle between light center and shading plane. */
float sin_light_angle = dot(L, Ng);
/* Do attenuation after the horizon line to avoid harsh cut

View File

@@ -486,7 +486,10 @@ float shadow_normal_offset(float texel_radius, vec3 Ng, vec3 L)
/* TODO: Should we take the light shape into consideration? */
float cos_theta = abs(dot(Ng, L));
float sin_theta = sqrt(saturate(1.0 - square(cos_theta)));
return texel_radius * sin_theta;
/* Note that we still bias by one pixel anyway to fight quantization artifacts.
* This helps with self intersection of slopped surfaces and gives softer soft shadow (?! why).
* FIXME: This is likely to hide some issue, and we need a user facing bias parameter anyway. */
return texel_radius * (sin_theta + 3.0);
}
/**

View File

@@ -29,8 +29,6 @@ void main()
* Note that we always need a minimum slope bias of 1 pixel to avoid slanted surfaces aliasing
* onto facing surfaces.
* IMPORTANT: `fwidth` needs to be inside uniform control flow. */
f_depth += fwidth(f_depth) * shadow_flat.filter_radius;
#ifdef SHADOW_UPDATE_TBDR
/* We need to write to `gl_FragDepth` un-conditionally. So we cannot early exit or use discard. */
# define discard_result f_depth = 1.0;
@@ -86,8 +84,6 @@ void main()
ivec3 out_texel = ivec3((page.xy << page_shift) | texel_page, page.z);
uint u_depth = floatBitsToUint(f_depth);
/* Quantization bias. Equivalent to `nextafter()` in C without all the safety. */
u_depth += 2;
imageAtomicMin(shadow_atlas_img, out_texel, u_depth);
#endif