Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release/scripts/startup/bl_ui/properties_data_lamp.py31
-rw-r--r--source/blender/draw/engines/eevee/eevee_lights.c257
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c1
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h23
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl31
-rw-r--r--source/blender/draw/engines/eevee/shaders/lamps_lib.glsl132
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_geom.glsl1
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl63
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