diff options
8 files changed, 351 insertions, 188 deletions
diff --git a/release/scripts/startup/bl_ui/properties_data_lamp.py b/release/scripts/startup/bl_ui/properties_data_lamp.py index c9b5fa80122..39b5f0eba55 100644 --- a/release/scripts/startup/bl_ui/properties_data_lamp.py +++ b/release/scripts/startup/bl_ui/properties_data_lamp.py @@ -371,23 +371,20 @@ class DATA_PT_EEVEE_shadow(DataButtonsPanel, Panel): lamp = context.lamp - if lamp.type == 'SUN': - layout.label("Comming Soon") - else: - split = layout.split() - split.active = lamp.use_shadow - - sub = split.column() - col = sub.column(align=True) - col.prop(lamp, "shadow_buffer_clip_start", text="Clip Start") - col.prop(lamp, "shadow_buffer_clip_end", text="Clip End") - col = sub.column() - col.prop(lamp, "shadow_buffer_soft", text="Soft") - - col = split.column(align=True) - col.prop(lamp, "shadow_buffer_bias", text="Bias") - col.prop(lamp, "shadow_buffer_exp", text="Exponent") - col.prop(lamp, "shadow_buffer_bleed_bias", text="Bleed Bias") + split = layout.split() + split.active = lamp.use_shadow + + sub = split.column() + col = sub.column(align=True) + col.prop(lamp, "shadow_buffer_clip_start", text="Clip Start") + col.prop(lamp, "shadow_buffer_clip_end", text="Clip End") + col = sub.column() + col.prop(lamp, "shadow_buffer_soft", text="Soft") + + col = split.column(align=True) + col.prop(lamp, "shadow_buffer_bias", text="Bias") + col.prop(lamp, "shadow_buffer_exp", text="Exponent") + col.prop(lamp, "shadow_buffer_bleed_bias", text="Bleed Bias") class DATA_PT_area(DataButtonsPanel, Panel): diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c index 0033670528a..2bd33f0a755 100644 --- a/source/blender/draw/engines/eevee/eevee_lights.c +++ b/source/blender/draw/engines/eevee/eevee_lights.c @@ -38,13 +38,13 @@ typedef struct EEVEE_LightData { } 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; 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 radius[MAX_CASCADE_NUM]; } EEVEE_ShadowCascadeData; typedef struct ShadowCaster { @@ -68,7 +68,8 @@ extern char datatoc_shadow_store_frag_glsl[]; void EEVEE_lights_init(EEVEE_SceneLayerData *sldata) { - const unsigned int shadow_ubo_size = sizeof(EEVEE_ShadowCube) * MAX_SHADOW_CUBE + + const unsigned int shadow_ubo_size = sizeof(EEVEE_Shadow) * MAX_SHADOW + + sizeof(EEVEE_ShadowCube) * MAX_SHADOW_CUBE + sizeof(EEVEE_ShadowCascade) * MAX_SHADOW_CASCADE; const DRWContextState *draw_ctx = DRW_context_state_get(); @@ -130,7 +131,10 @@ void EEVEE_lights_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl) { EEVEE_LampsInfo *linfo = sldata->lamps; - linfo->num_light = linfo->num_cube = linfo->num_cascade = linfo->num_shadow = 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->shadow_cascade_ref, 0, sizeof(linfo->shadow_cascade_ref)); @@ -141,6 +145,7 @@ void EEVEE_lights_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl) 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_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_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); } @@ -150,6 +155,8 @@ void EEVEE_lights_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl) 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_target); 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); } @@ -184,28 +191,54 @@ void EEVEE_lights_cache_add(EEVEE_SceneLayerData *sldata, Object *ob) 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) { - led->storage = MEM_mallocN(sizeof(EEVEE_ShadowCascadeData), "EEVEE_ShadowCascadeData"); - ((EEVEE_ShadowCascadeData *)led->storage)->shadow_id = linfo->num_shadow; - linfo->shadow_cascade_ref[linfo->num_cascade] = ob; - linfo->num_cascade++; - linfo->num_shadow += MAX_CASCADE_NUM; + 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_shadow; - linfo->shadow_cube_ref[linfo->num_cube] = ob; - linfo->num_cube++; - linfo->num_shadow += 1; + 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"); @@ -270,14 +303,9 @@ void EEVEE_lights_cache_finish(EEVEE_SceneLayerData *sldata) /* Setup enough layers. */ /* Free textures if number mismatch. */ - if ((linfo->num_shadow != linfo->cache_num_shadow) || - (linfo->num_cube != linfo->cache_num_cube) || - (linfo->num_cascade != linfo->cache_num_cascade)) - { + if (linfo->num_layer != linfo->cache_num_layer) { DRW_TEXTURE_FREE_SAFE(sldata->shadow_pool); - linfo->cache_num_cube = linfo->num_cube; - linfo->cache_num_cascade = linfo->num_cascade; - linfo->cache_num_shadow = linfo->num_shadow; + linfo->cache_num_layer = linfo->num_layer; linfo->update_flag |= LIGHT_UPDATE_SHADOW_CUBE; } @@ -305,7 +333,7 @@ void EEVEE_lights_cache_finish(EEVEE_SceneLayerData *sldata) 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_cube + linfo->num_cascade), + linfo->shadow_size, linfo->shadow_size, max_ff(1, linfo->num_layer), shadow_pool_format, DRW_TEX_FILTER, NULL); } @@ -405,29 +433,28 @@ 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) { - 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; - 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 = (linfo->shadow_method == SHADOW_VSM) ? la->bleedbias : la->bleedexp; + 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)(evsmp->shadow_id); + 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); } #define LERP(t, a, b) ((a) + (t) * ((b) - (a))) @@ -489,12 +516,13 @@ static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE /* 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 = MAX_CASCADE_NUM; /* TODO : Custom cascade number */ - 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; + 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; Lamp *la = (Lamp *)ob->data; /* The technique consists into splitting @@ -503,29 +531,29 @@ static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE /* init near/far */ for (int c = 0; c < MAX_CASCADE_NUM; ++c) { - evsh->split[c] = far; + cascade_data->split[c] = far; } /* 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) { + splits_ndc[cascade_nbr] = 1.0f; + for (int c = 1; c < cascade_nbr; ++c) { const float lambda = 0.8f; /* TODO : Parameter */ /* 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), near, far); + float exp_split = near * powf(far / near, (float)(c) / (float)cascade_nbr); if (is_persp) { - evsh->split[c-1] = LERP(lambda, linear_split, exp_split); + cascade_data->split[c-1] = LERP(lambda, linear_split, exp_split); } else { - evsh->split[c-1] = linear_split; + cascade_data->split[c-1] = linear_split; } /* NDC Space */ - float p[4] = {1.0f, 1.0f, evsh->split[c-1], 1.0f}; + float p[4] = {1.0f, 1.0f, cascade_data->split[c-1], 1.0f}; mul_m4_v4(viewprojmat, p); splits_ndc[c] = p[2]; @@ -535,8 +563,8 @@ static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE } /* 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 */ {-1.0f, -1.0f, splits_ndc[c], 1.0f}, @@ -567,12 +595,12 @@ static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE 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]; - 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]); @@ -580,27 +608,32 @@ static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE /* 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, - 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); - 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 = 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 + 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); } /* Used for checking if object is inside the shadow volume. */ @@ -732,7 +765,7 @@ void EEVEE_lights_update(EEVEE_SceneLayerData *sldata) } DRW_uniformbuffer_update(sldata->light_ubo, &linfo->light_data); - DRW_uniformbuffer_update(sldata->shadow_ubo, &linfo->shadow_cube_data); /* Update all data at once */ + DRW_uniformbuffer_update(sldata->shadow_ubo, &linfo->shadow_data); /* Update all data at once */ } /* this refresh lamps shadow buffers */ @@ -744,20 +777,23 @@ void EEVEE_draw_shadows(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl) float clear_col[4] = {FLT_MAX}; /* 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; + 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) { - EEVEE_ShadowCubeData *evscd = (EEVEE_ShadowCubeData *)led->storage; EEVEE_ShadowRender *srd = &linfo->shadow_render_data; srd->shadow_samples_ct = 32.0f; srd->shadow_inv_samples_ct = 1.0f / srd->shadow_samples_ct; srd->clip_near = la->clipsta; srd->clip_far = la->clipend; - srd->filter_size = la->soft * 0.0005f; + linfo->filter_size = la->soft * 0.0005f; copy_v3_v3(srd->position, ob->obmat[3]); for (int j = 0; j < 6; j++) { float tmp[4][4]; @@ -766,13 +802,13 @@ 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); - 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, srd); - DRW_framebuffer_texture_attach(sldata->shadow_target_fb, sldata->shadow_cube_target, 0, 0); DRW_framebuffer_bind(sldata->shadow_target_fb); DRW_framebuffer_clear(true, true, false, clear_col, 1.0f); + /* Render shadow cube */ DRW_draw_pass(psl->shadow_cube_pass); @@ -789,23 +825,44 @@ void EEVEE_draw_shadows(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl) DRW_framebuffer_texture_detach(sldata->shadow_cube_target); /* 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_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); + Lamp *la = (Lamp *)ob->data; + + EEVEE_ShadowCascadeData *evscd = (EEVEE_ShadowCascadeData *)led->storage; + EEVEE_ShadowRender *srd = &linfo->shadow_render_data; + + srd->shadow_samples_ct = 32.0f; + srd->shadow_inv_samples_ct = 1.0f / srd->shadow_samples_ct; + srd->clip_near = la->clipsta; + srd->clip_far = la->clipend; + 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_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); + + for (linfo->current_shadow_cascade = 0; + linfo->current_shadow_cascade < MAX_CASCADE_NUM; + ++linfo->current_shadow_cascade) + { + linfo->filter_size = la->soft * 0.0005f / (evscd->radius[linfo->current_shadow_cascade] * 0.05f); + + /* Push it to shadowmap array */ + 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); + } + } + + DRW_framebuffer_texture_detach(sldata->shadow_cube_target); } void EEVEE_lights_free(void) diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index 296fc7b02a0..8f2d2bc9ad7 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -57,6 +57,7 @@ "#define MAX_GRID " STRINGIFY(MAX_GRID) "\n" \ "#define MAX_PLANAR " STRINGIFY(MAX_PLANAR) "\n" \ "#define MAX_LIGHT " STRINGIFY(MAX_LIGHT) "\n" \ + "#define MAX_SHADOW " STRINGIFY(MAX_SHADOW) "\n" \ "#define MAX_SHADOW_CUBE " STRINGIFY(MAX_SHADOW_CUBE) "\n" \ "#define MAX_SHADOW_CASCADE " STRINGIFY(MAX_SHADOW_CASCADE) "\n" \ "#define MAX_CASCADE_NUM " STRINGIFY(MAX_CASCADE_NUM) "\n" \ diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 1e994c8d1fa..157f3076be4 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -35,9 +35,10 @@ extern struct DrawEngineType draw_engine_eevee_type; #define MAX_GRID 64 /* TODO : find size by dividing UBO max size by grid data size */ #define MAX_PLANAR 16 /* TODO : find size by dividing UBO max size by grid data size */ #define MAX_LIGHT 128 /* TODO : find size by dividing UBO max size by light data size */ -#define MAX_SHADOW_CUBE 42 /* TODO : Make this depends on GL_MAX_ARRAY_TEXTURE_LAYERS */ -#define MAX_SHADOW_CASCADE 8 #define MAX_CASCADE_NUM 4 +#define MAX_SHADOW 256 /* TODO : Make this depends on GL_MAX_ARRAY_TEXTURE_LAYERS */ +#define MAX_SHADOW_CASCADE 8 +#define MAX_SHADOW_CUBE (MAX_SHADOW - MAX_CASCADE_NUM * MAX_SHADOW_CASCADE) #define MAX_BLOOM_STEP 16 /* Only define one of these. */ @@ -211,14 +212,18 @@ typedef struct EEVEE_Light { float forwardvec[3], lamptype; } EEVEE_Light; -typedef struct EEVEE_ShadowCube { +typedef struct EEVEE_Shadow { float near, far, bias, exp; + float shadow_start, data_start, multi_shadow_count, pad; +} EEVEE_Shadow; + +typedef struct EEVEE_ShadowCube { + float position[3], pad; } EEVEE_ShadowCube; typedef struct EEVEE_ShadowCascade { float shadowmat[MAX_CASCADE_NUM][4][4]; /* World->Lamp->NDC->Tex : used for sampling the shadow map. */ float split[4]; - float near, far, bias, pad; } EEVEE_ShadowCascade; typedef struct EEVEE_ShadowRender { @@ -231,7 +236,6 @@ typedef struct EEVEE_ShadowRender { float clip_far; float shadow_samples_ct; float shadow_inv_samples_ct; - float filter_size; } EEVEE_ShadowRender; /* ************ VOLUME DATA ************ */ @@ -244,13 +248,15 @@ typedef struct EEVEE_VolumetricsInfo { /* ************ LIGHT DATA ************* */ typedef struct EEVEE_LampsInfo { int num_light, cache_num_light; - int num_cube, cache_num_cube; - int num_cascade, cache_num_cascade; - int num_shadow, cache_num_shadow; + int num_layer, cache_num_layer; + int gpu_cube_ct, gpu_cascade_ct, gpu_shadow_ct; + int cpu_cube_ct, cpu_cascade_ct; int update_flag; int shadow_size, shadow_method; bool shadow_high_bitdepth; int shadow_cube_target_size; + int current_shadow_cascade; + float filter_size; /* List of lights in the scene. */ /* XXX This is fragile, can get out of sync quickly. */ struct Object *light_ref[MAX_LIGHT]; @@ -259,6 +265,7 @@ typedef struct EEVEE_LampsInfo { /* UBO Storage : data used by UBO */ struct EEVEE_Light light_data[MAX_LIGHT]; struct EEVEE_ShadowRender shadow_render_data; + struct EEVEE_Shadow shadow_data[MAX_SHADOW]; struct EEVEE_ShadowCube shadow_cube_data[MAX_SHADOW_CUBE]; struct EEVEE_ShadowCascade shadow_cascade_data[MAX_SHADOW_CASCADE]; } EEVEE_LampsInfo; diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl index 97ee6bccafc..bb48a204ae5 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -25,7 +25,6 @@ layout(std140) uniform shadow_render_block { float farClip; float shadowSampleCount; float shadowInvSampleCount; - float shadowFilterSize; }; flat in int shFace; /* Shadow layer we are rendering to. */ @@ -47,6 +46,8 @@ uniform sampler2DArray planarDepth; #define viewCameraVec ((ProjectionMatrix[3][3] == 0.0) ? normalize(-viewPosition) : vec3(0.0, 0.0, 1.0)) /* ------- Structures -------- */ + +/* ------ Lights ----- */ struct LightData { vec4 position_influence; /* w : InfluenceRadius */ vec4 color_spec; /* w : Spec Intensity */ @@ -72,28 +73,34 @@ struct LightData { #define l_radius spotdata_radius_shadow.z #define l_shadowid spotdata_radius_shadow.w +/* ------ Shadows ----- */ +#ifndef MAX_CASCADE_NUM +#define MAX_CASCADE_NUM 4 +#endif -struct ShadowCubeData { +struct ShadowData { vec4 near_far_bias_exp; + vec4 shadow_data_start_end; }; -#ifndef MAX_CASCADE_NUM -#define MAX_CASCADE_NUM 4 -#endif +struct ShadowCubeData { + vec4 position; +}; struct ShadowCascadeData { mat4 shadowmat[MAX_CASCADE_NUM]; - /* arrays of float are not aligned so use vec4 */ vec4 split_distances; - vec4 near_far_bias_exp; }; /* convenience aliases */ -#define sh_cube_near near_far_bias_exp.x -#define sh_cube_far near_far_bias_exp.y -#define sh_cube_bias near_far_bias_exp.z -#define sh_cube_exp near_far_bias_exp.w -#define sh_cube_bleed near_far_bias_exp.w +#define sh_near near_far_bias_exp.x +#define sh_far near_far_bias_exp.y +#define sh_bias near_far_bias_exp.z +#define sh_exp near_far_bias_exp.w +#define sh_bleed near_far_bias_exp.w +#define sh_tex_start shadow_data_start_end.x +#define sh_data_start shadow_data_start_end.y +#define sh_multi_nbr shadow_data_start_end.z /* ------- Convenience functions --------- */ diff --git a/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl b/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl index a0b28a02dbc..6a263aee880 100644 --- a/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl @@ -2,6 +2,7 @@ uniform sampler2DArray shadowTexture; layout(std140) uniform shadow_block { + ShadowData shadows_data[MAX_SHADOW]; ShadowCubeData shadows_cube_data[MAX_SHADOW_CUBE]; ShadowCascadeData shadows_cascade_data[MAX_SHADOW_CASCADE]; }; @@ -17,91 +18,113 @@ layout(std140) uniform light_block { #define HEMI 3.0 #define AREA 4.0 -float shadow_cubemap(float shid, vec4 l_vector) +/* ----------------------------------------------------------- */ +/* ----------------------- Shadow tests ---------------------- */ +/* ----------------------------------------------------------- */ + +float shadow_test_esm(float z, float dist, float exponent) { - ShadowCubeData scd = shadows_cube_data[int(shid)]; + return saturate(exp(exponent * (z - dist))); +} - vec3 cubevec = -l_vector.xyz / l_vector.w; - float dist = l_vector.w; +float shadow_test_pcf(float z, float dist) +{ + return step(0, z - dist); +} -#if defined(SHADOW_VSM) - vec2 moments = texture_octahedron(shadowTexture, vec4(cubevec, shid)).rg; +float shadow_test_vsm(vec2 moments, float dist, float bias, float bleed_bias) +{ float p = 0.0; if (dist <= moments.x) p = 1.0; float variance = moments.y - (moments.x * moments.x); - variance = max(variance, scd.sh_cube_bias / 10.0); + variance = max(variance, bias / 10.0); float d = moments.x - dist; float p_max = variance / (variance + d * d); - // Now reduce light-bleeding by removing the [0, x] tail and linearly rescaling (x, 1] - p_max = clamp((p_max - scd.sh_cube_bleed) / (1.0 - scd.sh_cube_bleed), 0.0, 1.0); + /* Now reduce light-bleeding by removing the [0, x] tail and linearly rescaling (x, 1] */ + p_max = clamp((p_max - bleed_bias) / (1.0 - bleed_bias), 0.0, 1.0); - float vsm_test = max(p, p_max); - return vsm_test; + return max(p, p_max); +} -#elif defined(SHADOW_ESM) - float z = texture_octahedron(shadowTexture, vec4(cubevec, shid)).r; - float esm_test = saturate(exp(scd.sh_cube_exp * (z - (dist - scd.sh_cube_bias)))); - return esm_test; +/* ----------------------------------------------------------- */ +/* ----------------------- Shadow types ---------------------- */ +/* ----------------------------------------------------------- */ + +float shadow_cubemap(ShadowData sd, ShadowCubeData scd, float texid, vec3 W) +{ + vec3 cubevec = W - scd.position.xyz; + float dist = length(cubevec); + + cubevec /= dist; + +#if defined(SHADOW_VSM) + vec2 moments = texture_octahedron(shadowTexture, vec4(cubevec, texid)).rg; #else - float z = texture_octahedron(shadowTexture, vec4(cubevec, shid)).r; - float sh_test = step(0, z - (dist - scd.sh_cube_bias)); - return sh_test; + float z = texture_octahedron(shadowTexture, vec4(cubevec, texid)).r; +#endif + +#if defined(SHADOW_VSM) + return shadow_test_vsm(moments, dist, sd.sh_bias, sd.sh_bleed); +#elif defined(SHADOW_ESM) + return shadow_test_esm(z, dist - sd.sh_bias, sd.sh_exp); +#else + return shadow_test_pcf(z, dist - sd.sh_bias); #endif } -float shadow_cascade(float shid, vec3 W) +float shadow_cascade(ShadowData sd, ShadowCascadeData scd, float texid, vec3 W) { - return 1.0; - #if 0 - /* Shadow Cascade */ - shid -= MAX_SHADOW_CUBE; - ShadowCascadeData smd = shadows_cascade_data[int(shid)]; - /* Finding Cascade index */ - vec4 view_z = vec4(-dot(cameraPos - W, cameraForward)); - vec4 comp = step(view_z, smd.split_distances); + vec4 view_z = vec4(dot(W - cameraPos, cameraForward)); + vec4 comp = step(view_z, scd.split_distances); float cascade = dot(comp, comp); mat4 shadowmat; - float bias; /* Manual Unrolling of a loop for better performance. * Doing fetch directly with cascade index leads to * major performance impact. (0.27ms -> 10.0ms for 1 light) */ if (cascade == 0.0) { - shadowmat = smd.shadowmat[0]; - bias = smd.bias[0]; + shadowmat = scd.shadowmat[0]; } else if (cascade == 1.0) { - shadowmat = smd.shadowmat[1]; - bias = smd.bias[1]; + shadowmat = scd.shadowmat[1]; } else if (cascade == 2.0) { - shadowmat = smd.shadowmat[2]; - bias = smd.bias[2]; + shadowmat = scd.shadowmat[2]; } else { - shadowmat = smd.shadowmat[3]; - bias = smd.bias[3]; + shadowmat = scd.shadowmat[3]; } vec4 shpos = shadowmat * vec4(W, 1.0); - float dist = shpos.z - bias * shpos.w; - shpos.xyz /= shpos.w; + float dist = shpos.z * abs(sd.sh_far - sd.sh_near); /* Same factor as in get_cascade_world_distance(). */ - float z = texture(shadowTexture, vec4(shpos.xy, shid * float(MAX_CASCADE_NUM) + cascade, shpos.z)).r; - - float esm_test = saturate(exp(smd.sh_cube_exp * (z - dist))); +#if defined(SHADOW_VSM) + vec2 moments = texture(shadowTexture, vec3(shpos.xy, texid + cascade)).rg; +#else + float z = texture(shadowTexture, vec3(shpos.xy, texid + cascade)).r; +#endif - return esm_test; - #endif +#if defined(SHADOW_VSM) + return shadow_test_vsm(moments, dist, sd.sh_bias, sd.sh_bleed); +#elif defined(SHADOW_ESM) + return shadow_test_esm(z, dist - sd.sh_bias, sd.sh_exp); +#else + return shadow_test_pcf(z, dist - sd.sh_bias); +#endif } +/* ----------------------------------------------------------- */ +/* --------------------- Light Functions --------------------- */ +/* ----------------------------------------------------------- */ +#define MAX_MULTI_SHADOW 4 + float light_visibility(LightData ld, vec3 W, vec4 l_vector) { float vis = 1.0; @@ -125,11 +148,24 @@ float light_visibility(LightData ld, vec3 W, vec4 l_vector) #if !defined(VOLUMETRICS) || defined(VOLUME_SHADOW) /* shadowing */ - if (ld.l_shadowid >= MAX_SHADOW_CUBE) { - vis *= shadow_cascade(ld.l_shadowid, W); - } - else if (ld.l_shadowid >= 0.0) { - vis *= shadow_cubemap(ld.l_shadowid, l_vector); + if (ld.l_shadowid >= 0.0) { + ShadowData data = shadows_data[int(ld.l_shadowid)]; + if (ld.l_type == SUN) { + /* TODO : MSM */ + // for (int i = 0; i < MAX_MULTI_SHADOW; ++i) { + vis *= shadow_cascade( + data, shadows_cascade_data[int(data.sh_data_start)], + data.sh_tex_start, W); + // } + } + else { + /* TODO : MSM */ + // for (int i = 0; i < MAX_MULTI_SHADOW; ++i) { + vis *= shadow_cubemap( + data, shadows_cube_data[int(data.sh_data_start)], + data.sh_tex_start, W); + // } + } } #endif diff --git a/source/blender/draw/engines/eevee/shaders/shadow_geom.glsl b/source/blender/draw/engines/eevee/shaders/shadow_geom.glsl index 4eafef05082..508df7a6b37 100644 --- a/source/blender/draw/engines/eevee/shaders/shadow_geom.glsl +++ b/source/blender/draw/engines/eevee/shaders/shadow_geom.glsl @@ -9,7 +9,6 @@ layout(std140) uniform shadow_render_block { float farClip; float shadowSampleCount; float shadowInvSampleCount; - float shadowFilterSize; }; layout(triangles) in; diff --git a/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl b/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl index 61a26d999b7..5a9d0292ddf 100644 --- a/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl @@ -9,14 +9,15 @@ layout(std140) uniform shadow_render_block { float farClip; float shadowSampleCount; float shadowInvSampleCount; - float shadowFilterSize; }; #ifdef CSM uniform sampler2DArray shadowTexture; +uniform int cascadeId; #else uniform samplerCube shadowTexture; #endif +uniform float shadowFilterSize; out vec4 FragColor; @@ -52,6 +53,13 @@ float linear_depth(float z) return (nearClip * farClip) / (z * (nearClip - farClip) + farClip); } +#ifdef CSM +float get_cascade_world_distance(vec2 uvs) +{ + float zdepth = texture(shadowTexture, vec3(uvs, float(cascadeId))).r; + return zdepth * abs(farClip - nearClip); /* Same factor as in shadow_cascade(). */ +} +#else float get_cube_radial_distance(vec3 cubevec) { float zdepth = texture(shadowTexture, cubevec).r; @@ -60,6 +68,7 @@ float get_cube_radial_distance(vec3 cubevec) float cos_vec = max(cubevec.x, max(cubevec.y, cubevec.z)); return linear_zdepth / cos_vec; } +#endif /* Marco Salvi's GDC 2008 presentation about shadow maps pre-filtering techniques slide 24 */ float ln_space_prefilter(float w0, float x, float w1, float y) @@ -119,6 +128,55 @@ float wang_hash_noise(uint s) return fract(value); } +#ifdef CSM +void main() { + vec2 uvs = gl_FragCoord.xy * storedTexelSize; + + vec2 X, Y; + X.x = cos(wang_hash_noise(0u) * 3.1415 * 2.0); + X.y = sqrt(1.0 - X.x * X.x); + + Y = vec2(-X.y, X.x); + + X *= shadowFilterSize; + Y *= shadowFilterSize; + +/* TODO Can be optimized by groupping fetches + * and by converting to world distance beforehand. */ +#if defined(ESM) || defined(VSM) +#ifdef ESM + float accum = 0.0; + + /* Poisson disc blur in log space. */ + float depth1 = get_cascade_world_distance(uvs + X * poisson[0].x + Y * poisson[0].y); + float depth2 = get_cascade_world_distance(uvs + X * poisson[1].x + Y * poisson[1].y); + accum = ln_space_prefilter(INV_SAMPLE_NUM, depth1, INV_SAMPLE_NUM, depth2); + + for (int i = 2; i < SAMPLE_NUM; ++i) { + depth1 = get_cascade_world_distance(uvs + X * poisson[i].x + Y * poisson[i].y); + accum = ln_space_prefilter(1.0, accum, INV_SAMPLE_NUM, depth1); + } + + FragColor = vec4(accum); +#else /* VSM */ + vec2 accum = vec2(0.0); + + /* Poisson disc blur. */ + for (int i = 0; i < SAMPLE_NUM; ++i) { + float dist = get_cascade_world_distance(uvs + X * poisson[i].x + Y * poisson[i].y); + float dist_sqr = dist * dist; + accum += vec2(dist, dist_sqr); + } + + FragColor = accum.xyxy * shadowInvSampleCount; +#endif /* Prefilter */ +#else /* PCF (no prefilter) */ + FragColor = vec4(get_cascade_world_distance(uvs)); +#endif +} + +#else /* CUBEMAP */ + void main() { vec2 uvs = gl_FragCoord.xy * storedTexelSize; @@ -180,4 +238,5 @@ void main() { #else /* PCF (no prefilter) */ FragColor = vec4(get_cube_radial_distance(cubevec)); #endif -}
\ No newline at end of file +} +#endif
\ No newline at end of file |