Eevee: Shadows: Add Contact Shadows

This add the possibility to add screen space raytraced shadows to fix light leaking cause by shadows maps.

Theses inherit of the same artifacts as other screenspace methods.
This commit is contained in:
Clément Foucault 2017-10-06 23:43:36 +02:00
parent 9ab18d14f6
commit dfcdec914c
Notes: blender-bot 2023-02-14 06:27:50 +01:00
Referenced by issue #53095, Black cube on start and no material updates
10 changed files with 124 additions and 12 deletions

View File

@ -401,6 +401,19 @@ class DATA_PT_EEVEE_shadow(DataButtonsPanel, Panel):
sub.prop(lamp, "shadow_cascade_max_distance", text="Max Distance")
sub.prop(lamp, "shadow_cascade_exponent", text="Distribution")
layout.separator()
layout.prop(lamp, "use_contact_shadow")
split = layout.split()
split.active = lamp.use_contact_shadow
col = split.column()
col.prop(lamp, "contact_shadow_distance", text="Distance")
col.prop(lamp, "contact_shadow_soft_size", text="Soft")
col = split.column()
col.prop(lamp, "contact_shadow_bias", text="Bias")
col.prop(lamp, "contact_shadow_thickness", text="Thickness")
class DATA_PT_area(DataButtonsPanel, Panel):
bl_label = "Area Shape"

View File

@ -106,6 +106,10 @@ void BKE_lamp_init(Lamp *la)
la->cascade_count = 4;
la->cascade_exponent = 0.8f;
la->cascade_fade = 0.1f;
la->contact_dist = 1.0f;
la->contact_bias = 0.03f;
la->contact_spread = 0.2f;
la->contact_thickness = 0.5f;
curvemapping_initialize(la->curfalloff);
}

View File

@ -432,12 +432,23 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "cascade_max_dist")) {
for (Lamp *la = main->lamp.first; la; la = la->id.next) {
la->cascade_max_dist = 1000.0f;
la->cascade_count = 4;
la->cascade_exponent = 0.8f;
la->cascade_fade = 0.1f;
{
if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "cascade_max_dist")) {
for (Lamp *la = main->lamp.first; la; la = la->id.next) {
la->cascade_max_dist = 1000.0f;
la->cascade_count = 4;
la->cascade_exponent = 0.8f;
la->cascade_fade = 0.1f;
}
}
if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "contact_dist")) {
for (Lamp *la = main->lamp.first; la; la = la->id.next) {
la->contact_dist = 1.0f;
la->contact_bias = 0.03f;
la->contact_spread = 0.2f;
la->contact_thickness = 0.5f;
}
}
}

View File

@ -509,6 +509,11 @@ static void eevee_shadow_cube_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_La
ubo_data->shadow_start = (float)(sh_data->layer_id);
ubo_data->data_start = (float)(sh_data->cube_id);
ubo_data->multi_shadow_count = (float)(sh_nbr);
ubo_data->contact_dist = (la->mode & LA_SHAD_CONTACT) ? la->contact_dist : 0.0f;
ubo_data->contact_bias = 0.05f * la->contact_bias;
ubo_data->contact_spread = la->contact_spread;
ubo_data->contact_thickness = la->contact_thickness;
}
#define LERP(t, a, b) ((a) + (t) * ((b) - (a)))
@ -750,6 +755,11 @@ static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE
ubo_data->shadow_start = (float)(sh_data->layer_id);
ubo_data->data_start = (float)(sh_data->cascade_id);
ubo_data->multi_shadow_count = (float)(sh_nbr);
ubo_data->contact_dist = (la->mode & LA_SHAD_CONTACT) ? la->contact_dist : 0.0f;
ubo_data->contact_bias = 0.05f * la->contact_bias;
ubo_data->contact_spread = la->contact_spread;
ubo_data->contact_thickness = la->contact_thickness;
}
/* Used for checking if object is inside the shadow volume. */

View File

@ -221,6 +221,7 @@ typedef struct EEVEE_Light {
typedef struct EEVEE_Shadow {
float near, far, bias, exp;
float shadow_start, data_start, multi_shadow_count, pad;
float contact_dist, contact_bias, contact_spread, contact_thickness;
} EEVEE_Shadow;
typedef struct EEVEE_ShadowCube {

View File

@ -81,6 +81,7 @@ struct LightData {
struct ShadowData {
vec4 near_far_bias_exp;
vec4 shadow_data_start_end;
vec4 contact_shadow_data;
};
struct ShadowCubeData {
@ -102,6 +103,10 @@ struct ShadowCascadeData {
#define sh_tex_start shadow_data_start_end.x
#define sh_data_start shadow_data_start_end.y
#define sh_multi_nbr shadow_data_start_end.z
#define sh_contact_dist contact_shadow_data.x
#define sh_contact_offset contact_shadow_data.y
#define sh_contact_spread contact_shadow_data.z
#define sh_contact_thickness contact_shadow_data.w
/* ------- Convenience functions --------- */

View File

@ -144,7 +144,7 @@ float shadow_cascade(ShadowData sd, ShadowCascadeData scd, float texid, vec3 W)
/* ----------------------------------------------------------- */
#define MAX_MULTI_SHADOW 4
float light_visibility(LightData ld, vec3 W, vec4 l_vector)
float light_visibility(LightData ld, vec3 W, vec3 viewPosition, vec3 viewNormal, vec4 l_vector)
{
float vis = 1.0;
@ -169,6 +169,7 @@ float light_visibility(LightData ld, vec3 W, vec4 l_vector)
/* shadowing */
if (ld.l_shadowid >= 0.0) {
ShadowData data = shadows_data[int(ld.l_shadowid)];
if (ld.l_type == SUN) {
/* TODO : MSM */
// for (int i = 0; i < MAX_MULTI_SHADOW; ++i) {
@ -185,6 +186,35 @@ float light_visibility(LightData ld, vec3 W, vec4 l_vector)
data.sh_tex_start, W);
// }
}
#endif
#ifndef VOLUMETRICS
/* Only compute if not already in shadow. */
if ((vis > 0.001) && (data.sh_contact_dist > 0.0)) {
vec4 L = (ld.l_type != SUN) ? l_vector : vec4(-ld.l_forward, 1.0);
float trace_distance = (ld.l_type != SUN) ? min(data.sh_contact_dist, l_vector.w) : data.sh_contact_dist;
vec3 T, B;
make_orthonormal_basis(L.xyz / L.w, T, B);
vec3 rand = texture(utilTex, vec3(gl_FragCoord.xy / LUT_SIZE, 2.0)).xzw;
rand.yz *= rand.x * data.sh_contact_spread;
/* We use the full l_vector.xyz so that the spread is minimize
* if the shading point is further away from the light source */
vec3 ray_dir = L.xyz + T * rand.y + B * rand.z;
ray_dir = transform_direction(ViewMatrix, ray_dir);
ray_dir = normalize(ray_dir);
vec3 ray_origin = viewPosition + viewNormal * data.sh_contact_offset;
vec3 hit_pos = raycast(-1, ray_origin, ray_dir * trace_distance, data.sh_contact_thickness, rand.x, 0.75, 0.01);
if (hit_pos.z > 0.0) {
hit_pos = get_view_space_from_depth(hit_pos.xy, hit_pos.z);
float hit_dist = distance(viewPosition, hit_pos);
float dist_ratio = hit_dist / trace_distance;
return mix(0.0, vis, dist_ratio * dist_ratio * dist_ratio);
}
}
}
#endif

View File

@ -66,7 +66,7 @@ vec3 eevee_surface_lit(vec3 N, vec3 albedo, vec3 f0, float roughness, float ao,
l_vector.xyz = ld.l_position - worldPosition;
l_vector.w = length(l_vector.xyz);
vec3 l_color_vis = ld.l_color * light_visibility(ld, worldPosition, l_vector);
vec3 l_color_vis = ld.l_color * light_visibility(ld, worldPosition, viewPosition, viewNormal, l_vector);
#ifdef HAIR_SHADER
vec3 norm_lamp, view_vec;
@ -224,7 +224,7 @@ vec3 eevee_surface_clearcoat_lit(
l_vector.xyz = ld.l_position - worldPosition;
l_vector.w = length(l_vector.xyz);
vec3 l_color_vis = ld.l_color * light_visibility(ld, worldPosition, l_vector);
vec3 l_color_vis = ld.l_color * light_visibility(ld, worldPosition, viewPosition, viewNormal, l_vector);
#ifdef HAIR_SHADER
vec3 norm_lamp, view_vec;
@ -388,7 +388,7 @@ vec3 eevee_surface_diffuse_lit(vec3 N, vec3 albedo, float ao)
l_vector.xyz = ld.l_position - worldPosition;
l_vector.w = length(l_vector.xyz);
vec3 l_color_vis = ld.l_color * light_visibility(ld, worldPosition, l_vector);
vec3 l_color_vis = ld.l_color * light_visibility(ld, worldPosition, viewPosition, viewNormal, l_vector);
#ifdef HAIR_SHADER
vec3 norm_lamp, view_vec;
@ -480,7 +480,7 @@ vec3 eevee_surface_glossy_lit(vec3 N, vec3 f0, float roughness, float ao, int ss
l_vector.xyz = ld.l_position - worldPosition;
l_vector.w = length(l_vector.xyz);
vec3 l_color_vis = ld.l_color * light_visibility(ld, worldPosition, l_vector);
vec3 l_color_vis = ld.l_color * light_visibility(ld, worldPosition, viewPosition, viewNormal, l_vector);
#ifdef HAIR_SHADER
vec3 norm_lamp, view_vec;
@ -681,7 +681,7 @@ vec3 eevee_surface_glass(vec3 N, vec3 transmission_col, float roughness, float i
l_vector.xyz = ld.l_position - worldPosition;
l_vector.w = length(l_vector.xyz);
vec3 l_color_vis = ld.l_color * light_visibility(ld, worldPosition, l_vector);
vec3 l_color_vis = ld.l_color * light_visibility(ld, worldPosition, viewPosition, viewNormal, l_vector);
#ifdef HAIR_SHADER
vec3 norm_lamp, view_vec;

View File

@ -112,6 +112,8 @@ typedef struct Lamp {
float cascade_fade;
int cascade_count;
float contact_dist, contact_bias, contact_spread, contact_thickness;
/* preview */
struct PreviewImage *preview;
@ -157,6 +159,7 @@ typedef struct Lamp {
#define LA_SHAD_TEX (1 << 16)
#define LA_SHOW_CONE (1 << 17)
#define LA_SHOW_SHADOW_BOX (1 << 18)
#define LA_SHAD_CONTACT (1 << 19)
/* layer_shadow */
#define LA_LAYER_SHADOW_BOTH 0

View File

@ -699,6 +699,41 @@ static void rna_def_lamp_shadow(StructRNA *srna, int spot, int area, int sun)
RNA_def_property_ui_text(prop, "Shadow Layer", "Objects on the same layers only cast shadows");
RNA_def_property_update(prop, 0, "rna_Lamp_update");
/* Eevee */
prop = RNA_def_property(srna, "use_contact_shadow", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", LA_SHAD_CONTACT);
RNA_def_property_ui_text(prop, "Contact Shadow", "Use screen space raytracing to have correct shadowing "
"near occluder, or for small features that does not appear "
"in shadow maps");
RNA_def_property_update(prop, 0, "rna_Lamp_update");
prop = RNA_def_property(srna, "contact_shadow_distance", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "contact_dist");
RNA_def_property_range(prop, 0.0f, 9999.0f);
RNA_def_property_ui_text(prop, "Contact Shadow Distance", "World space distance in which to search for "
"screen space occluder");
RNA_def_property_update(prop, 0, "rna_Lamp_update");
prop = RNA_def_property(srna, "contact_shadow_bias", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "contact_bias");
RNA_def_property_range(prop, 0.001f, 9999.0f);
RNA_def_property_ui_range(prop, 0.001f, 5.0f, 1.0, 3);
RNA_def_property_ui_text(prop, "Contact Shadow Bias", "Bias to avoid self shadowing");
RNA_def_property_update(prop, 0, "rna_Lamp_update");
prop = RNA_def_property(srna, "contact_shadow_soft_size", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "contact_spread");
RNA_def_property_range(prop, 0.0f, 9999.0f);
RNA_def_property_ui_text(prop, "Contact Shadow Soft", "Control how soft the contact shadows will be");
RNA_def_property_update(prop, 0, "rna_Lamp_update");
prop = RNA_def_property(srna, "contact_shadow_thickness", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "contact_thickness");
RNA_def_property_range(prop, 0.0f, 9999.0f);
RNA_def_property_ui_range(prop, 0, 100, 0.1, 3);
RNA_def_property_ui_text(prop, "Contact Shadow Thickness", "Pixel thickness used to detect occlusion");
RNA_def_property_update(prop, 0, "rna_Lamp_update");
if (sun) {
prop = RNA_def_property(srna, "shadow_cascade_max_distance", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "cascade_max_dist");