Eevee: Shadows: Add Contact Shadows
[blender.git] / source / blender / draw / engines / eevee / eevee_lights.c
index 8f5c633c24a9dfbaad78781b94a253d493e7702d..8138b9a0ffd8b0baf610ab05be620d6a81a52542 100644 (file)
@@ -25,6 +25,8 @@
 
 #include "DRW_render.h"
 
 
 #include "DRW_render.h"
 
+#include "BLI_dynstr.h"
+
 #include "BKE_object.h"
 
 #include "eevee_engine.h"
 #include "BKE_object.h"
 
 #include "eevee_engine.h"
@@ -38,18 +40,13 @@ typedef struct EEVEE_LightData {
 } EEVEE_LightData;
 
 typedef struct EEVEE_ShadowCubeData {
 } EEVEE_LightData;
 
 typedef struct EEVEE_ShadowCubeData {
-       short light_id, shadow_id;
-       float viewprojmat[6][4][4];
+       short light_id, shadow_id, cube_id, layer_id;
 } EEVEE_ShadowCubeData;
 
 } EEVEE_ShadowCubeData;
 
-typedef struct EEVEE_ShadowMapData {
-       short light_id, shadow_id;
-       float viewprojmat[4][4]; /* World->Lamp->NDC : used for rendering the shadow map. */
-} EEVEE_ShadowMapData;
-
 typedef struct EEVEE_ShadowCascadeData {
 typedef struct EEVEE_ShadowCascadeData {
-       short light_id, shadow_id;
+       short light_id, shadow_id, cascade_id, layer_id;
        float viewprojmat[MAX_CASCADE_NUM][4][4]; /* World->Lamp->NDC : used for rendering the shadow map. */
        float viewprojmat[MAX_CASCADE_NUM][4][4]; /* World->Lamp->NDC : used for rendering the shadow map. */
+       float radius[MAX_CASCADE_NUM];
 } EEVEE_ShadowCascadeData;
 
 typedef struct ShadowCaster {
 } EEVEE_ShadowCascadeData;
 
 typedef struct ShadowCaster {
@@ -60,30 +57,62 @@ typedef struct ShadowCaster {
 
 static struct {
        struct GPUShader *shadow_sh;
 
 static struct {
        struct GPUShader *shadow_sh;
-       struct GPUShader *shadow_store_sh;
+       struct GPUShader *shadow_store_cube_sh[SHADOW_METHOD_MAX];
+       struct GPUShader *shadow_store_cascade_sh[SHADOW_METHOD_MAX];
+       struct GPUShader *shadow_copy_cube_sh[SHADOW_METHOD_MAX];
+       struct GPUShader *shadow_copy_cascade_sh[SHADOW_METHOD_MAX];
 } e_data = {NULL}; /* Engine data */
 
 extern char datatoc_shadow_vert_glsl[];
 extern char datatoc_shadow_geom_glsl[];
 extern char datatoc_shadow_frag_glsl[];
 } e_data = {NULL}; /* Engine data */
 
 extern char datatoc_shadow_vert_glsl[];
 extern char datatoc_shadow_geom_glsl[];
 extern char datatoc_shadow_frag_glsl[];
-extern char datatoc_shadow_store_vert_glsl[];
-extern char datatoc_shadow_store_geom_glsl[];
 extern char datatoc_shadow_store_frag_glsl[];
 extern char datatoc_shadow_store_frag_glsl[];
+extern char datatoc_shadow_copy_frag_glsl[];
+extern char datatoc_concentric_samples_lib_glsl[];
 
 /* *********** FUNCTIONS *********** */
 
 void EEVEE_lights_init(EEVEE_SceneLayerData *sldata)
 {
 
 /* *********** FUNCTIONS *********** */
 
 void EEVEE_lights_init(EEVEE_SceneLayerData *sldata)
 {
-       const unsigned int shadow_ubo_size = sizeof(EEVEE_ShadowCube) * MAX_SHADOW_CUBE +
-                                            sizeof(EEVEE_ShadowMap) * MAX_SHADOW_MAP +
+       const unsigned int shadow_ubo_size = sizeof(EEVEE_Shadow) * MAX_SHADOW +
+                                            sizeof(EEVEE_ShadowCube) * MAX_SHADOW_CUBE +
                                             sizeof(EEVEE_ShadowCascade) * MAX_SHADOW_CASCADE;
 
                                             sizeof(EEVEE_ShadowCascade) * MAX_SHADOW_CASCADE;
 
+       const DRWContextState *draw_ctx = DRW_context_state_get();
+       SceneLayer *scene_layer = draw_ctx->scene_layer;
+       IDProperty *props = BKE_scene_layer_engine_evaluated_get(scene_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE);
+
        if (!e_data.shadow_sh) {
                e_data.shadow_sh = DRW_shader_create(
                        datatoc_shadow_vert_glsl, datatoc_shadow_geom_glsl, datatoc_shadow_frag_glsl, NULL);
 
        if (!e_data.shadow_sh) {
                e_data.shadow_sh = DRW_shader_create(
                        datatoc_shadow_vert_glsl, datatoc_shadow_geom_glsl, datatoc_shadow_frag_glsl, NULL);
 
-               e_data.shadow_store_sh = DRW_shader_create(
-                       datatoc_shadow_store_vert_glsl, datatoc_shadow_store_geom_glsl, datatoc_shadow_store_frag_glsl, NULL);
+               DynStr *ds_frag = BLI_dynstr_new();
+               BLI_dynstr_append(ds_frag, datatoc_concentric_samples_lib_glsl);
+               BLI_dynstr_append(ds_frag, datatoc_shadow_store_frag_glsl);
+               char *store_shadow_shader_str = BLI_dynstr_get_cstring(ds_frag);
+               BLI_dynstr_free(ds_frag);
+
+               e_data.shadow_store_cube_sh[SHADOW_ESM] = DRW_shader_create_fullscreen(store_shadow_shader_str, "#define ESM\n");
+               e_data.shadow_store_cascade_sh[SHADOW_ESM] = DRW_shader_create_fullscreen(store_shadow_shader_str, "#define ESM\n"
+                                                                                                                  "#define CSM\n");
+
+               e_data.shadow_store_cube_sh[SHADOW_VSM] = DRW_shader_create_fullscreen(store_shadow_shader_str, "#define VSM\n");
+               e_data.shadow_store_cascade_sh[SHADOW_VSM] = DRW_shader_create_fullscreen(store_shadow_shader_str, "#define VSM\n"
+                                                                                                                  "#define CSM\n");
+
+               MEM_freeN(store_shadow_shader_str);
+
+               e_data.shadow_copy_cube_sh[SHADOW_ESM] = DRW_shader_create_fullscreen(datatoc_shadow_copy_frag_glsl, "#define ESM\n"
+                                                                                                                    "#define COPY\n");
+               e_data.shadow_copy_cascade_sh[SHADOW_ESM] = DRW_shader_create_fullscreen(datatoc_shadow_copy_frag_glsl, "#define ESM\n"
+                                                                                                                       "#define COPY\n"
+                                                                                                                       "#define CSM\n");
+
+               e_data.shadow_copy_cube_sh[SHADOW_VSM] = DRW_shader_create_fullscreen(datatoc_shadow_copy_frag_glsl, "#define VSM\n"
+                                                                                                                    "#define COPY\n");
+               e_data.shadow_copy_cascade_sh[SHADOW_VSM] = DRW_shader_create_fullscreen(datatoc_shadow_copy_frag_glsl, "#define VSM\n"
+                                                                                                                       "#define COPY\n"
+                                                                                                                       "#define CSM\n");
        }
 
        if (!sldata->lamps) {
        }
 
        if (!sldata->lamps) {
@@ -92,24 +121,92 @@ void EEVEE_lights_init(EEVEE_SceneLayerData *sldata)
                sldata->shadow_ubo         = DRW_uniformbuffer_create(shadow_ubo_size, NULL);
                sldata->shadow_render_ubo  = DRW_uniformbuffer_create(sizeof(EEVEE_ShadowRender), NULL);
        }
                sldata->shadow_ubo         = DRW_uniformbuffer_create(shadow_ubo_size, NULL);
                sldata->shadow_render_ubo  = DRW_uniformbuffer_create(sizeof(EEVEE_ShadowRender), NULL);
        }
+
+       int sh_method = BKE_collection_engine_property_value_get_int(props, "shadow_method");
+       int sh_size = BKE_collection_engine_property_value_get_int(props, "shadow_size");
+       int sh_high_bitdepth = BKE_collection_engine_property_value_get_int(props, "shadow_high_bitdepth");
+
+       EEVEE_LampsInfo *linfo = sldata->lamps;
+       if ((linfo->shadow_size != sh_size) ||
+               (linfo->shadow_method != sh_method) ||
+               (linfo->shadow_high_bitdepth != sh_high_bitdepth))
+       {
+               BLI_assert((sh_size > 0) && (sh_size <= 8192));
+               DRW_TEXTURE_FREE_SAFE(sldata->shadow_pool);
+               DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_target);
+               DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_target);
+               DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_blur);
+               DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_blur);
+
+               linfo->shadow_high_bitdepth = sh_high_bitdepth;
+               linfo->shadow_method = sh_method;
+               linfo->shadow_size = sh_size;
+               linfo->shadow_render_data.stored_texel_size = 1.0 / (float)linfo->shadow_size;
+
+               /* Compute adequate size for the cubemap render target.
+                * The 3.0f factor is here to make sure there is no under sampling between
+                * the octahedron mapping and the cubemap. */
+               int new_cube_target_size = (int)ceil(sqrt((float)(sh_size * sh_size) / 6.0f) * 3.0f);
+
+               CLAMP(new_cube_target_size, 1, 4096);
+
+               linfo->shadow_cube_target_size = new_cube_target_size;
+               linfo->shadow_render_data.cube_texel_size = 1.0 / (float)linfo->shadow_cube_target_size;
+       }
 }
 
 void EEVEE_lights_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
 {
        EEVEE_LampsInfo *linfo = sldata->lamps;
 
 }
 
 void EEVEE_lights_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
 {
        EEVEE_LampsInfo *linfo = sldata->lamps;
 
-       linfo->num_light = linfo->num_cube = linfo->num_map = linfo->num_cascade = 0;
+       linfo->num_light = 0;
+       linfo->num_layer = 0;
+       linfo->gpu_cube_ct = linfo->gpu_cascade_ct = linfo->gpu_shadow_ct = 0;
+       linfo->cpu_cube_ct = linfo->cpu_cascade_ct = 0;
        memset(linfo->light_ref, 0, sizeof(linfo->light_ref));
        memset(linfo->shadow_cube_ref, 0, sizeof(linfo->shadow_cube_ref));
        memset(linfo->light_ref, 0, sizeof(linfo->light_ref));
        memset(linfo->shadow_cube_ref, 0, sizeof(linfo->shadow_cube_ref));
-       memset(linfo->shadow_map_ref, 0, sizeof(linfo->shadow_map_ref));
        memset(linfo->shadow_cascade_ref, 0, sizeof(linfo->shadow_cascade_ref));
 
        {
                psl->shadow_cube_store_pass = DRW_pass_create("Shadow Storage Pass", DRW_STATE_WRITE_COLOR);
 
        memset(linfo->shadow_cascade_ref, 0, sizeof(linfo->shadow_cascade_ref));
 
        {
                psl->shadow_cube_store_pass = DRW_pass_create("Shadow Storage Pass", DRW_STATE_WRITE_COLOR);
 
-               DRWShadingGroup *grp = DRW_shgroup_create(e_data.shadow_store_sh, psl->shadow_cube_store_pass);
-               DRW_shgroup_uniform_buffer(grp, "shadowCube", &sldata->shadow_color_cube_target);
+               DRWShadingGroup *grp = DRW_shgroup_create(e_data.shadow_store_cube_sh[linfo->shadow_method], psl->shadow_cube_store_pass);
+               DRW_shgroup_uniform_buffer(grp, "shadowTexture", &sldata->shadow_cube_blur);
+               DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
+               DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1);
+               DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
+       }
+
+       {
+               psl->shadow_cascade_store_pass = DRW_pass_create("Shadow Cascade Storage Pass", DRW_STATE_WRITE_COLOR);
+
+               DRWShadingGroup *grp = DRW_shgroup_create(e_data.shadow_store_cascade_sh[linfo->shadow_method], psl->shadow_cascade_store_pass);
+               DRW_shgroup_uniform_buffer(grp, "shadowTexture", &sldata->shadow_cascade_blur);
+               DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
+               DRW_shgroup_uniform_int(grp, "cascadeId", &linfo->current_shadow_cascade, 1);
+               DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1);
+               DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
+       }
+
+       {
+               psl->shadow_cube_copy_pass = DRW_pass_create("Shadow Copy Pass", DRW_STATE_WRITE_COLOR);
+
+               DRWShadingGroup *grp = DRW_shgroup_create(e_data.shadow_copy_cube_sh[linfo->shadow_method], psl->shadow_cube_copy_pass);
+               DRW_shgroup_uniform_buffer(grp, "shadowTexture", &sldata->shadow_cube_target);
+               DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
+               DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1);
+               DRW_shgroup_uniform_int(grp, "faceId", &linfo->current_shadow_face, 1);
+               DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
+       }
+
+       {
+               psl->shadow_cascade_copy_pass = DRW_pass_create("Shadow Cascade Copy Pass", DRW_STATE_WRITE_COLOR);
+
+               DRWShadingGroup *grp = DRW_shgroup_create(e_data.shadow_copy_cascade_sh[linfo->shadow_method], psl->shadow_cascade_copy_pass);
+               DRW_shgroup_uniform_buffer(grp, "shadowTexture", &sldata->shadow_cascade_target);
                DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
                DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
+               DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1);
+               DRW_shgroup_uniform_int(grp, "cascadeId", &linfo->current_shadow_cascade, 1);
                DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
        }
 
                DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
        }
 
@@ -118,7 +215,7 @@ void EEVEE_lights_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
        }
 
        {
        }
 
        {
-               psl->shadow_cascade_pass = DRW_pass_create("Shadow Cascade Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
+               psl->shadow_cascade_pass = DRW_pass_create("Shadow Cascade Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
        }
 
        /* Reset shadow casters list */
        }
 
        /* Reset shadow casters list */
@@ -130,9 +227,9 @@ void EEVEE_lights_cache_add(EEVEE_SceneLayerData *sldata, Object *ob)
        EEVEE_LampsInfo *linfo = sldata->lamps;
 
        /* Step 1 find all lamps in the scene and setup them */
        EEVEE_LampsInfo *linfo = sldata->lamps;
 
        /* Step 1 find all lamps in the scene and setup them */
-       if (linfo->num_light > MAX_LIGHT) {
+       if (linfo->num_light >= MAX_LIGHT) {
                printf("Too much lamps in the scene !!!\n");
                printf("Too much lamps in the scene !!!\n");
-               linfo->num_light = MAX_LIGHT;
+               linfo->num_light = MAX_LIGHT - 1;
        }
        else {
                Lamp *la = (Lamp *)ob->data;
        }
        else {
                Lamp *la = (Lamp *)ob->data;
@@ -144,28 +241,54 @@ void EEVEE_lights_cache_add(EEVEE_SceneLayerData *sldata, Object *ob)
 
                MEM_SAFE_FREE(led->storage);
 
 
                MEM_SAFE_FREE(led->storage);
 
-#if 1 /* TODO Waiting for notified refresh. only on scene change. Else too much perf cost. */
                if (la->mode & (LA_SHAD_BUF | LA_SHAD_RAY)) {
                if (la->mode & (LA_SHAD_BUF | LA_SHAD_RAY)) {
-                       if (la->type == LA_SUN && linfo->num_cascade < MAX_SHADOW_CASCADE) {
-#if 0 /* TODO filter cascaded shadow map */
-                               led->storage = MEM_mallocN(sizeof(EEVEE_ShadowCascadeData), "EEVEE_ShadowCascadeData");
-                               ((EEVEE_ShadowCascadeData *)led->storage)->shadow_id = linfo->num_cascade;
-                               linfo->shadow_cascade_ref[linfo->num_cascade] = ob;
-                               linfo->num_cascade++;
-#endif
+                       if (la->type == LA_SUN) {
+                               int sh_nbr = 1; /* TODO : MSM */
+                               int cascade_nbr = MAX_CASCADE_NUM; /* TODO : Custom cascade number */
+
+                               if ((linfo->gpu_cascade_ct + sh_nbr) <= MAX_SHADOW_CASCADE) {
+                                       /* Save Light object. */
+                                       linfo->shadow_cascade_ref[linfo->cpu_cascade_ct] = ob;
+
+                                       /* Create storage and store indices. */
+                                       EEVEE_ShadowCascadeData *data = MEM_mallocN(sizeof(EEVEE_ShadowCascadeData), "EEVEE_ShadowCascadeData");
+                                       data->shadow_id = linfo->gpu_shadow_ct;
+                                       data->cascade_id = linfo->gpu_cascade_ct;
+                                       data->layer_id = linfo->num_layer;
+                                       led->storage = data;
+
+                                       /* Increment indices. */
+                                       linfo->gpu_shadow_ct += 1;
+                                       linfo->gpu_cascade_ct += sh_nbr;
+                                       linfo->num_layer += sh_nbr * cascade_nbr;
+
+                                       linfo->cpu_cascade_ct += 1;
+                               }
                        }
                        }
-                       else if ((la->type == LA_SPOT || la->type == LA_LOCAL || la->type == LA_AREA)
-                                 && linfo->num_cube < MAX_SHADOW_CUBE) {
-                               led->storage = MEM_mallocN(sizeof(EEVEE_ShadowCubeData), "EEVEE_ShadowCubeData");
-                               ((EEVEE_ShadowCubeData *)led->storage)->shadow_id = linfo->num_cube;
-                               linfo->shadow_cube_ref[linfo->num_cube] = ob;
-                               linfo->num_cube++;
+                       else if (la->type == LA_SPOT || la->type == LA_LOCAL || la->type == LA_AREA) {
+                               int sh_nbr = 1; /* TODO : MSM */
+
+                               if ((linfo->gpu_cube_ct + sh_nbr) <= MAX_SHADOW_CUBE) {
+                                       /* Save Light object. */
+                                       linfo->shadow_cube_ref[linfo->cpu_cube_ct] = ob;
+
+                                       /* Create storage and store indices. */
+                                       EEVEE_ShadowCubeData *data = MEM_mallocN(sizeof(EEVEE_ShadowCubeData), "EEVEE_ShadowCubeData");
+                                       data->shadow_id = linfo->gpu_shadow_ct;
+                                       data->cube_id = linfo->gpu_cube_ct;
+                                       data->layer_id = linfo->num_layer;
+                                       led->storage = data;
+
+                                       /* Increment indices. */
+                                       linfo->gpu_shadow_ct += 1;
+                                       linfo->gpu_cube_ct += sh_nbr;
+                                       linfo->num_layer += sh_nbr;
+
+                                       linfo->cpu_cube_ct += 1;
+                               }
                        }
                        }
-
                }
                }
-#else
-               UNUSED_VARS(la);
-#endif
+
                /* Default light without shadows */
                if (!led->storage) {
                        led->storage = MEM_mallocN(sizeof(EEVEE_LightData), "EEVEE_LightData");
                /* Default light without shadows */
                if (!led->storage) {
                        led->storage = MEM_mallocN(sizeof(EEVEE_LightData), "EEVEE_LightData");
@@ -197,9 +320,10 @@ void EEVEE_lights_cache_shcaster_add(EEVEE_SceneLayerData *sldata, EEVEE_PassLis
 }
 
 void EEVEE_lights_cache_shcaster_material_add(
 }
 
 void EEVEE_lights_cache_shcaster_material_add(
-       EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl, struct GPUMaterial *gpumat, struct Gwn_Batch *geom, float (*obmat)[4], float *alpha_threshold)
+       EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl, struct GPUMaterial *gpumat,
+       struct Gwn_Batch *geom, struct Object *ob, float (*obmat)[4], float *alpha_threshold)
 {
 {
-       DRWShadingGroup *grp = DRW_shgroup_material_instance_create(gpumat, psl->shadow_cube_pass, geom);
+       DRWShadingGroup *grp = DRW_shgroup_material_instance_create(gpumat, psl->shadow_cube_pass, geom, ob);
 
        if (grp == NULL) return;
 
 
        if (grp == NULL) return;
 
@@ -212,7 +336,7 @@ void EEVEE_lights_cache_shcaster_material_add(
        for (int i = 0; i < 6; ++i)
                DRW_shgroup_call_dynamic_add_empty(grp);
 
        for (int i = 0; i < 6; ++i)
                DRW_shgroup_call_dynamic_add_empty(grp);
 
-       grp = DRW_shgroup_material_instance_create(gpumat, psl->shadow_cascade_pass, geom);
+       grp = DRW_shgroup_material_instance_create(gpumat, psl->shadow_cascade_pass, geom, ob);
        DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
        DRW_shgroup_uniform_mat4(grp, "ShadowModelMatrix", (float *)obmat);
 
        DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
        DRW_shgroup_uniform_mat4(grp, "ShadowModelMatrix", (float *)obmat);
 
@@ -226,70 +350,61 @@ void EEVEE_lights_cache_shcaster_material_add(
 void EEVEE_lights_cache_finish(EEVEE_SceneLayerData *sldata)
 {
        EEVEE_LampsInfo *linfo = sldata->lamps;
 void EEVEE_lights_cache_finish(EEVEE_SceneLayerData *sldata)
 {
        EEVEE_LampsInfo *linfo = sldata->lamps;
+       DRWTextureFormat shadow_pool_format;
 
        /* Setup enough layers. */
        /* Free textures if number mismatch. */
 
        /* Setup enough layers. */
        /* Free textures if number mismatch. */
-       if (linfo->num_cube != linfo->cache_num_cube) {
-               DRW_TEXTURE_FREE_SAFE(sldata->shadow_depth_cube_pool);
-               linfo->cache_num_cube = linfo->num_cube;
+       if (linfo->num_layer != linfo->cache_num_layer) {
+               DRW_TEXTURE_FREE_SAFE(sldata->shadow_pool);
+               linfo->cache_num_layer = linfo->num_layer;
                linfo->update_flag |= LIGHT_UPDATE_SHADOW_CUBE;
        }
                linfo->update_flag |= LIGHT_UPDATE_SHADOW_CUBE;
        }
-       if (linfo->num_map != linfo->cache_num_map) {
-               DRW_TEXTURE_FREE_SAFE(sldata->shadow_depth_map_pool);
-               linfo->cache_num_map = linfo->num_map;
-       }
-       if (linfo->num_cascade != linfo->cache_num_cascade) {
-               DRW_TEXTURE_FREE_SAFE(sldata->shadow_depth_cascade_pool);
-               linfo->cache_num_cascade = linfo->num_cascade;
-       }
 
 
-       /* Initialize Textures Arrays first so DRW_framebuffer_init just bind them. */
-       if (!sldata->shadow_depth_cube_target) {
-               /* Render Cubemap */
-               sldata->shadow_depth_cube_target = DRW_texture_create_cube(512, DRW_TEX_DEPTH_24, 0, NULL);
-               sldata->shadow_color_cube_target = DRW_texture_create_cube(512, DRW_TEX_R_32, DRW_TEX_FILTER, NULL);
-               if (sldata->shadow_cube_fb) {
-                       DRW_framebuffer_texture_attach(sldata->shadow_cube_fb, sldata->shadow_depth_cube_target, 0, 0);
-                       DRW_framebuffer_texture_attach(sldata->shadow_cube_fb, sldata->shadow_color_cube_target, 0, 0);
-               }
+       switch (linfo->shadow_method) {
+               case SHADOW_ESM: shadow_pool_format = ((linfo->shadow_high_bitdepth) ? DRW_TEX_R_32 : DRW_TEX_R_16); break;
+               case SHADOW_VSM: shadow_pool_format = ((linfo->shadow_high_bitdepth) ? DRW_TEX_RG_32 : DRW_TEX_RG_16); break;
+               default:
+                       BLI_assert(!"Incorrect Shadow Method");
+                       break;
        }
        }
-       if (!sldata->shadow_depth_cube_pool) {
-               /* Cubemap / octahedral map pool */
-               /* TODO Cubemap array */
-               sldata->shadow_depth_cube_pool = DRW_texture_create_2D_array(
-                       512, 512, max_ff(1, linfo->num_cube), DRW_TEX_R_16,
-                       DRW_TEX_FILTER | DRW_TEX_COMPARE, NULL);
-               if (sldata->shadow_cube_fb) {
-                       DRW_framebuffer_texture_attach(sldata->shadow_cube_fb, sldata->shadow_depth_cube_pool, 0, 0);
-               }
+
+       if (!sldata->shadow_cube_target) {
+               /* TODO render everything on the same 2d render target using clip planes and no Geom Shader. */
+               /* Cubemaps */
+               sldata->shadow_cube_target = DRW_texture_create_cube(linfo->shadow_cube_target_size, DRW_TEX_DEPTH_24, 0, NULL);
+               sldata->shadow_cube_blur = DRW_texture_create_cube(linfo->shadow_cube_target_size, shadow_pool_format, DRW_TEX_FILTER, NULL);
        }
        }
-       if (!sldata->shadow_depth_map_pool) {
-               sldata->shadow_depth_map_pool = DRW_texture_create_2D_array(
-                       512, 512, max_ff(1, linfo->num_map), DRW_TEX_DEPTH_24,
-                       DRW_TEX_FILTER | DRW_TEX_COMPARE, NULL);
-               if (sldata->shadow_map_fb) {
-                       DRW_framebuffer_texture_attach(sldata->shadow_map_fb, sldata->shadow_depth_map_pool, 0, 0);
-               }
+
+       if (!sldata->shadow_cascade_target) {
+               /* CSM */
+               sldata->shadow_cascade_target = DRW_texture_create_2D_array(
+                       linfo->shadow_size, linfo->shadow_size, MAX_CASCADE_NUM, DRW_TEX_DEPTH_24, 0, NULL);
+               sldata->shadow_cascade_blur = DRW_texture_create_2D_array(
+                       linfo->shadow_size, linfo->shadow_size, MAX_CASCADE_NUM, shadow_pool_format, DRW_TEX_FILTER, NULL);
        }
        }
-       if (!sldata->shadow_depth_cascade_pool) {
-               sldata->shadow_depth_cascade_pool = DRW_texture_create_2D_array(
-                       512, 512, max_ff(1, linfo->num_cascade * MAX_CASCADE_NUM), DRW_TEX_DEPTH_24,
-                       DRW_TEX_FILTER | DRW_TEX_COMPARE, NULL);
-               if (sldata->shadow_cascade_fb) {
-                       DRW_framebuffer_texture_attach(sldata->shadow_cascade_fb, sldata->shadow_depth_map_pool, 0, 0);
-               }
+
+       /* Initialize Textures Array first so DRW_framebuffer_init just bind them. */
+       if (!sldata->shadow_pool) {
+               /* All shadows fit in this array */
+               sldata->shadow_pool = DRW_texture_create_2D_array(
+                       linfo->shadow_size, linfo->shadow_size, max_ff(1, linfo->num_layer),
+                       shadow_pool_format, DRW_TEX_FILTER, NULL);
        }
 
        }
 
-       DRWFboTexture tex_cube_target[2] = {
-               {&sldata->shadow_depth_cube_target, DRW_TEX_DEPTH_24, 0},
-               {&sldata->shadow_color_cube_target, DRW_TEX_R_16, DRW_TEX_FILTER}};
-       DRW_framebuffer_init(&sldata->shadow_cube_target_fb, &draw_engine_eevee_type, 512, 512, tex_cube_target, 2);
+       /* Render FB */
+       DRWFboTexture tex_cascade = {&sldata->shadow_cube_target, DRW_TEX_DEPTH_24, 0};
+       DRW_framebuffer_init(&sldata->shadow_target_fb, &draw_engine_eevee_type,
+                            linfo->shadow_size, linfo->shadow_size,
+                            &tex_cascade, 1);
 
 
-       DRWFboTexture tex_cube = {&sldata->shadow_depth_cube_pool, DRW_TEX_R_16, DRW_TEX_FILTER};
-       DRW_framebuffer_init(&sldata->shadow_cube_fb, &draw_engine_eevee_type, 512, 512, &tex_cube, 1);
+       /* Storage FB */
+       DRWFboTexture tex_pool = {&sldata->shadow_pool, shadow_pool_format, DRW_TEX_FILTER};
+       DRW_framebuffer_init(&sldata->shadow_store_fb, &draw_engine_eevee_type,
+                            linfo->shadow_size, linfo->shadow_size,
+                            &tex_pool, 1);
 
 
-       DRWFboTexture tex_cascade = {&sldata->shadow_depth_cascade_pool, DRW_TEX_DEPTH_24, DRW_TEX_FILTER | DRW_TEX_COMPARE};
-       DRW_framebuffer_init(&sldata->shadow_cascade_fb, &draw_engine_eevee_type, 512, 512, &tex_cascade, 1);
+       /* Restore */
+       DRW_framebuffer_texture_detach(sldata->shadow_cube_target);
 
        /* Update Lamps UBOs. */
        EEVEE_lights_update(sldata);
 
        /* Update Lamps UBOs. */
        EEVEE_lights_update(sldata);
@@ -372,54 +487,33 @@ static void eevee_light_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngi
 
 static void eevee_shadow_cube_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngineData *led)
 {
 
 static void eevee_shadow_cube_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngineData *led)
 {
-       float projmat[4][4];
-
-       EEVEE_ShadowCubeData *evsmp = (EEVEE_ShadowCubeData *)led->storage;
-       EEVEE_Light *evli = linfo->light_data + evsmp->light_id;
-       EEVEE_ShadowCube *evsh = linfo->shadow_cube_data + evsmp->shadow_id;
+       EEVEE_ShadowCubeData *sh_data = (EEVEE_ShadowCubeData *)led->storage;
+       EEVEE_Light *evli = linfo->light_data + sh_data->light_id;
+       EEVEE_Shadow *ubo_data = linfo->shadow_data + sh_data->shadow_id;
+       EEVEE_ShadowCube *cube_data = linfo->shadow_cube_data + sh_data->cube_id;
        Lamp *la = (Lamp *)ob->data;
 
        Lamp *la = (Lamp *)ob->data;
 
-       perspective_m4(projmat, -la->clipsta, la->clipsta, -la->clipsta, la->clipsta, la->clipsta, la->clipend);
+       int sh_nbr = 1; /* TODO: MSM */
 
 
-       for (int i = 0; i < 6; ++i) {
-               float tmp[4][4];
-               unit_m4(tmp);
-               negate_v3_v3(tmp[3], ob->obmat[3]);
-               mul_m4_m4m4(tmp, cubefacemat[i], tmp);
-               mul_m4_m4m4(evsmp->viewprojmat[i], projmat, tmp);
+       for (int i = 0; i < sh_nbr; ++i) {
+               /* TODO : choose MSM sample point here. */
+               copy_v3_v3(cube_data->position, ob->obmat[3]);
        }
 
        }
 
-       evsh->bias = 0.05f * la->bias;
-       evsh->near = la->clipsta;
-       evsh->far = la->clipend;
-       evsh->exp = la->bleedexp;
-
-       evli->shadowid = (float)(evsmp->shadow_id);
-}
-
-static void eevee_shadow_map_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngineData *led)
-{
-       float viewmat[4][4], projmat[4][4];
-
-       EEVEE_ShadowMapData *evsmp = (EEVEE_ShadowMapData *)led->storage;
-       EEVEE_Light *evli = linfo->light_data + evsmp->light_id;
-       EEVEE_ShadowMap *evsh = linfo->shadow_map_data + evsmp->shadow_id;
-       Lamp *la = (Lamp *)ob->data;
-
-       invert_m4_m4(viewmat, ob->obmat);
-       normalize_v3(viewmat[0]);
-       normalize_v3(viewmat[1]);
-       normalize_v3(viewmat[2]);
+       ubo_data->bias = 0.05f * la->bias;
+       ubo_data->near = la->clipsta;
+       ubo_data->far = la->clipend;
+       ubo_data->exp = (linfo->shadow_method == SHADOW_VSM) ? la->bleedbias : la->bleedexp;
 
 
-       float wsize = la->shadow_frustum_size;
-       orthographic_m4(projmat, -wsize, wsize, -wsize, wsize, la->clipsta, la->clipend);
+       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);
 
 
-       mul_m4_m4m4(evsmp->viewprojmat, projmat, viewmat);
-       mul_m4_m4m4(evsh->shadowmat, texcomat, evsmp->viewprojmat);
-
-       evsh->bias = 0.005f * la->bias;
-
-       evli->shadowid = (float)(MAX_SHADOW_CUBE + evsmp->shadow_id);
+       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)))
 }
 
 #define LERP(t, a, b) ((a) + (t) * ((b) - (a)))
@@ -458,10 +552,12 @@ static void frustum_min_bounding_sphere(const float corners[8][4], float r_cente
 
 static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngineData *led)
 {
 
 static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngineData *led)
 {
+       Lamp *la = (Lamp *)ob->data;
+
        /* Camera Matrices */
        float persmat[4][4], persinv[4][4];
        float viewprojmat[4][4], projinv[4][4];
        /* Camera Matrices */
        float persmat[4][4], persinv[4][4];
        float viewprojmat[4][4], projinv[4][4];
-       float near, far;
+       float view_near, view_far;
        float near_v[4] = {0.0f, 0.0f, -1.0f, 1.0f};
        float far_v[4] = {0.0f, 0.0f,  1.0f, 1.0f};
        bool is_persp = DRW_viewport_is_persp_get();
        float near_v[4] = {0.0f, 0.0f, -1.0f, 1.0f};
        float far_v[4] = {0.0f, 0.0f,  1.0f, 1.0f};
        bool is_persp = DRW_viewport_is_persp_get();
@@ -472,74 +568,134 @@ static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE
        invert_m4_m4(projinv, viewprojmat);
        mul_m4_v4(projinv, near_v);
        mul_m4_v4(projinv, far_v);
        invert_m4_m4(projinv, viewprojmat);
        mul_m4_v4(projinv, near_v);
        mul_m4_v4(projinv, far_v);
-       near = near_v[2];
-       far = far_v[2]; /* TODO: Should be a shadow parameter */
+       view_near = near_v[2];
+       view_far = far_v[2]; /* TODO: Should be a shadow parameter */
        if (is_persp) {
        if (is_persp) {
-               near /= near_v[3];
-               far /= far_v[3];
+               view_near /= near_v[3];
+               view_far /= far_v[3];
        }
 
        /* Lamps Matrices */
        float viewmat[4][4], projmat[4][4];
        }
 
        /* Lamps Matrices */
        float viewmat[4][4], projmat[4][4];
-       int cascade_ct = MAX_CASCADE_NUM;
-       float shadow_res = 512.0f; /* TODO parameter */
+       int sh_nbr = 1; /* TODO : MSM */
+       int cascade_nbr = la->cascade_count;
 
 
-       EEVEE_ShadowCascadeData *evscp = (EEVEE_ShadowCascadeData *)led->storage;
-       EEVEE_Light *evli = linfo->light_data + evscp->light_id;
-       EEVEE_ShadowCascade *evsh = linfo->shadow_cascade_data + evscp->shadow_id;
-       Lamp *la = (Lamp *)ob->data;
+       EEVEE_ShadowCascadeData *sh_data = (EEVEE_ShadowCascadeData *)led->storage;
+       EEVEE_Light *evli = linfo->light_data + sh_data->light_id;
+       EEVEE_Shadow *ubo_data = linfo->shadow_data + sh_data->shadow_id;
+       EEVEE_ShadowCascade *cascade_data = linfo->shadow_cascade_data + sh_data->cascade_id;
 
        /* The technique consists into splitting
         * the view frustum into several sub-frustum
         * that are individually receiving one shadow map */
 
 
        /* The technique consists into splitting
         * the view frustum into several sub-frustum
         * that are individually receiving one shadow map */
 
+       float csm_start, csm_end;
+
+       if (is_persp) {
+               csm_start = view_near;
+               csm_end = max_ff(view_far, -la->cascade_max_dist);
+               /* Avoid artifacts */
+               csm_end = min_ff(view_near, csm_end);
+       }
+       else {
+               csm_start = -view_far;
+               csm_end = view_far;
+       }
+
        /* init near/far */
        for (int c = 0; c < MAX_CASCADE_NUM; ++c) {
        /* init near/far */
        for (int c = 0; c < MAX_CASCADE_NUM; ++c) {
-               evsh->split[c] = far;
+               cascade_data->split_start[c] = csm_end;
+               cascade_data->split_end[c] = csm_end;
        }
 
        /* Compute split planes */
        }
 
        /* Compute split planes */
-       float splits_ndc[MAX_CASCADE_NUM + 1];
-       splits_ndc[0] = -1.0f;
-       splits_ndc[cascade_ct] = 1.0f;
-       for (int c = 1; c < cascade_ct; ++c) {
-               const float lambda = 0.8f; /* TODO : Parameter */
+       float splits_start_ndc[MAX_CASCADE_NUM];
+       float splits_end_ndc[MAX_CASCADE_NUM];
 
 
+       {
+               /* Nearest plane */
+               float p[4] = {1.0f, 1.0f, csm_start, 1.0f};
+               /* TODO: we don't need full m4 multiply here */
+               mul_m4_v4(viewprojmat, p);
+               splits_start_ndc[0] = p[2];
+               if (is_persp) {
+                       splits_start_ndc[0] /= p[3];
+               }
+       }
+
+       {
+               /* Farthest plane */
+               float p[4] = {1.0f, 1.0f, csm_end, 1.0f};
+               /* TODO: we don't need full m4 multiply here */
+               mul_m4_v4(viewprojmat, p);
+               splits_end_ndc[cascade_nbr - 1] = p[2];
+               if (is_persp) {
+                       splits_end_ndc[cascade_nbr - 1] /= p[3];
+               }
+       }
+
+       cascade_data->split_start[0] = csm_start;
+       cascade_data->split_end[cascade_nbr - 1] = csm_end;
+
+       for (int c = 1; c < cascade_nbr; ++c) {
                /* View Space */
                /* View Space */
-               float linear_split = LERP(((float)(c) / (float)cascade_ct), near, far);
-               float exp_split = near * powf(far / near, (float)(c) / (float)cascade_ct);
+               float linear_split = LERP(((float)(c) / (float)cascade_nbr), csm_start, csm_end);
+               float exp_split = csm_start * powf(csm_end / csm_start, (float)(c) / (float)cascade_nbr);
 
                if (is_persp) {
 
                if (is_persp) {
-                       evsh->split[c-1] = LERP(lambda, linear_split, exp_split);
+                       cascade_data->split_start[c] = LERP(la->cascade_exponent, linear_split, exp_split);
                }
                else {
                }
                else {
-                       evsh->split[c-1] = linear_split;
+                       cascade_data->split_start[c] = linear_split;
                }
                }
+               cascade_data->split_end[c-1] = cascade_data->split_start[c];
+
+               /* Add some overlap for smooth transition */
+               cascade_data->split_start[c] = LERP(la->cascade_fade, cascade_data->split_end[c-1],
+                                                   (c > 1) ? cascade_data->split_end[c-2] : cascade_data->split_start[0]);
 
                /* NDC Space */
 
                /* NDC Space */
-               float p[4] = {1.0f, 1.0f, evsh->split[c-1], 1.0f};
-               mul_m4_v4(viewprojmat, p);
-               splits_ndc[c] = p[2];
+               {
+                       float p[4] = {1.0f, 1.0f, cascade_data->split_start[c], 1.0f};
+                       /* TODO: we don't need full m4 multiply here */
+                       mul_m4_v4(viewprojmat, p);
+                       splits_start_ndc[c] = p[2];
+
+                       if (is_persp) {
+                               splits_start_ndc[c] /= p[3];
+                       }
+               }
 
 
-               if (is_persp) {
-                       splits_ndc[c] /= p[3];
+               {
+                       float p[4] = {1.0f, 1.0f, cascade_data->split_end[c-1], 1.0f};
+                       /* TODO: we don't need full m4 multiply here */
+                       mul_m4_v4(viewprojmat, p);
+                       splits_end_ndc[c-1] = p[2];
+
+                       if (is_persp) {
+                               splits_end_ndc[c-1] /= p[3];
+                       }
                }
        }
 
                }
        }
 
+       /* Set last cascade split fade distance into the first split_start. */
+       float prev_split = (cascade_nbr > 1) ? cascade_data->split_end[cascade_nbr-2] : cascade_data->split_start[0];
+       cascade_data->split_start[0] = LERP(la->cascade_fade, cascade_data->split_end[cascade_nbr-1], prev_split);
+
        /* For each cascade */
        /* For each cascade */
-       for (int c = 0; c < cascade_ct; ++c) {
-               /* Given 8 frustrum corners */
+       for (int c = 0; c < cascade_nbr; ++c) {
+               /* Given 8 frustum corners */
                float corners[8][4] = {
                        /* Near Cap */
                float corners[8][4] = {
                        /* Near Cap */
-                       {-1.0f, -1.0f, splits_ndc[c], 1.0f},
-                       { 1.0f, -1.0f, splits_ndc[c], 1.0f},
-                       {-1.0f,  1.0f, splits_ndc[c], 1.0f},
-                       { 1.0f,  1.0f, splits_ndc[c], 1.0f},
+                       {-1.0f, -1.0f, splits_start_ndc[c], 1.0f},
+                       { 1.0f, -1.0f, splits_start_ndc[c], 1.0f},
+                       {-1.0f,  1.0f, splits_start_ndc[c], 1.0f},
+                       { 1.0f,  1.0f, splits_start_ndc[c], 1.0f},
                        /* Far Cap */
                        /* Far Cap */
-                       {-1.0f, -1.0f, splits_ndc[c+1], 1.0f},
-                       { 1.0f, -1.0f, splits_ndc[c+1], 1.0f},
-                       {-1.0f,  1.0f, splits_ndc[c+1], 1.0f},
-                       { 1.0f,  1.0f, splits_ndc[c+1], 1.0f}
+                       {-1.0f, -1.0f, splits_end_ndc[c], 1.0f},
+                       { 1.0f, -1.0f, splits_end_ndc[c], 1.0f},
+                       {-1.0f,  1.0f, splits_end_ndc[c], 1.0f},
+                       { 1.0f,  1.0f, splits_end_ndc[c], 1.0f}
                };
 
                /* Transform them into world space */
                };
 
                /* Transform them into world space */
@@ -549,6 +705,7 @@ static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE
                        corners[i][3] = 1.0f;
                }
 
                        corners[i][3] = 1.0f;
                }
 
+
                /* Project them into light space */
                invert_m4_m4(viewmat, ob->obmat);
                normalize_v3(viewmat[0]);
                /* Project them into light space */
                invert_m4_m4(viewmat, ob->obmat);
                normalize_v3(viewmat[0]);
@@ -559,12 +716,12 @@ static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE
                        mul_m4_v4(viewmat, corners[i]);
                }
 
                        mul_m4_v4(viewmat, corners[i]);
                }
 
-               float center[3], radius;
-               frustum_min_bounding_sphere(corners, center, &radius);
+               float center[3];
+               frustum_min_bounding_sphere(corners, center, &(sh_data->radius[c]));
 
 
-               /* Snap projection center to nearest texel to cancel shimering. */
+               /* Snap projection center to nearest texel to cancel shimmering. */
                float shadow_origin[2], shadow_texco[2];
                float shadow_origin[2], shadow_texco[2];
-               mul_v2_v2fl(shadow_origin, center, shadow_res / (2.0f * radius)); /* Light to texture space. */
+               mul_v2_v2fl(shadow_origin, center, linfo->shadow_size / (2.0f * sh_data->radius[c])); /* Light to texture space. */
 
                /* Find the nearest texel. */
                shadow_texco[0] = round(shadow_origin[0]);
 
                /* Find the nearest texel. */
                shadow_texco[0] = round(shadow_origin[0]);
@@ -572,27 +729,37 @@ static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE
 
                /* Compute offset. */
                sub_v2_v2(shadow_texco, shadow_origin);
 
                /* Compute offset. */
                sub_v2_v2(shadow_texco, shadow_origin);
-               mul_v2_fl(shadow_texco, (2.0f * radius) / shadow_res); /* Texture to light space. */
+               mul_v2_fl(shadow_texco, (2.0f * sh_data->radius[c]) / linfo->shadow_size); /* Texture to light space. */
 
                /* Apply offset. */
                add_v2_v2(center, shadow_texco);
 
                /* Expand the projection to cover frustum range */
                orthographic_m4(projmat,
 
                /* Apply offset. */
                add_v2_v2(center, shadow_texco);
 
                /* Expand the projection to cover frustum range */
                orthographic_m4(projmat,
-                               center[0] - radius,
-                               center[0] + radius,
-                               center[1] - radius,
-                               center[1] + radius,
+                               center[0] - sh_data->radius[c],
+                               center[0] + sh_data->radius[c],
+                               center[1] - sh_data->radius[c],
+                               center[1] + sh_data->radius[c],
                                la->clipsta, la->clipend);
 
                                la->clipsta, la->clipend);
 
-               mul_m4_m4m4(evscp->viewprojmat[c], projmat, viewmat);
-               mul_m4_m4m4(evsh->shadowmat[c], texcomat, evscp->viewprojmat[c]);
-
-               /* TODO modify bias depending on the cascade radius */
-               evsh->bias[c] = 0.005f * la->bias;
+               mul_m4_m4m4(sh_data->viewprojmat[c], projmat, viewmat);
+               mul_m4_m4m4(cascade_data->shadowmat[c], texcomat, sh_data->viewprojmat[c]);
        }
 
        }
 
-       evli->shadowid = (float)(MAX_SHADOW_CUBE + MAX_SHADOW_MAP + evscp->shadow_id);
+       ubo_data->bias = 0.05f * la->bias;
+       ubo_data->near = la->clipsta;
+       ubo_data->far = la->clipend;
+       ubo_data->exp = (linfo->shadow_method == SHADOW_VSM) ? la->bleedbias : la->bleedexp;
+
+       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->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. */
 }
 
 /* Used for checking if object is inside the shadow volume. */
@@ -717,19 +884,6 @@ void EEVEE_lights_update(EEVEE_SceneLayerData *sldata)
                eevee_shadow_cube_setup(ob, linfo, led);
                delete_pruned_shadowcaster(led);
        }
                eevee_shadow_cube_setup(ob, linfo, led);
                delete_pruned_shadowcaster(led);
        }
-
-       for (i = 0; (ob = linfo->shadow_map_ref[i]) && (i < MAX_SHADOW_MAP); i++) {
-               EEVEE_LampEngineData *led = EEVEE_lamp_data_get(ob);
-               eevee_shadow_map_setup(ob, linfo, led);
-       }
-
-       for (i = 0; (ob = linfo->shadow_cascade_ref[i]) && (i < MAX_SHADOW_CASCADE); i++) {
-               EEVEE_LampEngineData *led = EEVEE_lamp_data_get(ob);
-               eevee_shadow_cascade_setup(ob, linfo, led);
-       }
-
-       DRW_uniformbuffer_update(sldata->light_ubo, &linfo->light_data);
-       DRW_uniformbuffer_update(sldata->shadow_ubo, &linfo->shadow_cube_data); /* Update all data at once */
 }
 
 /* this refresh lamps shadow buffers */
 }
 
 /* this refresh lamps shadow buffers */
@@ -738,20 +892,25 @@ void EEVEE_draw_shadows(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
        EEVEE_LampsInfo *linfo = sldata->lamps;
        Object *ob;
        int i;
        EEVEE_LampsInfo *linfo = sldata->lamps;
        Object *ob;
        int i;
-       float clear_color[4] = {FLT_MAX, FLT_MAX, FLT_MAX, 0.0f};
+       float clear_col[4] = {FLT_MAX};
 
        /* Cube Shadow Maps */
 
        /* Cube Shadow Maps */
+       DRW_stats_group_start("Cube Shadow Maps");
+       DRW_framebuffer_texture_attach(sldata->shadow_target_fb, sldata->shadow_cube_target, 0, 0);
        /* Render each shadow to one layer of the array */
        for (i = 0; (ob = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) {
                EEVEE_LampEngineData *led = EEVEE_lamp_data_get(ob);
                Lamp *la = (Lamp *)ob->data;
 
        /* Render each shadow to one layer of the array */
        for (i = 0; (ob = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) {
                EEVEE_LampEngineData *led = EEVEE_lamp_data_get(ob);
                Lamp *la = (Lamp *)ob->data;
 
+               float cube_projmat[4][4];
+               perspective_m4(cube_projmat, -la->clipsta, la->clipsta, -la->clipsta, la->clipsta, la->clipsta, la->clipend);
+
                if (led->need_update) {
                if (led->need_update) {
-                       EEVEE_ShadowCubeData *evscd = (EEVEE_ShadowCubeData *)led->storage;
                        EEVEE_ShadowRender *srd = &linfo->shadow_render_data;
                        EEVEE_ShadowRender *srd = &linfo->shadow_render_data;
+                       EEVEE_ShadowCubeData *evscd = (EEVEE_ShadowCubeData *)led->storage;
 
 
-                       srd->layer = i;
-                       srd->exponent = la->bleedexp;
+                       srd->clip_near = la->clipsta;
+                       srd->clip_far = la->clipend;
                        copy_v3_v3(srd->position, ob->obmat[3]);
                        for (int j = 0; j < 6; j++) {
                                float tmp[4][4];
                        copy_v3_v3(srd->position, ob->obmat[3]);
                        for (int j = 0; j < 6; j++) {
                                float tmp[4][4];
@@ -760,17 +919,56 @@ void EEVEE_draw_shadows(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
                                negate_v3_v3(tmp[3], ob->obmat[3]);
                                mul_m4_m4m4(srd->viewmat[j], cubefacemat[j], tmp);
 
                                negate_v3_v3(tmp[3], ob->obmat[3]);
                                mul_m4_m4m4(srd->viewmat[j], cubefacemat[j], tmp);
 
-                               copy_m4_m4(srd->shadowmat[j], evscd->viewprojmat[j]);
+                               mul_m4_m4m4(srd->shadowmat[j], cube_projmat, srd->viewmat[j]);
                        }
                        }
-                       DRW_uniformbuffer_update(sldata->shadow_render_ubo, &linfo->shadow_render_data);
+                       DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd);
+
+                       DRW_framebuffer_bind(sldata->shadow_target_fb);
+                       DRW_framebuffer_clear(true, true, false, clear_col, 1.0f);
 
 
-                       DRW_framebuffer_bind(sldata->shadow_cube_target_fb);
-                       DRW_framebuffer_clear(true, true, false, clear_color, 1.0f);
                        /* Render shadow cube */
                        DRW_draw_pass(psl->shadow_cube_pass);
 
                        /* Render shadow cube */
                        DRW_draw_pass(psl->shadow_cube_pass);
 
+                       /* 0.001f is arbitrary, but it should be relatively small so that filter size is not too big. */
+                       float filter_texture_size = la->soft * 0.001f;
+                       float filter_pixel_size = ceil(filter_texture_size / linfo->shadow_render_data.cube_texel_size);
+                       linfo->filter_size = linfo->shadow_render_data.cube_texel_size * ((filter_pixel_size > 1.0f) ? 1.5f : 0.0f);
+
+                       /* TODO: OPTI: Filter all faces in one/two draw call */
+                       for (linfo->current_shadow_face = 0;
+                            linfo->current_shadow_face < 6;
+                            linfo->current_shadow_face++)
+                       {
+                               /* Copy using a small 3x3 box filter */
+                               DRW_framebuffer_cubeface_attach(sldata->shadow_store_fb, sldata->shadow_cube_blur, 0, linfo->current_shadow_face, 0);
+                               DRW_framebuffer_bind(sldata->shadow_store_fb);
+                               DRW_draw_pass(psl->shadow_cube_copy_pass);
+                               DRW_framebuffer_texture_detach(sldata->shadow_cube_blur);
+                       }
+
                        /* Push it to shadowmap array */
                        /* Push it to shadowmap array */
-                       DRW_framebuffer_bind(sldata->shadow_cube_fb);
+
+                       /* Adjust constants if concentric samples change. */
+                       const float max_filter_size = 7.5f;
+                       const float previous_box_filter_size = 9.0f; /* Dunno why but that works. */
+                       const int max_sample = 256;
+
+                       if (filter_pixel_size > 2.0f) {
+                               linfo->filter_size = linfo->shadow_render_data.cube_texel_size * max_filter_size * previous_box_filter_size;
+                               filter_pixel_size = max_ff(0.0f, filter_pixel_size - 3.0f);
+                               /* Compute number of concentric samples. Depends directly on filter size. */
+                               float pix_size_sqr = filter_pixel_size * filter_pixel_size;
+                               srd->shadow_samples_ct = min_ii(max_sample, 4 + 8 * (int)filter_pixel_size + 4 * (int)(pix_size_sqr));
+                       }
+                       else {
+                               linfo->filter_size = 0.0f;
+                               srd->shadow_samples_ct = 4;
+                       }
+                       srd->shadow_inv_samples_ct = 1.0f / (float)srd->shadow_samples_ct;
+                       DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd);
+
+                       DRW_framebuffer_texture_layer_attach(sldata->shadow_store_fb, sldata->shadow_pool, 0, evscd->layer_id, 0);
+                       DRW_framebuffer_bind(sldata->shadow_store_fb);
                        DRW_draw_pass(psl->shadow_cube_store_pass);
 
                        led->need_update = false;
                        DRW_draw_pass(psl->shadow_cube_store_pass);
 
                        led->need_update = false;
@@ -778,44 +976,92 @@ void EEVEE_draw_shadows(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
        }
        linfo->update_flag &= ~LIGHT_UPDATE_SHADOW_CUBE;
 
        }
        linfo->update_flag &= ~LIGHT_UPDATE_SHADOW_CUBE;
 
-#if 0
-       /* Standard Shadow Maps */
-       DRW_framebuffer_bind(fbl->shadow_map_fb);
-       DRW_framebuffer_clear(false, true, false, NULL, 1.0);
+       DRW_framebuffer_texture_detach(sldata->shadow_cube_target);
+       DRW_stats_group_end();
 
 
-       /* Render each shadow to one layer of the array */
-       for (i = 0; (ob = linfo->shadow_map_ref[i]) && (i < MAX_SHADOW_MAP); i++) {
+       /* Cascaded Shadow Maps */
+       DRW_stats_group_start("Cascaded Shadow Maps");
+       DRW_framebuffer_texture_attach(sldata->shadow_target_fb, sldata->shadow_cascade_target, 0, 0);
+       for (i = 0; (ob = linfo->shadow_cascade_ref[i]) && (i < MAX_SHADOW_CASCADE); i++) {
                EEVEE_LampEngineData *led = EEVEE_lamp_data_get(ob);
                EEVEE_LampEngineData *led = EEVEE_lamp_data_get(ob);
-               EEVEE_ShadowMapData *evsmd = (EEVEE_ShadowMapData *)led->storage;
+               Lamp *la = (Lamp *)ob->data;
+
+               EEVEE_ShadowCascadeData *evscd = (EEVEE_ShadowCascadeData *)led->storage;
+               EEVEE_ShadowRender *srd = &linfo->shadow_render_data;
+
+               eevee_shadow_cascade_setup(ob, linfo, led);
 
 
-               linfo->layer = i;
-               copy_m4_m4(linfo->shadowmat, evsmd->viewprojmat);
-               DRW_draw_pass(vedata->psl->shadow_pass);
+               srd->clip_near = la->clipsta;
+               srd->clip_far = la->clipend;
+               for (int j = 0; j < la->cascade_count; ++j) {
+                       copy_m4_m4(srd->shadowmat[j], evscd->viewprojmat[j]);
+               }
+               DRW_uniformbuffer_update(sldata->shadow_render_ubo, &linfo->shadow_render_data);
+
+               DRW_framebuffer_bind(sldata->shadow_target_fb);
+               DRW_framebuffer_clear(false, true, false, NULL, 1.0);
+
+               /* Render shadow cascades */
+               DRW_draw_pass(psl->shadow_cascade_pass);
+
+               /* TODO: OPTI: Filter all cascade in one/two draw call */
+               for (linfo->current_shadow_cascade = 0;
+                    linfo->current_shadow_cascade < la->cascade_count;
+                    ++linfo->current_shadow_cascade)
+               {
+                       /* 0.01f factor to convert to percentage */
+                       float filter_texture_size = la->soft * 0.01f / evscd->radius[linfo->current_shadow_cascade];
+                       float filter_pixel_size = ceil(linfo->shadow_size * filter_texture_size);
+
+                       /* Copy using a small 3x3 box filter */
+                       linfo->filter_size = linfo->shadow_render_data.stored_texel_size * ((filter_pixel_size > 1.0f) ? 1.0f : 0.0f);
+                       DRW_framebuffer_texture_layer_attach(sldata->shadow_store_fb, sldata->shadow_cascade_blur, 0, linfo->current_shadow_cascade, 0);
+                       DRW_framebuffer_bind(sldata->shadow_store_fb);
+                       DRW_draw_pass(psl->shadow_cascade_copy_pass);
+                       DRW_framebuffer_texture_detach(sldata->shadow_cascade_blur);
+
+                       /* Push it to shadowmap array and blur more */
+
+                       /* Adjust constants if concentric samples change. */
+                       const float max_filter_size = 7.5f;
+                       const float previous_box_filter_size = 3.2f; /* Arbitrary: less banding */
+                       const int max_sample = 256;
+
+                       if (filter_pixel_size > 2.0f) {
+                               linfo->filter_size = linfo->shadow_render_data.stored_texel_size * max_filter_size * previous_box_filter_size;
+                               filter_pixel_size = max_ff(0.0f, filter_pixel_size - 3.0f);
+                               /* Compute number of concentric samples. Depends directly on filter size. */
+                               float pix_size_sqr = filter_pixel_size * filter_pixel_size;
+                               srd->shadow_samples_ct = min_ii(max_sample, 4 + 8 * (int)filter_pixel_size + 4 * (int)(pix_size_sqr));
+                       }
+                       else {
+                               linfo->filter_size = 0.0f;
+                               srd->shadow_samples_ct = 4;
+                       }
+                       srd->shadow_inv_samples_ct = 1.0f / (float)srd->shadow_samples_ct;
+                       DRW_uniformbuffer_update(sldata->shadow_render_ubo, &linfo->shadow_render_data);
+
+                       int layer = evscd->layer_id + linfo->current_shadow_cascade;
+                       DRW_framebuffer_texture_layer_attach(sldata->shadow_store_fb, sldata->shadow_pool, 0, layer, 0);
+                       DRW_framebuffer_bind(sldata->shadow_store_fb);
+                       DRW_draw_pass(psl->shadow_cascade_store_pass);
+               }
        }
        }
-#endif
 
 
-       /* Cascaded Shadow Maps */
-//     DRW_framebuffer_bind(fbl->shadow_cascade_fb);
-//     DRW_framebuffer_clear(false, true, false, NULL, 1.0);
-
-//     /* Render each shadow to one layer of the array */
-//     for (i = 0; (ob = linfo->shadow_cascade_ref[i]) && (i < MAX_SHADOW_CASCADE); i++) {
-//             EEVEE_LampEngineData *led = EEVEE_lamp_data_get(ob);
-//             EEVEE_ShadowCascadeData *evscd = (EEVEE_ShadowCascadeData *)led->storage;
-//             EEVEE_ShadowRender *srd = &linfo->shadow_render_data;
-
-//             srd->layer = i;
-//             for (int j = 0; j < MAX_CASCADE_NUM; ++j) {
-//                     copy_m4_m4(srd->shadowmat[j], evscd->viewprojmat[j]);
-//             }
-//             DRW_uniformbuffer_update(sldata->shadow_render_ubo, &linfo->shadow_render_data);
-
-//             DRW_draw_pass(psl->shadow_cascade_pass);
-//     }
+       DRW_framebuffer_texture_detach(sldata->shadow_cascade_target);
+       DRW_stats_group_end();
+
+       DRW_uniformbuffer_update(sldata->light_ubo, &linfo->light_data);
+       DRW_uniformbuffer_update(sldata->shadow_ubo, &linfo->shadow_data); /* Update all data at once */
 }
 
 void EEVEE_lights_free(void)
 {
        DRW_SHADER_FREE_SAFE(e_data.shadow_sh);
 }
 
 void EEVEE_lights_free(void)
 {
        DRW_SHADER_FREE_SAFE(e_data.shadow_sh);
-       DRW_SHADER_FREE_SAFE(e_data.shadow_store_sh);
+       for (int i = 0; i < SHADOW_METHOD_MAX; ++i) {
+               DRW_SHADER_FREE_SAFE(e_data.shadow_store_cube_sh[i]);
+               DRW_SHADER_FREE_SAFE(e_data.shadow_store_cascade_sh[i]);
+               DRW_SHADER_FREE_SAFE(e_data.shadow_copy_cube_sh[i]);
+               DRW_SHADER_FREE_SAFE(e_data.shadow_copy_cascade_sh[i]);
+       }
 }
\ No newline at end of file
 }
\ No newline at end of file