diff --git a/source/blender/draw/engines/eevee/eevee.c b/source/blender/draw/engines/eevee/eevee.c index fca7feb2f65..0c3802b37ad 100644 --- a/source/blender/draw/engines/eevee/eevee.c +++ b/source/blender/draw/engines/eevee/eevee.c @@ -316,6 +316,18 @@ static DRWShadingGroup *eevee_cube_shadow_shgroup(EEVEE_PassList *psl, EEVEE_Sto return grp; } +static DRWShadingGroup *eevee_cascade_shadow_shgroup(EEVEE_PassList *psl, EEVEE_StorageList *stl, struct Batch *geom, float (*obmat)[4]) +{ + DRWShadingGroup *grp = DRW_shgroup_instance_create(e_data.shadow_sh, psl->shadow_cascade_pass, geom); + DRW_shgroup_uniform_block(grp, "shadow_render_block", stl->shadow_render_ubo, 0); + DRW_shgroup_uniform_mat4(grp, "ShadowModelMatrix", (float *)obmat); + + for (int i = 0; i < MAX_CASCADE_NUM; ++i) + DRW_shgroup_dynamic_call_add_empty(grp); + + return grp; +} + static void EEVEE_cache_init(void *vedata) { EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; @@ -331,6 +343,10 @@ static void EEVEE_cache_init(void *vedata) psl->shadow_cube_pass = DRW_pass_create("Shadow Cube Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); } + { + psl->shadow_cascade_pass = DRW_pass_create("Shadow Cascade Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); + } + { // psl->shadow_pass = DRW_pass_create("Shadow Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); // stl->g_data->shadow_shgrp = DRW_shgroup_create(e_data.shadow_sh, psl->shadow_pass); @@ -430,6 +446,7 @@ static void EEVEE_cache_populate(void *vedata, Object *ob) DRW_shgroup_call_add(stl->g_data->default_lit_grp, geom, ob->obmat); // DRW_shgroup_call_add(stl->g_data->shadow_shgrp, geom, ob->obmat); + eevee_cascade_shadow_shgroup(psl, stl, geom, ob->obmat); eevee_cube_shadow_shgroup(psl, stl, geom, ob->obmat); } else if (ob->type == OB_LAMP) { @@ -448,6 +465,7 @@ static void EEVEE_cache_finish(void *vedata) /* Shadows binding */ DRW_shgroup_uniform_texture(stl->g_data->default_lit_grp, "shadowMaps", txl->shadow_depth_map_pool, 4); DRW_shgroup_uniform_texture(stl->g_data->default_lit_grp, "shadowCubes", txl->shadow_depth_cube_pool, 5); + DRW_shgroup_uniform_texture(stl->g_data->default_lit_grp, "shadowCascades", txl->shadow_depth_cascade_pool, 6); } static void EEVEE_draw_scene(void *vedata) diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c index 6c694b05e6a..7c4a5523ecd 100644 --- a/source/blender/draw/engines/eevee/eevee_lights.c +++ b/source/blender/draw/engines/eevee/eevee_lights.c @@ -90,11 +90,11 @@ void EEVEE_lights_cache_add(EEVEE_StorageList *stl, Object *ob) DRW_lamp_engine_data_free((void *)led); if (la->mode & (LA_SHAD_BUF | LA_SHAD_RAY)) { - if (la->type == LA_SUN && linfo->num_map < MAX_SHADOW_MAP) { - led->sto = MEM_mallocN(sizeof(EEVEE_ShadowMapData), "EEVEE_ShadowMapData"); - ((EEVEE_ShadowMapData *)led->sto)->shadow_id = linfo->num_map; - linfo->shadow_map_ref[linfo->num_map] = ob; - linfo->num_map++; + if (la->type == LA_SUN && linfo->num_cascade < MAX_SHADOW_CASCADE) { + led->sto = MEM_mallocN(sizeof(EEVEE_ShadowCascadeData), "EEVEE_ShadowCascadeData"); + ((EEVEE_ShadowCascadeData *)led->sto)->shadow_id = linfo->num_cascade; + linfo->shadow_cascade_ref[linfo->num_cascade] = ob; + linfo->num_cascade++; } else if ((la->type == LA_SPOT || la->type == LA_LOCAL || la->type == LA_AREA) && linfo->num_cube < MAX_SHADOW_CUBE) { @@ -150,7 +150,7 @@ void EEVEE_lights_cache_finish(EEVEE_StorageList *stl, EEVEE_TextureList *txl, E DRW_framebuffer_texture_attach(fbl->shadow_map_fb, txl->shadow_depth_map_pool, 0, 0); } if (!txl->shadow_depth_cascade_pool) { - txl->shadow_depth_cascade_pool = DRW_texture_create_2D_array(512, 512, MAX2(1, linfo->num_cascade), DRW_TEX_DEPTH_24, DRW_TEX_FILTER | DRW_TEX_COMPARE, NULL); + txl->shadow_depth_cascade_pool = DRW_texture_create_2D_array(512, 512, MAX2(1, linfo->num_cascade * MAX_CASCADE_NUM), DRW_TEX_DEPTH_24, DRW_TEX_FILTER | DRW_TEX_COMPARE, NULL); if (fbl->shadow_cascade_fb) DRW_framebuffer_texture_attach(fbl->shadow_cascade_fb, txl->shadow_depth_map_pool, 0, 0); } @@ -293,6 +293,83 @@ static void eevee_shadow_map_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_Lam evli->shadowid = (float)(MAX_SHADOW_CUBE + evsmp->shadow_id); } +#define LERP(t, a, b) ((a) + (t) * ((b) - (a))) + +static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngineData *led) +{ + /* Camera Matrices */ + float persmat[4][4], persinv[4][4]; + /* Lamps Matrices */ + float viewmat[4][4], projmat[4][4]; + float minvec[3], maxvec[3]; + int cascade_ct = MAX_CASCADE_NUM; + + EEVEE_ShadowCascadeData *evscp = (EEVEE_ShadowCascadeData *)led->sto; + EEVEE_Light *evli = linfo->light_data + evscp->light_id; + EEVEE_ShadowCascade *evsh = linfo->shadow_cascade_data + evscp->shadow_id; + Lamp *la = (Lamp *)ob->data; + + /* The technique consists into splitting + * the view frustum into several sub-frustum + * that are individually receiving one shadow map */ + + /* For each cascade */ + for (int c = 0; c < cascade_ct; ++c) { + float splitnear = LERP(((float)(c) / cascade_ct), -1.0f, 1.0f); + float splitfar = LERP(((float)(c + 1) / cascade_ct), -1.0f, 1.0f); + + /* Given 8 frustrum corners */ + float corners[8][4] = { + /* Far Cap */ + {-1.0f, -1.0f, splitfar, 1.0f}, + { 1.0f, -1.0f, splitfar, 1.0f}, + {-1.0f, 1.0f, splitfar, 1.0f}, + { 1.0f, 1.0f, splitfar, 1.0f}, + /* Near Cap */ + {-1.0f, -1.0f, splitnear, 1.0f}, + { 1.0f, -1.0f, splitnear, 1.0f}, + {-1.0f, 1.0f, splitnear, 1.0f}, + { 1.0f, 1.0f, splitnear, 1.0f} + }; + + /* Transform them into world space */ + DRW_viewport_matrix_get(persmat, DRW_MAT_PERS); + invert_m4_m4(persinv, persmat); + for (int i = 0; i < 8; ++i) { + mul_m4_v4(persinv, corners[i]); + mul_v3_fl(corners[i], 1.0f / corners[i][3]); + corners[i][3] = 1.0f; + } + + /* Project them into light space */ + invert_m4_m4(viewmat, ob->obmat); + normalize_v3(viewmat[0]); + normalize_v3(viewmat[1]); + normalize_v3(viewmat[2]); + + for (int i = 0; i < 8; ++i) { + mul_m4_v4(viewmat, corners[i]); + } + + /* compute the minimum bounding box */ + INIT_MINMAX(minvec, maxvec); + for (int i = 0; i < 8; ++i) { + minmax_v3v3_v3(minvec, maxvec, corners[i]); + } + + /* expand the bounding box to cover light range */ + orthographic_m4(projmat, minvec[0], maxvec[0], minvec[1], maxvec[1], la->clipsta, la->clipend); + + mul_m4_m4m4(evscp->viewprojmat[c], projmat, viewmat); + mul_m4_m4m4(evsh->shadowmat[c], texcomat, evscp->viewprojmat[c]); + } + + evsh->bias = 0.005f * la->bias; + evsh->count = (float)cascade_ct; + + evli->shadowid = (float)(MAX_SHADOW_CUBE + MAX_SHADOW_MAP + evscp->shadow_id); +} + void EEVEE_lights_update(EEVEE_StorageList *stl) { EEVEE_LampsInfo *linfo = stl->lamps; @@ -314,10 +391,10 @@ void EEVEE_lights_update(EEVEE_StorageList *stl) 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_LampEngineData *)DRW_lamp_engine_data_get(ob, &viewport_eevee_type); - // 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_LampEngineData *)DRW_lamp_engine_data_get(ob, &viewport_eevee_type); + eevee_shadow_cascade_setup(ob, linfo, led); + } DRW_uniformbuffer_update(stl->light_ubo, &linfo->light_data); DRW_uniformbuffer_update(stl->shadow_ubo, &linfo->shadow_cube_data); /* Update all data at once */ @@ -355,19 +432,38 @@ void EEVEE_draw_shadows(EEVEE_Data *vedata) DRW_draw_pass(psl->shadow_cube_pass); } +#if 0 /* Standard Shadow Maps */ - // DRW_framebuffer_bind(fbl->shadow_map_fb); - // DRW_framebuffer_clear(false, true, false, NULL, 1.0); + DRW_framebuffer_bind(fbl->shadow_map_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_map_ref[i]) && (i < MAX_SHADOW_MAP); i++) { - // EEVEE_LampEngineData *led = (EEVEE_LampEngineData *)DRW_lamp_engine_data_get(ob, &viewport_eevee_type); - // EEVEE_ShadowMapData *evsmd = (EEVEE_ShadowMapData *)led->sto; + /* Render each shadow to one layer of the array */ + for (i = 0; (ob = linfo->shadow_map_ref[i]) && (i < MAX_SHADOW_MAP); i++) { + EEVEE_LampEngineData *led = (EEVEE_LampEngineData *)DRW_lamp_engine_data_get(ob, &viewport_eevee_type); + EEVEE_ShadowMapData *evsmd = (EEVEE_ShadowMapData *)led->sto; - // linfo->layer = i; - // copy_m4_m4(linfo->shadowmat, evsmd->viewprojmat); - // DRW_draw_pass(vedata->psl->shadow_pass); - // } + linfo->layer = i; + copy_m4_m4(linfo->shadowmat, evsmd->viewprojmat); + DRW_draw_pass(vedata->psl->shadow_pass); + } +#endif - // DRW_framebuffer_bind(e_data.shadow_cascade_fb); + /* 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_LampEngineData *)DRW_lamp_engine_data_get(ob, &viewport_eevee_type); + EEVEE_ShadowCascadeData *evscd = (EEVEE_ShadowCascadeData *)led->sto; + 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(stl->shadow_render_ubo, &linfo->shadow_render_data); + + DRW_draw_pass(psl->shadow_cascade_pass); + } } diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 97d78a7ce84..6f249ea888d 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -36,6 +36,7 @@ typedef struct EEVEE_PassList { /* Shadows */ struct DRWPass *shadow_pass; struct DRWPass *shadow_cube_pass; + struct DRWPass *shadow_cascade_pass; /* Probes */ struct DRWPass *probe_background; diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl index 189cdcf10fb..02111d6fcba 100644 --- a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl @@ -13,7 +13,7 @@ uniform sampler2D brdfLut; #endif uniform sampler2DArrayShadow shadowCubes; uniform sampler2DArrayShadow shadowMaps; -// uniform sampler2DArrayShadow shadowCascades; +uniform sampler2DArrayShadow shadowCascades; layout(std140) uniform light_block { LightData lights_data[MAX_LIGHT]; @@ -88,6 +88,20 @@ float light_visibility(LightData ld, ShadingData sd) /* shadowing */ if (ld.l_shadowid >= (MAX_SHADOW_MAP + MAX_SHADOW_CUBE)) { /* Shadow Cascade */ + float shid = ld.l_shadowid - (MAX_SHADOW_CUBE + MAX_SHADOW_MAP); + ShadowCascadeData smd = shadows_cascade_data[int(shid)]; + + for (int i = 0; i < int(smd.sh_cascade_count); i++) { + vec4 shpos = smd.shadowmat[i] * vec4(sd.W, 1.0); + shpos.z -= smd.sh_cascade_bias * shpos.w; + shpos.xyz /= shpos.w; + + if (shpos.w > 0.0 && min(shpos.x, shpos.y) > 0.0 && max(shpos.x, shpos.y) < 1.0) { + vis *= texture(shadowCascades, vec4(shpos.xy, shid * float(MAX_CASCADE_NUM) + float(i), shpos.z)); + // vis = float(i) / float(MAX_CASCADE_NUM); + break; + } + } } else if (ld.l_shadowid >= MAX_SHADOW_CUBE) { /* Shadow Map */ diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 50e5b541290..355c3b41c4f 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -1889,7 +1889,6 @@ void DRW_draw_view(const bContext *C) DRW_engines_draw_background(); DRW_draw_callbacks_pre_scene(); - // DRW_draw_grid(); DRW_engines_draw_scene(); DRW_draw_callbacks_post_scene();