Commit: f59b1179c5b368179fd78a2ad999161ad4f071b9 Author: Clément Foucault Date: Thu Jun 1 18:20:44 2017 +0200 Branches: blender2.8 https://developer.blender.org/rBf59b1179c5b368179fd78a2ad999161ad4f071b9
Eevee: Tag shadow maps to update only when necessary. Shadow maps are now only updated if one shadow casting object inside it's shadow bounds has been updated. =================================================================== M source/blender/draw/engines/eevee/eevee_engine.c M source/blender/draw/engines/eevee/eevee_lights.c M source/blender/draw/engines/eevee/eevee_private.h =================================================================== diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index cd3819b88e1..3e2b47819d7 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -441,6 +441,17 @@ static void EEVEE_cache_init(void *vedata) EEVEE_effects_cache_init(vedata); } +EEVEE_ObjectEngineData *EEVEE_get_object_engine_data(Object *ob) +{ + EEVEE_ObjectEngineData **oedata = (EEVEE_ObjectEngineData **)DRW_object_engine_data_get(ob, &draw_engine_eevee_type, NULL); + + if (*oedata == NULL) { + *oedata = MEM_callocN(sizeof(**oedata), "EEVEE_ObjectEngineData"); + } + + return *oedata; +} + static void EEVEE_cache_populate(void *vedata, Object *ob) { EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; @@ -565,6 +576,9 @@ static void EEVEE_cache_populate(void *vedata, Object *ob) if (cast_shadow) { EEVEE_lights_cache_shcaster_add(sldata, psl, geom, ob->obmat); + BLI_addtail(&sldata->shadow_casters, BLI_genericNodeN(ob)); + EEVEE_ObjectEngineData *oedata = EEVEE_get_object_engine_data(ob); + oedata->need_update = ((ob->deg_update_flag & DEG_RUNTIME_DATA_UPDATE) != 0); } } else if (ob->type == OB_LAMP) { diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c index 4c992fca8e0..9dd87cc11f3 100644 --- a/source/blender/draw/engines/eevee/eevee_lights.c +++ b/source/blender/draw/engines/eevee/eevee_lights.c @@ -25,6 +25,8 @@ #include "DRW_render.h" +#include "BKE_object.h" + #include "eevee_engine.h" #include "eevee_private.h" @@ -47,6 +49,12 @@ typedef struct EEVEE_ShadowCascadeData { float viewprojmat[MAX_CASCADE_NUM][4][4]; /* World->Lamp->NDC : used for rendering the shadow map. */ } EEVEE_ShadowCascadeData; +typedef struct ShadowCaster { + struct ShadowCaster *next, *prev; + void *ob; + bool prune; +} ShadowCaster; + static struct { struct GPUShader *shadow_sh; struct GPUShader *shadow_store_sh; @@ -61,6 +69,25 @@ extern char datatoc_shadow_store_frag_glsl[]; /* *********** FUNCTIONS *********** */ +static void eevee_lamp_engine_data_free(void *storage) +{ + EEVEE_LampEngineData *led = (EEVEE_LampEngineData *)storage; + MEM_SAFE_FREE(led->storage); + BLI_freelistN(&led->shadow_caster_list); +} + +static EEVEE_LampEngineData *eevee_get_lamp_engine_data(Object *ob) +{ + EEVEE_LampEngineData **ledata = (EEVEE_LampEngineData **)DRW_object_engine_data_get(ob, &draw_engine_eevee_type, &eevee_lamp_engine_data_free); + + if (*ledata == NULL) { + *ledata = MEM_callocN(sizeof(**ledata), "EEVEE_LampEngineData"); + (*ledata)->need_update = true; + } + + return *ledata; +} + void EEVEE_lights_init(EEVEE_SceneLayerData *sldata) { const unsigned int shadow_ubo_size = sizeof(EEVEE_ShadowCube) * MAX_SHADOW_CUBE + @@ -109,6 +136,9 @@ 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); } + + /* Reset shadow casters list */ + BLI_freelistN(&sldata->shadow_casters); } void EEVEE_lights_cache_add(EEVEE_SceneLayerData *sldata, Object *ob) @@ -122,37 +152,43 @@ void EEVEE_lights_cache_add(EEVEE_SceneLayerData *sldata, Object *ob) } else { Lamp *la = (Lamp *)ob->data; - EEVEE_LampEngineData *led = (EEVEE_LampEngineData *)DRW_lamp_engine_data_get(ob, &DRW_engine_viewport_eevee_type); + EEVEE_LampEngineData *led = eevee_get_lamp_engine_data(ob); + + if ((ob->deg_update_flag & DEG_RUNTIME_DATA_UPDATE) != 0) { + led->need_update = true; + } - DRW_lamp_engine_data_free((void *)led); + 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->type == LA_SUN && linfo->num_cascade < MAX_SHADOW_CASCADE) { #if 0 /* TODO filter cascaded shadow map */ - led->sto = MEM_mallocN(sizeof(EEVEE_ShadowCascadeData), "EEVEE_ShadowCascadeData"); - ((EEVEE_ShadowCascadeData *)led->sto)->shadow_id = linfo->num_cascade; + 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 } else if ((la->type == LA_SPOT || la->type == LA_LOCAL || la->type == LA_AREA) && linfo->num_cube < MAX_SHADOW_CUBE) { - led->sto = MEM_mallocN(sizeof(EEVEE_ShadowCubeData), "EEVEE_ShadowCubeData"); - ((EEVEE_ShadowCubeData *)led->sto)->shadow_id = linfo->num_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 UNUSED_VARS(la); #endif - if (!led->sto) { - led->sto = MEM_mallocN(sizeof(EEVEE_LightData), "EEVEE_LightData"); - ((EEVEE_LightData *)led->sto)->shadow_id = -1; + /* Default light without shadows */ + if (!led->storage) { + led->storage = MEM_mallocN(sizeof(EEVEE_LightData), "EEVEE_LightData"); + ((EEVEE_LightData *)led->storage)->shadow_id = -1; } - ((EEVEE_LightData *)led->sto)->light_id = linfo->num_light; + ((EEVEE_LightData *)led->storage)->light_id = linfo->num_light; linfo->light_ref[linfo->num_light] = ob; linfo->num_light++; } @@ -180,14 +216,13 @@ void EEVEE_lights_cache_finish(EEVEE_SceneLayerData *sldata) { EEVEE_LampsInfo *linfo = sldata->lamps; - /* Step 4 Update Lamp UBOs */ - EEVEE_lights_update(sldata); - /* Step 5 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; + linfo->update_flag |= LIGHT_UPDATE_SHADOW_CUBE; } if (linfo->num_map != linfo->cache_num_map) { DRW_TEXTURE_FREE_SAFE(sldata->shadow_depth_map_pool); @@ -245,13 +280,16 @@ void EEVEE_lights_cache_finish(EEVEE_SceneLayerData *sldata) 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); + + /* Update Lamps UBOs. */ + EEVEE_lights_update(sldata); } /* Update buffer with lamp data */ static void eevee_light_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngineData *led) { /* TODO only update if data changes */ - EEVEE_LightData *evld = led->sto; + EEVEE_LightData *evld = led->storage; EEVEE_Light *evli = linfo->light_data + evld->light_id; Lamp *la = (Lamp *)ob->data; float mat[4][4], scale[3], power; @@ -326,7 +364,7 @@ static void eevee_shadow_cube_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_La { float projmat[4][4]; - EEVEE_ShadowCubeData *evsmp = (EEVEE_ShadowCubeData *)led->sto; + 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; Lamp *la = (Lamp *)ob->data; @@ -352,7 +390,7 @@ static void eevee_shadow_map_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_Lam { float viewmat[4][4], projmat[4][4]; - EEVEE_ShadowMapData *evsmp = (EEVEE_ShadowMapData *)led->sto; + 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; @@ -435,7 +473,7 @@ static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE int cascade_ct = MAX_CASCADE_NUM; float shadow_res = 512.0f; /* TODO parameter */ - EEVEE_ShadowCascadeData *evscp = (EEVEE_ShadowCascadeData *)led->sto; + 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; @@ -546,29 +584,135 @@ static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE evli->shadowid = (float)(MAX_SHADOW_CUBE + MAX_SHADOW_MAP + evscp->shadow_id); } +/* Used for checking if object is inside the shadow volume. */ +static bool cube_bbox_intersect(const float cube_center[3], float cube_half_dim, const BoundBox *bb, float (*obmat)[4]) +{ + float min[3], max[4], tmp[4][4]; + unit_m4(tmp); + translate_m4(tmp, -cube_center[0], -cube_center[1], -cube_center[2]); + mul_m4_m4m4(tmp, tmp, obmat); + + /* Just simple AABB intersection test in world space. */ + INIT_MINMAX(min, max); + for (int i = 0; i < 8; ++i) { + float vec[3]; + copy_v3_v3(vec, bb->vec[i]); + mul_m4_v3(tmp, vec); + minmax_v3v3_v3(min, max, vec); + } + + if (MAX3(max[0], max[1], max[2]) < -cube_half_dim) return false; + if (MIN3(min[0], min[1], min[2]) > cube_half_dim) return false; + + return true; +} + +static ShadowCaster *search_object_in_list(ListBase *list, Object *ob) +{ + for (ShadowCaster *ldata = list->first; ldata; ldata = ldata->next) { + if (ldata->ob == ob) + return ldata; + } + + return NULL; +} + +static void delete_pruned_shadowcaster(EEVEE_LampEngineData *led) +{ + ShadowCaster *next; + for (ShadowCaster *ldata = led->shadow_caster_list.first; ldata; ldata = next) { + next = ldata->next; + if (ldata->prune == true) { + BLI_freelinkN(&led->shadow_caster_list, ldata); + } + } +} + +static void light_tag_shadow_update(Object *lamp, Object *ob) +{ + Lamp *la = lamp->data; + EEVEE_LampEngineData *led = eevee_get_lamp_engine_data(lamp); + + bool is_inside_range = cube_bbox_intersect(lamp->obmat[3], la->clipend, BKE_object_boundbox_get(ob), ob->obmat); + ShadowCaster *ldata = search_object_in_list(&led->shadow_caster_list, ob); + + if (is_inside_range) { + if (ldata == NULL) { + /* Object was not a shadow caster previously but is now. Add it. */ + ldata = MEM_callocN(siz @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org https://lists.blender.org/mailman/listinfo/bf-blender-cvs