diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2017-04-20 14:07:24 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2017-04-20 14:07:51 +0300 |
commit | 3d17ece53924aae7289d279bf139ca444dd5bf82 (patch) | |
tree | 9512cb1b80c3c463ae0ea9748177eea12391a0ca /source/blender/draw/engines/eevee/eevee_lights.c | |
parent | b386828671a40feea026ccefae17560e58e0d440 (diff) |
Eevee: Start Implementation of Cascaded Shadow Maps
Diffstat (limited to 'source/blender/draw/engines/eevee/eevee_lights.c')
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_lights.c | 138 |
1 files changed, 117 insertions, 21 deletions
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); + } +#endif - // linfo->layer = i; - // copy_m4_m4(linfo->shadowmat, evsmd->viewprojmat); - // DRW_draw_pass(vedata->psl->shadow_pass); - // } + /* Cascaded Shadow Maps */ + DRW_framebuffer_bind(fbl->shadow_cascade_fb); + DRW_framebuffer_clear(false, true, false, NULL, 1.0); - // DRW_framebuffer_bind(e_data.shadow_cascade_fb); + /* 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); + } } |