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:
authorClément Foucault <foucault.clem@gmail.com>2017-09-05 22:02:17 +0300
committerClément Foucault <foucault.clem@gmail.com>2017-09-10 04:09:45 +0300
commit716f7859a8f1412a656b51269ee82d46a2d8c7ae (patch)
treef1aedbf22fe5e091633acb6107e7f79a403f4806 /source/blender/draw
parent6c17348e9160e412e13e17cad996fe50c1ffcbe9 (diff)
Eevee: Add Cascaded Shadow Map support with filtering.
This brings some data structure changes. Shared shadow data are stored in ShadowData (in glsl) (aka EEVEE_Shadow in C). This structure contains the array indices of the first shadow element of this shadow "object". It also contains how many shadow to evaluate (to be used for Multiple shadow maps). The filtering is noisy and needs improvement.
Diffstat (limited to 'source/blender/draw')
-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
7 files changed, 337 insertions, 171 deletions
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