diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py index fbc19a4c83e..d64570b07ca 100644 --- a/release/scripts/startup/bl_ui/properties_render.py +++ b/release/scripts/startup/bl_ui/properties_render.py @@ -748,6 +748,7 @@ class RENDER_PT_eevee_shadows(RenderButtonsPanel, Panel): col.prop(props, "shadow_cube_size", text="Cube Size") col.prop(props, "shadow_cascade_size", text="Cascade Size") col.prop(props, "use_shadow_high_bitdepth") + col.prop(props, "use_soft_shadows") class RENDER_PT_eevee_sampling(RenderButtonsPanel, Panel): diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index fdd908dbc44..1d173e6d3fc 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -168,7 +168,7 @@ static void eevee_cache_finish(void *vedata) EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); EEVEE_materials_cache_finish(vedata); - EEVEE_lights_cache_finish(sldata); + EEVEE_lights_cache_finish(sldata, vedata); EEVEE_lightprobes_cache_finish(sldata, vedata); } @@ -249,7 +249,7 @@ static void eevee_draw_background(void *vedata) /* Refresh shadows */ DRW_stats_group_start("Shadows"); - EEVEE_draw_shadows(sldata, psl); + EEVEE_draw_shadows(sldata, vedata); DRW_stats_group_end(); GPU_framebuffer_bind(fbl->main_fb); diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c index 425749b0b52..e0616ae9dfe 100644 --- a/source/blender/draw/engines/eevee/eevee_lightcache.c +++ b/source/blender/draw/engines/eevee/eevee_lightcache.c @@ -709,7 +709,7 @@ static void eevee_lightbake_cache_create(EEVEE_Data *vedata, EEVEE_LightBake *lb DRW_render_object_iter(vedata, NULL, lbake->depsgraph, EEVEE_render_cache); EEVEE_materials_cache_finish(vedata); - EEVEE_lights_cache_finish(sldata); + EEVEE_lights_cache_finish(sldata, vedata); EEVEE_lightprobes_cache_finish(sldata, vedata); txl->color = NULL; diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index 3d236a5ddd9..d1e798098bb 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -972,7 +972,7 @@ static void lightbake_render_scene_face(int face, EEVEE_BakeRenderData *user_dat struct GPUFrameBuffer **face_fb = user_data->face_fb; /* Be sure that cascaded shadow maps are updated. */ - EEVEE_draw_shadows(sldata, psl); + EEVEE_draw_shadows(sldata, user_data->vedata); GPU_framebuffer_bind(face_fb[face]); GPU_framebuffer_clear_depth(face_fb[face], 1.0f); @@ -1028,7 +1028,7 @@ static void lightbake_render_scene_reflected(int layer, EEVEE_BakeRenderData *us DRW_stats_group_start("Planar Reflection"); /* Be sure that cascaded shadow maps are updated. */ - EEVEE_draw_shadows(sldata, psl); + EEVEE_draw_shadows(sldata, vedata); /* Since we are rendering with an inverted view matrix, we need * to invert the facing for backface culling to be the same. */ DRW_state_invert_facing(); diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c index 7319572d7eb..44bc4653037 100644 --- a/source/blender/draw/engines/eevee/eevee_lights.c +++ b/source/blender/draw/engines/eevee/eevee_lights.c @@ -26,6 +26,7 @@ #include "DRW_render.h" #include "BLI_dynstr.h" +#include "BLI_rand.h" #include "BLI_rect.h" #include "BKE_object.h" @@ -38,6 +39,7 @@ #define SHADOW_CASTER_ALLOC_CHUNK 16 // #define DEBUG_CSM +// #define DEBUG_SHADOW_DISTRIBUTION static struct { struct GPUShader *shadow_sh; @@ -138,6 +140,7 @@ void EEVEE_lights_init(EEVEE_ViewLayerData *sldata) int sh_cube_size = scene_eval->eevee.shadow_cube_size; int sh_cascade_size = scene_eval->eevee.shadow_cascade_size; const bool sh_high_bitdepth = (scene_eval->eevee.flag & SCE_EEVEE_SHADOW_HIGH_BITDEPTH) != 0; + sldata->lamps->soft_shadows = (scene_eval->eevee.flag & SCE_EEVEE_SHADOW_SOFT) != 0; EEVEE_LampsInfo *linfo = sldata->lamps; if ((linfo->shadow_cube_size != sh_cube_size) || @@ -518,7 +521,7 @@ void EEVEE_lights_cache_shcaster_object_add(EEVEE_ViewLayerData *sldata, Object oedata->need_update = false; } -void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata) +void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_LampsInfo *linfo = sldata->lamps; GPUTextureFormat shadow_pool_format = GPU_R32F; @@ -587,7 +590,7 @@ void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata) }); /* Update Lamps UBOs. */ - EEVEE_lights_update(sldata); + EEVEE_lights_update(sldata, vedata); } /* Update buffer with lamp data */ @@ -670,7 +673,108 @@ static void eevee_light_setup(Object *ob, EEVEE_Light *evli) evli->shadowid = -1.0f; } -static void eevee_shadow_cube_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngineData *led) +/** + * Special ball distribution: + * Point are distributed in a way that when they are orthogonaly + * projected into any plane, the resulting distribution is (close to) + * a uniform disc distribution. + **/ +static void sample_ball(int sample_ofs, float radius, float rsample[3]) +{ + double ht_point[3]; + double ht_offset[3] = {0.0, 0.0, 0.0}; + uint ht_primes[3] = {2, 3, 7}; + + BLI_halton_3D(ht_primes, ht_offset, sample_ofs, ht_point); + + float omega = ht_point[1] * 2.0f * M_PI; + + rsample[2] = ht_point[0] * 2.0f - 1.0f; /* cos theta */ + + float r = sqrtf(fmaxf(0.0f, 1.0f - rsample[2]*rsample[2])); /* sin theta */ + + rsample[0] = r * cosf(omega); + rsample[1] = r * sinf(omega); + + radius *= sqrt(sqrt(ht_point[2])); + mul_v3_fl(rsample, radius); +} + +static void sample_rectangle( + int sample_ofs, float x_axis[3], float y_axis[3], float size_x, float size_y, + float rsample[3]) +{ + double ht_point[2]; + double ht_offset[2] = {0.0, 0.0}; + uint ht_primes[2] = {2, 3}; + + BLI_halton_2D(ht_primes, ht_offset, sample_ofs, ht_point); + + /* Change ditribution center to be 0,0 */ + ht_point[0] = (ht_point[0] > 0.5f) ? ht_point[0] - 1.0f : ht_point[0]; + ht_point[1] = (ht_point[1] > 0.5f) ? ht_point[1] - 1.0f : ht_point[1]; + + zero_v3(rsample); + madd_v3_v3fl(rsample, x_axis, (ht_point[0] * 2.0f) * size_x); + madd_v3_v3fl(rsample, y_axis, (ht_point[1] * 2.0f) * size_y); +} + +static void sample_ellipse( + int sample_ofs, float x_axis[3], float y_axis[3], float size_x, float size_y, + float rsample[3]) +{ + double ht_point[2]; + double ht_offset[2] = {0.0, 0.0}; + uint ht_primes[2] = {2, 3}; + + BLI_halton_2D(ht_primes, ht_offset, sample_ofs, ht_point); + + /* Uniform disc sampling. */ + float omega = ht_point[1] * 2.0f * M_PI; + float r = sqrtf(ht_point[0]); + ht_point[0] = r * cosf(omega) * size_x; + ht_point[1] = r * sinf(omega) * size_y; + + zero_v3(rsample); + madd_v3_v3fl(rsample, x_axis, ht_point[0]); + madd_v3_v3fl(rsample, y_axis, ht_point[1]); +} + + +static void shadow_cube_random_position_set( + EEVEE_Light *evli, Lamp *la, + int sample_ofs, + float ws_sample_pos[3]) +{ + float jitter[3]; + +#ifndef DEBUG_SHADOW_DISTRIBUTION + int i = sample_ofs; +#else + for (int i = 1; i <= sample_ofs; ++i) { +#endif + switch (la->type) { + case LA_AREA: + if (ELEM(la->area_shape, LA_AREA_RECT, LA_AREA_SQUARE)) { + sample_rectangle(i, evli->rightvec, evli->upvec, evli->sizex, evli->sizey, jitter); + } + else { + sample_ellipse(i, evli->rightvec, evli->upvec, evli->sizex, evli->sizey, jitter); + } + break; + default: + sample_ball(i, evli->radius, jitter); + } +#ifdef DEBUG_SHADOW_DISTRIBUTION + float p[3]; + add_v3_v3v3(p, jitter, ws_sample_pos); + DRW_debug_sphere(p, 0.01f, (float[4]){1.0f, (sample_ofs == i) ? 1.0f : 0.0f, 0.0f, 1.0f}); + } +#endif + add_v3_v3(ws_sample_pos, jitter); +} + +static void eevee_shadow_cube_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngineData *led, int sample_ofs) { EEVEE_ShadowCubeData *sh_data = &led->data.scd; EEVEE_Light *evli = linfo->light_data + sh_data->light_id; @@ -678,11 +782,10 @@ static void eevee_shadow_cube_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_La EEVEE_ShadowCube *cube_data = linfo->shadow_cube_data + sh_data->cube_id; Lamp *la = (Lamp *)ob->data; - int sh_nbr = 1; /* TODO: MSM */ + copy_v3_v3(cube_data->position, ob->obmat[3]); - for (int i = 0; i < sh_nbr; ++i) { - /* TODO : choose MSM sample point here. */ - copy_v3_v3(cube_data->position, ob->obmat[3]); + if (linfo->soft_shadows) { + shadow_cube_random_position_set(evli, la, sample_ofs, cube_data->position); } ubo_data->bias = 0.05f * la->bias; @@ -693,7 +796,6 @@ static void eevee_shadow_cube_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_La evli->shadowid = (float)(sh_data->shadow_id); 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->shadow_blur = la->soft * 0.02f; /* Used by translucence shadowmap blur */ ubo_data->contact_dist = (la->mode & LA_SHAD_CONTACT) ? la->contact_dist : 0.0f; @@ -702,6 +804,27 @@ static void eevee_shadow_cube_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_La ubo_data->contact_thickness = la->contact_thickness; } +static void shadow_cascade_random_matrix_set(float mat[4][4], float radius, int sample_ofs) +{ + float jitter[3]; + +#ifndef DEBUG_SHADOW_DISTRIBUTION + int i = sample_ofs; +#else + for (int i = 1; i <= sample_ofs; ++i) { +#endif + sample_ellipse(i, mat[0], mat[1], radius, radius, jitter); +#ifdef DEBUG_SHADOW_DISTRIBUTION + float p[3]; + add_v3_v3v3(p, jitter, mat[2]); + DRW_debug_sphere(p, 0.01f, (float[4]){1.0f, (sample_ofs == i) ? 1.0f : 0.0f, 0.0f, 1.0f}); + } +#endif + + add_v3_v3(mat[2], jitter); + orthogonalize_m4(mat, 2); +} + #define LERP(t, a, b) ((a) + (t) * ((b) - (a))) static double round_to_digits(double value, int digits) @@ -752,7 +875,7 @@ static void frustum_min_bounding_sphere(const float corners[8][3], float r_cente static void eevee_shadow_cascade_setup( Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngineData *led, - DRWMatrixState *saved_mats, float view_near, float view_far) + DRWMatrixState *saved_mats, float view_near, float view_far, int sample_ofs) { Lamp *la = (Lamp *)ob->data; @@ -762,7 +885,6 @@ static void eevee_shadow_cascade_setup( bool is_persp = DRW_viewport_is_persp_get(); /* Lamps Matrices */ - int sh_nbr = 1; /* TODO : MSM */ int cascade_nbr = la->cascade_count; EEVEE_ShadowCascadeData *sh_data = &led->data.scad; @@ -776,8 +898,13 @@ static void eevee_shadow_cascade_setup( #if 0 /* done at culling time */ normalize_m4_m4(viewmat, ob->obmat); #endif + + if (linfo->soft_shadows) { + shadow_cascade_random_matrix_set(viewmat, evli->radius, sample_ofs); + } + + copy_m4_m4(sh_data->viewinv, viewmat); invert_m4(viewmat); - invert_m4_m4(sh_data->viewinv, viewmat); /* The technique consists into splitting * the view frustum into several sub-frustum @@ -953,7 +1080,6 @@ static void eevee_shadow_cascade_setup( evli->shadowid = (float)(sh_data->shadow_id); 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->shadow_blur = la->soft * 0.02f; /* Used by translucence shadowmap blur */ ubo_data->contact_dist = (la->mode & LA_SHAD_CONTACT) ? la->contact_dist : 0.0f; @@ -974,8 +1100,10 @@ static bool sphere_bbox_intersect(const EEVEE_BoundSphere *bs, const EEVEE_Bound return x && y && z; } -void EEVEE_lights_update(EEVEE_ViewLayerData *sldata) +void EEVEE_lights_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; EEVEE_LampsInfo *linfo = sldata->lamps; Object *ob; int i; @@ -1031,8 +1159,8 @@ void EEVEE_lights_update(EEVEE_ViewLayerData *sldata) for (i = 0; (i < MAX_SHADOW_CUBE) && (ob = linfo->shadow_cube_ref[i]); i++) { EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob); - eevee_shadow_cube_setup(ob, linfo, led); - if (lightbits_get(&update_bits, i) != 0) { + eevee_shadow_cube_setup(ob, linfo, led, effects->taa_current_sample - 1); + if (lightbits_get(&update_bits, i) != 0 || linfo->soft_shadows) { led->need_update = true; } } @@ -1047,8 +1175,11 @@ void EEVEE_lights_update(EEVEE_ViewLayerData *sldata) } /* this refresh lamps shadow buffers */ -void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) +void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; EEVEE_LampsInfo *linfo = sldata->lamps; Object *ob; int i; @@ -1071,6 +1202,7 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) EEVEE_ShadowCascadeData *sh_data = &led->data.scad; float plane[4]; normalize_m4_m4(sh_data->viewmat, ob->obmat); + plane_from_point_normal_v3(plane, sh_data->viewmat[3], sh_data->viewmat[2]); /* TODO: check against near/far instead of "local Z = 0" plane. * Or even the cascades AABB. */ @@ -1098,12 +1230,13 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) EEVEE_ShadowRender *srd = &linfo->shadow_render_data; EEVEE_ShadowCubeData *evscd = &led->data.scd; + EEVEE_ShadowCube *cube_data = linfo->shadow_cube_data + evscd->cube_id; perspective_m4(winmat, -la->clipsta, la->clipsta, -la->clipsta, la->clipsta, la->clipsta, la->clipend); srd->clip_near = la->clipsta; srd->clip_far = la->clipend; - copy_v3_v3(srd->position, ob->obmat[3]); + copy_v3_v3(srd->position, cube_data->position); srd->stored_texel_size = 1.0 / (float)linfo->shadow_cube_store_size; @@ -1178,7 +1311,9 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) DRWPass *store_pass = eevee_lights_cube_store_pass_get(psl, sldata, linfo->shadow_method, srd->shadow_samples_len); DRW_draw_pass(store_pass); - led->need_update = false; + if (linfo->soft_shadows == false) { + led->need_update = false; + } } linfo->update_flag &= ~LIGHT_UPDATE_SHADOW_CUBE; DRW_stats_group_end(); @@ -1205,7 +1340,7 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) float (*viewmat)[4] = render_mats.mat[DRW_MAT_VIEW]; float (*persmat)[4] = render_mats.mat[DRW_MAT_PERS]; - eevee_shadow_cascade_setup(ob, linfo, led, &saved_mats, near, far); + eevee_shadow_cascade_setup(ob, linfo, led, &saved_mats, near, far, effects->taa_current_sample); srd->clip_near = la->clipsta; srd->clip_far = la->clipend; diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 7a0180074f5..fbabf86074e 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -413,7 +413,7 @@ typedef struct EEVEE_LampsInfo { int cpu_cube_len, cpu_cascade_len; int update_flag; int shadow_cube_size, shadow_cascade_size, shadow_method; - bool shadow_high_bitdepth; + bool shadow_high_bitdepth, soft_shadows; int shadow_cube_store_size; int current_shadow_cascade; int current_shadow_face; @@ -852,9 +852,9 @@ void EEVEE_lights_cache_shcaster_material_add( struct GPUMaterial *gpumat, struct GPUBatch *geom, struct Object *ob, float *alpha_threshold); void EEVEE_lights_cache_shcaster_object_add(EEVEE_ViewLayerData *sldata, struct Object *ob); -void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata); -void EEVEE_lights_update(EEVEE_ViewLayerData *sldata); -void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl); +void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_lights_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_lights_free(void); diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c index b110b3f253e..06479588017 100644 --- a/source/blender/draw/engines/eevee/eevee_render.c +++ b/source/blender/draw/engines/eevee/eevee_render.c @@ -433,7 +433,7 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl /* FINISH CACHE */ EEVEE_materials_cache_finish(vedata); - EEVEE_lights_cache_finish(sldata); + EEVEE_lights_cache_finish(sldata, vedata); EEVEE_lightprobes_cache_finish(sldata, vedata); /* Sort transparents before the loop. */ @@ -507,7 +507,8 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl RE_engine_update_stats(engine, NULL, info); /* Refresh Shadows */ - EEVEE_draw_shadows(sldata, psl); + EEVEE_lights_update(sldata, vedata); + EEVEE_draw_shadows(sldata, vedata); GPU_framebuffer_bind(fbl->main_fb); GPU_framebuffer_clear_color_depth_stencil(fbl->main_fb, clear_col, clear_depth, clear_stencil); diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index ad38c7cfcdf..9045fb4353d 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -2191,6 +2191,7 @@ enum { SCE_EEVEE_SHOW_IRRADIANCE = (1 << 17), SCE_EEVEE_SHOW_CUBEMAPS = (1 << 18), SCE_EEVEE_GI_AUTOBAKE = (1 << 19), + SCE_EEVEE_SHADOW_SOFT = (1 << 20), }; /* SceneEEVEE->shadow_method */ diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 1d52b0011c1..466c7573edf 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -6014,6 +6014,12 @@ static void rna_def_scene_eevee(BlenderRNA *brna) RNA_def_property_boolean_default(prop, 0); RNA_def_property_ui_text(prop, "High Bitdepth", "Use 32bit shadows"); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); + + prop = RNA_def_property(srna, "use_soft_shadows", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SHADOW_SOFT); + RNA_def_property_boolean_default(prop, 0); + RNA_def_property_ui_text(prop, "Soft Shadows", "Randomize shadowmaps origin to create soft shadows"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); } void RNA_def_scene(BlenderRNA *brna)