Eevee: Shadows: Add Contact Shadows
authorClément Foucault <foucault.clem@gmail.com>
Fri, 6 Oct 2017 21:43:36 +0000 (23:43 +0200)
committerClément Foucault <foucault.clem@gmail.com>
Fri, 6 Oct 2017 21:44:22 +0000 (23:44 +0200)
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.

release/scripts/startup/bl_ui/properties_data_lamp.py
source/blender/blenkernel/intern/lamp.c
source/blender/blenloader/intern/versioning_280.c
source/blender/draw/engines/eevee/eevee_lights.c
source/blender/draw/engines/eevee/eevee_private.h
source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
source/blender/draw/engines/eevee/shaders/lamps_lib.glsl
source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl
source/blender/makesdna/DNA_lamp_types.h
source/blender/makesrna/intern/rna_lamp.c

index 861ad81cdccd0c7b74951306a592c82bf51a754e..40ebdbda75d136b3a8ae1b8761c2c72930c598fe 100644 (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"
index a9c85376a487bad54379c4218a43c1b861d2d6e9..3d0d5f87f15498befe433c4538652555378c7287 100644 (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);
 }
index f022b393967188f8362070eb5f73cb3ccd66c4bc..bc011824c407c3e71508acb8e355786eda516ff4 100644 (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;
+                       }
                }
        }
 
index 20344d46c50c65ebf161cd14c3d9132be50ae649..8138b9a0ffd8b0baf610ab05be620d6a81a52542 100644 (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. */
index 392b4bfe24acb962b6ccc8476fece942fd15cd68..9d93097b7fdeefad1d0f02802c1d1dc12a2bfa29 100644 (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 {
index c841acd3c2348dd47250a70358db5fa30e47d558..3e0e36cad24c7206724709bf5a57664e7e82fd45 100644 (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 --------- */
 
index 676aa2c97489d69f3c271eed0da48404a678ca09..a39f04d47af7befe0dabc22b60e21c8b9b35c28c 100644 (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
 
index 5f4a4c9f89fb2ae411e5c5b65243567f501d09d9..f63a9665810430f5ece7fadfe12ef5f536d2658b 100644 (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;
index 4c99b062f276be5af8f08b1663e2431538ae1496..92703fa2d3b36ddf213f9b1f27162fb7a4aee745 100644 (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
index 15dabba0c4d54306fbe4aec908e3f9eaeda36436..e40183e40b5d03576f8bfc14555bbc9b09e31e03 100644 (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");