Eevee: Shadows: Filtering improvement.

- Replace poisson by concentric samples: Less variance. They are sorted by radius then by angle.
- Separate filtering into 2 blur. First blur is 3x3 box blur. Second is user dependant.
- Group fetches by group of 4.
This commit is contained in:
Clément Foucault 2017-09-08 20:21:57 +02:00
parent adeaf37e77
commit 9fdf094b85
7 changed files with 620 additions and 173 deletions

View File

@ -117,11 +117,11 @@ data_to_c_simple(engines/clay/shaders/clay_particle_strand_frag.glsl SRC)
data_to_c_simple(engines/clay/shaders/ssao_alchemy.glsl SRC)
data_to_c_simple(engines/clay/shaders/ssao_groundtruth.glsl SRC)
data_to_c_simple(engines/eevee/shaders/ambient_occlusion_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/default_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/default_world_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/background_vert.glsl SRC)
data_to_c_simple(engines/eevee/shaders/ambient_occlusion_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_minmaxz_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/concentric_samples_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lamps_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lightprobe_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl SRC)
@ -143,6 +143,7 @@ data_to_c_simple(engines/eevee/shaders/effect_dof_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_downsample_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_downsample_cube_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_gtao_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_minmaxz_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_motion_blur_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_ssr_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl SRC)
@ -154,6 +155,7 @@ data_to_c_simple(engines/eevee/shaders/shadow_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/shadow_geom.glsl SRC)
data_to_c_simple(engines/eevee/shaders/shadow_vert.glsl SRC)
data_to_c_simple(engines/eevee/shaders/shadow_store_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/shadow_copy_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/bsdf_lut_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/btdf_lut_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/bsdf_direct_lib.glsl SRC)

View File

@ -42,7 +42,9 @@ static void eevee_scene_layer_data_free(void *storage)
DRW_FRAMEBUFFER_FREE_SAFE(sldata->shadow_target_fb);
DRW_FRAMEBUFFER_FREE_SAFE(sldata->shadow_store_fb);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_target);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_blur);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_target);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_blur);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_pool);
BLI_freelistN(&sldata->shadow_casters);

View File

@ -25,6 +25,8 @@
#include "DRW_render.h"
#include "BLI_dynstr.h"
#include "BKE_object.h"
#include "eevee_engine.h"
@ -57,12 +59,16 @@ static struct {
struct GPUShader *shadow_sh;
struct GPUShader *shadow_store_cube_sh[SHADOW_METHOD_MAX];
struct GPUShader *shadow_store_cascade_sh[SHADOW_METHOD_MAX];
struct GPUShader *shadow_copy_cube_sh[SHADOW_METHOD_MAX];
struct GPUShader *shadow_copy_cascade_sh[SHADOW_METHOD_MAX];
} e_data = {NULL}; /* Engine data */
extern char datatoc_shadow_vert_glsl[];
extern char datatoc_shadow_geom_glsl[];
extern char datatoc_shadow_frag_glsl[];
extern char datatoc_shadow_store_frag_glsl[];
extern char datatoc_shadow_copy_frag_glsl[];
extern char datatoc_concentric_samples_lib_glsl[];
/* *********** FUNCTIONS *********** */
@ -80,13 +86,33 @@ void EEVEE_lights_init(EEVEE_SceneLayerData *sldata)
e_data.shadow_sh = DRW_shader_create(
datatoc_shadow_vert_glsl, datatoc_shadow_geom_glsl, datatoc_shadow_frag_glsl, NULL);
e_data.shadow_store_cube_sh[SHADOW_ESM] = DRW_shader_create_fullscreen(datatoc_shadow_store_frag_glsl, "#define ESM\n");
e_data.shadow_store_cascade_sh[SHADOW_ESM] = DRW_shader_create_fullscreen(datatoc_shadow_store_frag_glsl, "#define ESM\n"
"#define CSM\n");
DynStr *ds_frag = BLI_dynstr_new();
BLI_dynstr_append(ds_frag, datatoc_concentric_samples_lib_glsl);
BLI_dynstr_append(ds_frag, datatoc_shadow_store_frag_glsl);
char *store_shadow_shader_str = BLI_dynstr_get_cstring(ds_frag);
BLI_dynstr_free(ds_frag);
e_data.shadow_store_cube_sh[SHADOW_VSM] = DRW_shader_create_fullscreen(datatoc_shadow_store_frag_glsl, "#define VSM\n");
e_data.shadow_store_cascade_sh[SHADOW_VSM] = DRW_shader_create_fullscreen(datatoc_shadow_store_frag_glsl, "#define VSM\n"
"#define CSM\n");
e_data.shadow_store_cube_sh[SHADOW_ESM] = DRW_shader_create_fullscreen(store_shadow_shader_str, "#define ESM\n");
e_data.shadow_store_cascade_sh[SHADOW_ESM] = DRW_shader_create_fullscreen(store_shadow_shader_str, "#define ESM\n"
"#define CSM\n");
e_data.shadow_store_cube_sh[SHADOW_VSM] = DRW_shader_create_fullscreen(store_shadow_shader_str, "#define VSM\n");
e_data.shadow_store_cascade_sh[SHADOW_VSM] = DRW_shader_create_fullscreen(store_shadow_shader_str, "#define VSM\n"
"#define CSM\n");
MEM_freeN(store_shadow_shader_str);
e_data.shadow_copy_cube_sh[SHADOW_ESM] = DRW_shader_create_fullscreen(datatoc_shadow_copy_frag_glsl, "#define ESM\n"
"#define COPY\n");
e_data.shadow_copy_cascade_sh[SHADOW_ESM] = DRW_shader_create_fullscreen(datatoc_shadow_copy_frag_glsl, "#define ESM\n"
"#define COPY\n"
"#define CSM\n");
e_data.shadow_copy_cube_sh[SHADOW_VSM] = DRW_shader_create_fullscreen(datatoc_shadow_copy_frag_glsl, "#define VSM\n"
"#define COPY\n");
e_data.shadow_copy_cascade_sh[SHADOW_VSM] = DRW_shader_create_fullscreen(datatoc_shadow_copy_frag_glsl, "#define VSM\n"
"#define COPY\n"
"#define CSM\n");
}
if (!sldata->lamps) {
@ -153,13 +179,35 @@ void EEVEE_lights_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
psl->shadow_cascade_store_pass = DRW_pass_create("Shadow Cascade Storage Pass", DRW_STATE_WRITE_COLOR);
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_buffer(grp, "shadowTexture", &sldata->shadow_cascade_blur);
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);
}
{
psl->shadow_cube_copy_pass = DRW_pass_create("Shadow Copy Pass", DRW_STATE_WRITE_COLOR);
DRWShadingGroup *grp = DRW_shgroup_create(e_data.shadow_copy_cube_sh[linfo->shadow_method], psl->shadow_cube_copy_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_uniform_int(grp, "faceId", &linfo->current_shadow_face, 1);
DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
}
{
psl->shadow_cascade_copy_pass = DRW_pass_create("Shadow Cascade Copy Pass", DRW_STATE_WRITE_COLOR);
DRWShadingGroup *grp = DRW_shgroup_create(e_data.shadow_copy_cascade_sh[linfo->shadow_method], psl->shadow_cascade_copy_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_float(grp, "shadowFilterSize", &linfo->filter_size, 1);
DRW_shgroup_uniform_int(grp, "cascadeId", &linfo->current_shadow_cascade, 1);
DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
}
{
psl->shadow_cube_pass = DRW_pass_create("Shadow Cube Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
}
@ -321,12 +369,15 @@ void EEVEE_lights_cache_finish(EEVEE_SceneLayerData *sldata)
/* TODO render everything on the same 2d render target using clip planes and no Geom Shader. */
/* Cubemaps */
sldata->shadow_cube_target = DRW_texture_create_cube(linfo->shadow_cube_target_size, DRW_TEX_DEPTH_24, 0, NULL);
sldata->shadow_cube_blur = DRW_texture_create_cube(linfo->shadow_cube_target_size, shadow_pool_format, DRW_TEX_FILTER, NULL);
}
if (!sldata->shadow_cascade_target) {
/* CSM */
sldata->shadow_cascade_target = DRW_texture_create_2D_array(
linfo->shadow_size, linfo->shadow_size, MAX_CASCADE_NUM, DRW_TEX_DEPTH_24, 0, NULL);
sldata->shadow_cascade_blur = DRW_texture_create_2D_array(
linfo->shadow_size, linfo->shadow_size, MAX_CASCADE_NUM, shadow_pool_format, DRW_TEX_FILTER, NULL);
}
/* Initialize Textures Array first so DRW_framebuffer_init just bind them. */
@ -855,7 +906,6 @@ void EEVEE_draw_shadows(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
srd->shadow_inv_samples_ct = 1.0f / srd->shadow_samples_ct;
srd->clip_near = la->clipsta;
srd->clip_far = la->clipend;
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];
@ -874,7 +924,20 @@ void EEVEE_draw_shadows(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
/* Render shadow cube */
DRW_draw_pass(psl->shadow_cube_pass);
for (linfo->current_shadow_face = 0;
linfo->current_shadow_face < 6;
linfo->current_shadow_face++)
{
/* Copy using a small 3x3 box filter */
linfo->filter_size = (la->soft > 0.00001f) ? 1.0f : 0.0f;
DRW_framebuffer_cubeface_attach(sldata->shadow_store_fb, sldata->shadow_cube_blur, 0, linfo->current_shadow_face, 0);
DRW_framebuffer_bind(sldata->shadow_store_fb);
DRW_draw_pass(psl->shadow_cube_copy_pass);
DRW_framebuffer_texture_detach(sldata->shadow_cube_blur);
}
/* Push it to shadowmap array */
linfo->filter_size = la->soft * 0.0005f;
DRW_framebuffer_texture_layer_attach(sldata->shadow_store_fb, sldata->shadow_pool, 0, i, 0);
DRW_framebuffer_bind(sldata->shadow_store_fb);
DRW_draw_pass(psl->shadow_cube_store_pass);
@ -914,9 +977,15 @@ void EEVEE_draw_shadows(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
linfo->current_shadow_cascade < la->cascade_count;
++linfo->current_shadow_cascade)
{
linfo->filter_size = la->soft * 0.0005f / (evscd->radius[linfo->current_shadow_cascade] * 0.05f);
/* Copy using a small 3x3 box filter */
linfo->filter_size = (la->soft > 0.00001f) ? 1.0f : 0.0f;
DRW_framebuffer_texture_layer_attach(sldata->shadow_store_fb, sldata->shadow_cascade_blur, 0, linfo->current_shadow_cascade, 0);
DRW_framebuffer_bind(sldata->shadow_store_fb);
DRW_draw_pass(psl->shadow_cascade_copy_pass);
DRW_framebuffer_texture_detach(sldata->shadow_cascade_blur);
/* Push it to shadowmap array */
/* Push it to shadowmap array and blur more */
linfo->filter_size = la->soft * 0.0005f / (evscd->radius[linfo->current_shadow_cascade] * 0.05f);
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);
@ -924,7 +993,7 @@ void EEVEE_draw_shadows(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
}
}
DRW_framebuffer_texture_detach(sldata->shadow_cube_target);
DRW_framebuffer_texture_detach(sldata->shadow_cascade_target);
}
void EEVEE_lights_free(void)
@ -933,5 +1002,7 @@ void EEVEE_lights_free(void)
for (int i = 0; i < SHADOW_METHOD_MAX; ++i) {
DRW_SHADER_FREE_SAFE(e_data.shadow_store_cube_sh[i]);
DRW_SHADER_FREE_SAFE(e_data.shadow_store_cascade_sh[i]);
DRW_SHADER_FREE_SAFE(e_data.shadow_copy_cube_sh[i]);
DRW_SHADER_FREE_SAFE(e_data.shadow_copy_cascade_sh[i]);
}
}

View File

@ -91,8 +91,10 @@ typedef struct EEVEE_PassList {
/* Shadows */
struct DRWPass *shadow_pass;
struct DRWPass *shadow_cube_pass;
struct DRWPass *shadow_cube_copy_pass;
struct DRWPass *shadow_cube_store_pass;
struct DRWPass *shadow_cascade_pass;
struct DRWPass *shadow_cascade_copy_pass;
struct DRWPass *shadow_cascade_store_pass;
/* Probes */
@ -257,6 +259,7 @@ typedef struct EEVEE_LampsInfo {
bool shadow_high_bitdepth;
int shadow_cube_target_size;
int current_shadow_cascade;
int current_shadow_face;
float filter_size;
/* List of lights in the scene. */
/* XXX This is fragile, can get out of sync quickly. */
@ -424,7 +427,9 @@ typedef struct EEVEE_SceneLayerData {
struct GPUFrameBuffer *shadow_store_fb;
struct GPUTexture *shadow_cube_target;
struct GPUTexture *shadow_cube_blur;
struct GPUTexture *shadow_cascade_target;
struct GPUTexture *shadow_cascade_blur;
struct GPUTexture *shadow_pool;
struct ListBase shadow_casters; /* Shadow casters gathered during cache iteration */

View File

@ -0,0 +1,267 @@
/* Precomputed table of concentric samples.
* Generated using this algorithm http://l2program.co.uk/900/concentric-disk-sampling
* Sorted by radius then by rotation angle.
* This way it's better for cache usage and for
* easily restricting to a certain number of
* sample while still having a circular kernel. */
#define CONCENTRIC_SAMPLE_NUM 256
const vec2 concentric[CONCENTRIC_SAMPLE_NUM] =
vec2[CONCENTRIC_SAMPLE_NUM](
vec2(0.0441941738242, 0.0441941738242),
vec2(-0.0441941738242, -0.0441941738242),
vec2(-0.0441941738242, 0.0441941738242),
vec2(0.0441941738242, -0.0441941738242),
vec2(0.181111092429, 0.0485285709567),
vec2(0.132582521472, 0.132582521472),
vec2(-0.181111092429, 0.0485285709567),
vec2(0.0485285709567, 0.181111092429),
vec2(-0.181111092429, -0.0485285709567),
vec2(-0.0485285709567, 0.181111092429),
vec2(-0.132582521472, -0.132582521472),
vec2(-0.132582521472, 0.132582521472),
vec2(-0.0485285709567, -0.181111092429),
vec2(0.0485285709567, -0.181111092429),
vec2(0.132582521472, -0.132582521472),
vec2(0.181111092429, -0.0485285709567),
vec2(0.308652606436, 0.0488857703251),
vec2(0.278439538809, 0.141872031169),
vec2(0.220970869121, 0.220970869121),
vec2(-0.278439538809, 0.141872031169),
vec2(0.141872031169, 0.278439538809),
vec2(-0.308652606436, 0.0488857703251),
vec2(0.0488857703251, 0.308652606436),
vec2(-0.308652606436, -0.0488857703251),
vec2(-0.0488857703251, 0.308652606436),
vec2(-0.278439538809, -0.141872031169),
vec2(-0.141872031169, 0.278439538809),
vec2(-0.220970869121, -0.220970869121),
vec2(-0.220970869121, 0.220970869121),
vec2(-0.141872031169, -0.278439538809),
vec2(-0.0488857703251, -0.308652606436),
vec2(0.0488857703251, -0.308652606436),
vec2(0.141872031169, -0.278439538809),
vec2(0.220970869121, -0.220970869121),
vec2(0.278439538809, -0.141872031169),
vec2(0.308652606436, -0.0488857703251),
vec2(0.434749091828, 0.0489844582952),
vec2(0.41294895701, 0.144497089605),
vec2(0.370441837162, 0.232764033475),
vec2(0.309359216769, 0.309359216769),
vec2(-0.370441837162, 0.232764033475),
vec2(0.232764033475, 0.370441837162),
vec2(-0.41294895701, 0.144497089605),
vec2(0.144497089605, 0.41294895701),
vec2(-0.434749091828, 0.0489844582952),
vec2(0.0489844582952, 0.434749091828),
vec2(-0.434749091828, -0.0489844582952),
vec2(-0.0489844582952, 0.434749091828),
vec2(-0.41294895701, -0.144497089605),
vec2(-0.144497089605, 0.41294895701),
vec2(-0.370441837162, -0.232764033475),
vec2(-0.232764033475, 0.370441837162),
vec2(-0.309359216769, -0.309359216769),
vec2(-0.309359216769, 0.309359216769),
vec2(-0.232764033475, -0.370441837162),
vec2(-0.144497089605, -0.41294895701),
vec2(-0.0489844582952, -0.434749091828),
vec2(0.0489844582952, -0.434749091828),
vec2(0.144497089605, -0.41294895701),
vec2(0.232764033475, -0.370441837162),
vec2(0.309359216769, -0.309359216769),
vec2(0.370441837162, -0.232764033475),
vec2(0.41294895701, -0.144497089605),
vec2(0.434749091828, -0.0489844582952),
vec2(0.560359517677, 0.0490251052956),
vec2(0.543333277288, 0.14558571287),
vec2(0.509798130208, 0.237722772229),
vec2(0.460773024913, 0.322636745447),
vec2(0.397747564417, 0.397747564417),
vec2(-0.460773024913, 0.322636745447),
vec2(0.322636745447, 0.460773024913),
vec2(-0.509798130208, 0.237722772229),
vec2(0.237722772229, 0.509798130208),
vec2(-0.543333277288, 0.14558571287),
vec2(0.14558571287, 0.543333277288),
vec2(-0.560359517677, 0.0490251052956),
vec2(0.0490251052956, 0.560359517677),
vec2(-0.560359517677, -0.0490251052956),
vec2(-0.0490251052956, 0.560359517677),
vec2(-0.543333277288, -0.14558571287),
vec2(-0.14558571287, 0.543333277288),
vec2(-0.509798130208, -0.237722772229),
vec2(-0.237722772229, 0.509798130208),
vec2(-0.460773024913, -0.322636745447),
vec2(-0.322636745447, 0.460773024913),
vec2(-0.397747564417, -0.397747564417),
vec2(-0.397747564417, 0.397747564417),
vec2(-0.322636745447, -0.460773024913),
vec2(-0.237722772229, -0.509798130208),
vec2(-0.14558571287, -0.543333277288),
vec2(-0.0490251052956, -0.560359517677),
vec2(0.0490251052956, -0.560359517677),
vec2(0.14558571287, -0.543333277288),
vec2(0.237722772229, -0.509798130208),
vec2(0.322636745447, -0.460773024913),
vec2(0.397747564417, -0.397747564417),
vec2(0.460773024913, -0.322636745447),
vec2(0.509798130208, -0.237722772229),
vec2(0.543333277288, -0.14558571287),
vec2(0.560359517677, -0.0490251052956),
vec2(0.685748328795, 0.0490456884495),
vec2(0.671788470355, 0.146138636568),
vec2(0.644152935937, 0.240256623474),
vec2(0.603404305327, 0.32948367837),
vec2(0.550372103135, 0.412003395727),
vec2(0.486135912066, 0.486135912066),
vec2(-0.550372103135, 0.412003395727),
vec2(0.412003395727, 0.550372103135),
vec2(-0.603404305327, 0.32948367837),
vec2(0.32948367837, 0.603404305327),
vec2(-0.644152935937, 0.240256623474),
vec2(0.240256623474, 0.644152935937),
vec2(-0.671788470355, 0.146138636568),
vec2(0.146138636568, 0.671788470355),
vec2(-0.685748328795, 0.0490456884495),
vec2(0.0490456884495, 0.685748328795),
vec2(-0.685748328795, -0.0490456884495),
vec2(-0.0490456884495, 0.685748328795),
vec2(-0.671788470355, -0.146138636568),
vec2(-0.146138636568, 0.671788470355),
vec2(-0.644152935937, -0.240256623474),
vec2(-0.240256623474, 0.644152935937),
vec2(-0.603404305327, -0.32948367837),
vec2(-0.32948367837, 0.603404305327),
vec2(-0.550372103135, -0.412003395727),
vec2(-0.412003395727, 0.550372103135),
vec2(-0.486135912066, -0.486135912066),
vec2(-0.486135912066, 0.486135912066),
vec2(-0.412003395727, -0.550372103135),
vec2(-0.32948367837, -0.603404305327),
vec2(-0.240256623474, -0.644152935937),
vec2(-0.146138636568, -0.671788470355),
vec2(-0.0490456884495, -0.685748328795),
vec2(0.0490456884495, -0.685748328795),
vec2(0.146138636568, -0.671788470355),
vec2(0.240256623474, -0.644152935937),
vec2(0.32948367837, -0.603404305327),
vec2(0.412003395727, -0.550372103135),
vec2(0.486135912066, -0.486135912066),
vec2(0.550372103135, -0.412003395727),
vec2(0.603404305327, -0.32948367837),
vec2(0.644152935937, -0.240256623474),
vec2(0.671788470355, -0.146138636568),
vec2(0.685748328795, -0.0490456884495),
vec2(0.811017637806, 0.0490575291556),
vec2(0.799191174395, 0.146457218224),
vec2(0.775710704038, 0.241721231257),
vec2(0.740918624869, 0.33346040443),
vec2(0.695322283745, 0.420336974019),
vec2(0.639586577995, 0.501084084011),
vec2(0.574524259714, 0.574524259714),
vec2(-0.639586577995, 0.501084084011),
vec2(0.501084084011, 0.639586577995),
vec2(-0.695322283745, 0.420336974019),
vec2(0.420336974019, 0.695322283745),
vec2(-0.740918624869, 0.33346040443),
vec2(0.33346040443, 0.740918624869),
vec2(-0.775710704038, 0.241721231257),
vec2(0.241721231257, 0.775710704038),
vec2(-0.799191174395, 0.146457218224),
vec2(0.146457218224, 0.799191174395),
vec2(-0.811017637806, 0.0490575291556),
vec2(0.0490575291556, 0.811017637806),
vec2(-0.811017637806, -0.0490575291556),
vec2(-0.0490575291556, 0.811017637806),
vec2(-0.799191174395, -0.146457218224),
vec2(-0.146457218224, 0.799191174395),
vec2(-0.775710704038, -0.241721231257),
vec2(-0.241721231257, 0.775710704038),
vec2(-0.740918624869, -0.33346040443),
vec2(-0.33346040443, 0.740918624869),
vec2(-0.695322283745, -0.420336974019),
vec2(-0.420336974019, 0.695322283745),
vec2(-0.639586577995, -0.501084084011),
vec2(-0.501084084011, 0.639586577995),
vec2(-0.574524259714, -0.574524259714),
vec2(-0.574524259714, 0.574524259714),
vec2(-0.501084084011, -0.639586577995),
vec2(-0.420336974019, -0.695322283745),
vec2(-0.33346040443, -0.740918624869),
vec2(-0.241721231257, -0.775710704038),
vec2(-0.146457218224, -0.799191174395),
vec2(-0.0490575291556, -0.811017637806),
vec2(0.0490575291556, -0.811017637806),
vec2(0.146457218224, -0.799191174395),
vec2(0.241721231257, -0.775710704038),
vec2(0.33346040443, -0.740918624869),
vec2(0.420336974019, -0.695322283745),
vec2(0.501084084011, -0.639586577995),
vec2(0.574524259714, -0.574524259714),
vec2(0.639586577995, -0.501084084011),
vec2(0.695322283745, -0.420336974019),
vec2(0.740918624869, -0.33346040443),
vec2(0.775710704038, -0.241721231257),
vec2(0.799191174395, -0.146457218224),
vec2(0.811017637806, -0.0490575291556),
vec2(0.936215188832, 0.0490649589778),
vec2(0.925957819308, 0.146657310975),
vec2(0.905555462146, 0.242642854784),
vec2(0.875231649841, 0.335969952699),
vec2(0.835318616427, 0.425616093506),
vec2(0.786253657449, 0.510599095327),
vec2(0.728574338866, 0.589987866609),
vec2(0.662912607362, 0.662912607362),
vec2(-0.728574338866, 0.589987866609),
vec2(0.589987866609, 0.728574338866),
vec2(-0.786253657449, 0.510599095327),
vec2(0.510599095327, 0.786253657449),
vec2(-0.835318616427, 0.425616093506),
vec2(0.425616093506, 0.835318616427),
vec2(-0.875231649841, 0.335969952699),
vec2(0.335969952699, 0.875231649841),
vec2(-0.905555462146, 0.242642854784),
vec2(0.242642854784, 0.905555462146),
vec2(-0.925957819308, 0.146657310975),
vec2(0.146657310975, 0.925957819308),
vec2(-0.936215188832, 0.0490649589778),
vec2(0.0490649589778, 0.936215188832),
vec2(-0.936215188832, -0.0490649589778),
vec2(-0.0490649589778, 0.936215188832),
vec2(-0.925957819308, -0.146657310975),
vec2(-0.146657310975, 0.925957819308),
vec2(-0.905555462146, -0.242642854784),
vec2(-0.242642854784, 0.905555462146),
vec2(-0.875231649841, -0.335969952699),
vec2(-0.335969952699, 0.875231649841),
vec2(-0.835318616427, -0.425616093506),
vec2(-0.425616093506, 0.835318616427),
vec2(-0.786253657449, -0.510599095327),
vec2(-0.510599095327, 0.786253657449),
vec2(-0.728574338866, -0.589987866609),
vec2(-0.589987866609, 0.728574338866),
vec2(-0.662912607362, -0.662912607362),
vec2(-0.662912607362, 0.662912607362),
vec2(-0.589987866609, -0.728574338866),
vec2(-0.510599095327, -0.786253657449),
vec2(-0.425616093506, -0.835318616427),
vec2(-0.335969952699, -0.875231649841),
vec2(-0.242642854784, -0.905555462146),
vec2(-0.146657310975, -0.925957819308),
vec2(-0.0490649589778, -0.936215188832),
vec2(0.0490649589778, -0.936215188832),
vec2(0.146657310975, -0.925957819308),
vec2(0.242642854784, -0.905555462146),
vec2(0.335969952699, -0.875231649841),
vec2(0.425616093506, -0.835318616427),
vec2(0.510599095327, -0.786253657449),
vec2(0.589987866609, -0.728574338866),
vec2(0.662912607362, -0.662912607362),
vec2(0.728574338866, -0.589987866609),
vec2(0.786253657449, -0.510599095327),
vec2(0.835318616427, -0.425616093506),
vec2(0.875231649841, -0.335969952699),
vec2(0.905555462146, -0.242642854784),
vec2(0.925957819308, -0.146657310975),
vec2(0.936215188832, -0.0490649589778)
);

View File

@ -0,0 +1,200 @@
/* Copy the depth only shadowmap into another texture while converting
* to linear depth (or other storage method) and doing a 3x3 box filter. */
layout(std140) uniform shadow_render_block {
mat4 ShadowMatrix[6];
mat4 FaceViewMatrix[6];
vec4 lampPosition;
float cubeTexelSize;
float storedTexelSize;
float nearClip;
float farClip;
float shadowSampleCount;
float shadowInvSampleCount;
};
#ifdef CSM
uniform sampler2DArray shadowTexture;
uniform int cascadeId;
#else
uniform samplerCube shadowTexture;
uniform vec3 cubeFaceVec[3];
#endif
uniform float shadowFilterSize;
out vec4 FragColor;
float linear_depth(float z)
{
return (nearClip * farClip) / (z * (nearClip - farClip) + farClip);
}
vec4 linear_depth(vec4 z)
{
return (nearClip * farClip) / (z * (nearClip - farClip) + farClip);
}
#ifdef CSM
vec4 get_world_distance(vec4 depths, vec3 cos[4])
{
/* Background case */
vec4 is_background = step(vec4(0.99999), depths);
depths *= abs(farClip - nearClip); /* Same factor as in shadow_cascade(). */
depths += 1e1 * is_background;
return depths;
}
float get_world_distance(float depth, vec3 cos)
{
/* Background case */
float is_background = step(0.9999, depth);
depth *= abs(farClip - nearClip); /* Same factor as in shadow_cascade(). */
depth += 1e1 * is_background;
return depth;
}
#else /* CUBEMAP */
vec4 get_world_distance(vec4 depths, vec3 cos[4])
{
vec4 is_background = step(vec4(1.0), depths);
depths = linear_depth(depths);
depths += vec4(1e16) * is_background;
cos[0] = normalize(abs(cos[0]));
cos[1] = normalize(abs(cos[1]));
cos[2] = normalize(abs(cos[2]));
cos[3] = normalize(abs(cos[3]));
vec4 cos_vec;
cos_vec.x = max(cos[0].x, max(cos[0].y, cos[0].z));
cos_vec.y = max(cos[1].x, max(cos[1].y, cos[1].z));
cos_vec.z = max(cos[2].x, max(cos[2].y, cos[2].z));
cos_vec.w = max(cos[3].x, max(cos[3].y, cos[3].z));
return depths / cos_vec;
}
float get_world_distance(float depth, vec3 cos)
{
float is_background = step(1.0, depth);
depth = linear_depth(depth);
depth += 1e16 * is_background;
cos = normalize(abs(cos));
float cos_vec = max(cos.x, max(cos.y, cos.z));
return depth / 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)
{
return x + log(w0 + w1 * exp(y - x));
}
#define SAMPLE_WEIGHT 0.11111
#ifdef ESM
void filter(vec4 depths, inout float accum)
{
accum = ln_space_prefilter(1.0, accum, SAMPLE_WEIGHT, depths.x);
accum = ln_space_prefilter(1.0, accum, SAMPLE_WEIGHT, depths.y);
accum = ln_space_prefilter(1.0, accum, SAMPLE_WEIGHT, depths.z);
accum = ln_space_prefilter(1.0, accum, SAMPLE_WEIGHT, depths.w);
}
#else /* VSM */
void filter(vec4 depths, inout vec2 accum)
{
vec4 depths_sqr = depths * depths;
accum += vec2(dot(vec4(1.0), depths), dot(vec4(1.0), depths_sqr)) * SAMPLE_WEIGHT;
}
#endif
#ifdef CSM
vec3 get_texco(vec2 uvs, vec2 ofs)
{
return vec3(uvs + ofs, float(cascadeId));
}
#else /* CUBEMAP */
const vec3 minorAxisX[6] = vec3[6](
vec3(0.0f, 0.0f, -1.0f),
vec3(0.0f, 0.0f, 1.0f),
vec3(1.0f, 0.0f, 0.0f),
vec3(1.0f, 0.0f, 0.0f),
vec3(1.0f, 0.0f, 0.0f),
vec3(-1.0f, 0.0f, 0.0f)
);
const vec3 minorAxisY[6] = vec3[6](
vec3(0.0f, -1.0f, 0.0f),
vec3(0.0f, -1.0f, 0.0f),
vec3(0.0f, 0.0f, -1.0f),
vec3(0.0f, 0.0f, 1.0f),
vec3(0.0f, -1.0f, 0.0f),
vec3(0.0f, -1.0f, 0.0f)
);
const vec3 majorAxis[6] = vec3[6](
vec3(-1.0f, 0.0f, 0.0f),
vec3(1.0f, 0.0f, 0.0f),
vec3(0.0f, 1.0f, 0.0f),
vec3(0.0f, -1.0f, 0.0f),
vec3(0.0f, 0.0f, -1.0f),
vec3(0.0f, 0.0f, 1.0f)
);
vec3 get_texco(vec2 uvs, vec2 ofs)
{
uvs += ofs;
return majorAxis[0] + uvs.x * minorAxisX[1] + uvs.y * minorAxisY[2];
}
#endif
void main() {
/* Copy the depth only shadowmap into another texture while converting
* to linear depth and do a 3x3 box blur. */
#ifdef CSM
vec2 uvs = gl_FragCoord.xy * storedTexelSize;
#else /* CUBEMAP */
vec2 uvs = gl_FragCoord.xy * cubeTexelSize;
#endif
/* Center texel */
vec3 co = get_texco(uvs, vec2(0.0));
float depth = texture(shadowTexture, co).r;
depth = get_world_distance(depth, co);
#ifdef ESM
float accum = ln_space_prefilter(0.0, 0.0, SAMPLE_WEIGHT, depth);
#else /* VSM */
vec2 accum = vec2(depth, depth * depth) * SAMPLE_WEIGHT;
#endif
#ifdef CSM
vec3 ofs = storedTexelSize * vec3(1.0, 0.0, -1.0) * shadowFilterSize;
#else /* CUBEMAP */
vec3 ofs = cubeTexelSize * vec3(1.0, 0.0, -1.0) * shadowFilterSize;
#endif
vec3 cos[4];
cos[0] = get_texco(uvs, ofs.zz);
cos[1] = get_texco(uvs, ofs.yz);
cos[2] = get_texco(uvs, ofs.xz);
cos[3] = get_texco(uvs, ofs.zy);
vec4 depths;
depths.x = texture(shadowTexture, cos[0]).r;
depths.y = texture(shadowTexture, cos[1]).r;
depths.z = texture(shadowTexture, cos[2]).r;
depths.w = texture(shadowTexture, cos[3]).r;
depths = get_world_distance(depths, cos);
filter(depths, accum);
cos[0] = get_texco(uvs, ofs.xy);
cos[1] = get_texco(uvs, ofs.zx);
cos[2] = get_texco(uvs, ofs.yx);
cos[3] = get_texco(uvs, ofs.xx);
depths.x = texture(shadowTexture, cos[0]).r;
depths.y = texture(shadowTexture, cos[1]).r;
depths.z = texture(shadowTexture, cos[2]).r;
depths.w = texture(shadowTexture, cos[3]).r;
depths = get_world_distance(depths, cos);
filter(depths, accum);
FragColor = vec2(accum).xyxy;
}

View File

@ -35,212 +35,112 @@ vec3 octahedral_to_cubemap_proj(vec2 co)
return v;
}
void make_orthonormal_basis(vec3 N, float rot, out vec3 T, out vec3 B)
void make_orthonormal_basis(vec3 N, out vec3 T, out vec3 B)
{
vec3 UpVector = (abs(N.z) < 0.999) ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
vec3 nT = normalize(cross(UpVector, N));
vec3 nB = cross(N, nT);
/* Rotate tangent space */
float angle = rot * 3.1415 * 2.0;
vec2 dir = vec2(cos(angle), sin(angle));
T = dir.x * nT + dir.y * nB;
B = -dir.y * nT + dir.x * nB;
}
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;
if (zdepth == 1.0) {
/* Background case */
return 1e16;
}
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;
float linear_zdepth = linear_depth(zdepth);
cubevec = normalize(abs(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)
{
return x + log(w0 + w1 * exp(y - x));
}
const int SAMPLE_NUM = 32;
const float INV_SAMPLE_NUM = 1.0 / float(SAMPLE_NUM);
const vec2 poisson[32] = vec2[32](
vec2(-0.31889129888, 0.945170187163),
vec2(0.0291070069348, 0.993645382622),
vec2(0.453968568675, 0.882119488776),
vec2(-0.59142811398, 0.775098624552),
vec2(0.0672147039953, 0.677233646792),
vec2(0.632546991242, 0.60080388224),
vec2(-0.846282545004, 0.478266943968),
vec2(-0.304563967348, 0.550414788876),
vec2(0.343951542639, 0.482122717676),
vec2(0.903371461134, 0.419225918868),
vec2(-0.566433506581, 0.326544955645),
vec2(-0.0174468029403, 0.345927250589),
vec2(-0.970838848328, 0.131541221423),
vec2(-0.317404956404, 0.102175571059),
vec2(0.309107085158, 0.136502232088),
vec2(0.67009683403, 0.198922062526),
vec2(-0.62544683989, -0.0237682928336),
vec2(0.0, 0.0),
vec2(0.260779995092, -0.192490308513),
vec2(0.555635503398, -0.0918935341973),
vec2(0.989587880961, -0.03629312269),
vec2(-0.93440130633, -0.213478602005),
vec2(-0.615716455579, -0.335329659339),
vec2(0.813589336772, -0.292544036149),
vec2(-0.821106257666, -0.568279197395),
vec2(-0.298092257627, -0.457929494012),
vec2(0.263233114326, -0.515552889911),
vec2(-0.0311374378304, -0.643310533036),
vec2(0.785838482787, -0.615972502555),
vec2(-0.444079211316, -0.836548440017),
vec2(-0.0253421088433, -0.96112294526),
vec2(0.350411908643, -0.89783206142)
);
float wang_hash_noise(uint s)
vec4 ln_space_prefilter(float w0, vec4 x, float w1, vec4 y)
{
uint seed = (uint(gl_FragCoord.x) * 1664525u + uint(gl_FragCoord.y)) + s;
seed = (seed ^ 61u) ^ (seed >> 16u);
seed *= 9u;
seed = seed ^ (seed >> 4u);
seed *= 0x27d4eb2du;
seed = seed ^ (seed >> 15u);
float value = float(seed);
value *= 1.0 / 4294967296.0;
return fract(value);
return x + log(w0 + w1 * exp(y - x));
}
/* globals */
vec3 T, B;
#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
vec3 get_texco(vec3 cos, vec2 ofs)
{
cos.xy += ofs * shadowFilterSize;
return cos;
}
#else /* CUBEMAP */
vec3 get_texco(vec3 cos, vec2 ofs)
{
return cos + ofs.x * T + ofs.y * B;
}
#endif
const float INV_SAMPLE_NUM = 1.0 / float(CONCENTRIC_SAMPLE_NUM);
void main() {
vec2 uvs = gl_FragCoord.xy * storedTexelSize;
vec3 cos;
cos.xy = gl_FragCoord.xy * storedTexelSize;
#ifdef CSM
cos.z = float(cascadeId);
#else /* CUBEMAP */
/* add a 2 pixel border to ensure filtering is correct */
uvs.xy *= 1.0 + storedTexelSize * 2.0;
uvs.xy -= storedTexelSize;
cos.xy *= 1.0 + storedTexelSize * 2.0;
cos.xy -= storedTexelSize;
float pattern = 1.0;
/* edge mirroring : only mirror if directly adjacent
* (not diagonally adjacent) */
vec2 m = abs(uvs - 0.5) + 0.5;
vec2 m = abs(cos.xy - 0.5) + 0.5;
vec2 f = floor(m);
if (f.x - f.y != 0.0) {
uvs.xy = 1.0 - uvs.xy;
cos.xy = 1.0 - cos.xy;
}
/* clamp to [0-1] */
uvs.xy = fract(uvs.xy);
cos.xy = fract(cos.xy);
/* get cubemap vector */
vec3 cubevec = normalize(octahedral_to_cubemap_proj(uvs.xy));
/* TODO Can be optimized by groupping fetches
* and by converting to radial distance beforehand. */
#if defined(ESM) || defined(VSM)
vec3 T, B;
make_orthonormal_basis(cubevec, wang_hash_noise(0u), T, B);
cos = normalize(octahedral_to_cubemap_proj(cos.xy));
make_orthonormal_basis(cos, T, B);
T *= shadowFilterSize;
B *= shadowFilterSize;
#endif
#ifdef ESM
float accum = 0.0;
vec4 accum = vec4(0.0);
/* Poisson disc blur in log space. */
float depth1 = get_cube_radial_distance(cubevec + poisson[0].x * T + poisson[0].y * B);
float depth2 = get_cube_radial_distance(cubevec + poisson[1].x * T + poisson[1].y * B);
accum = ln_space_prefilter(INV_SAMPLE_NUM, depth1, INV_SAMPLE_NUM, depth2);
/* disc blur in log space. */
vec4 depths;
depths.x = texture(shadowTexture, get_texco(cos, concentric[0])).r;
depths.y = texture(shadowTexture, get_texco(cos, concentric[1])).r;
depths.z = texture(shadowTexture, get_texco(cos, concentric[2])).r;
depths.w = texture(shadowTexture, get_texco(cos, concentric[3])).r;
accum = ln_space_prefilter(0.0, accum, INV_SAMPLE_NUM, depths);
for (int i = 2; i < SAMPLE_NUM; ++i) {
depth1 = get_cube_radial_distance(cubevec + poisson[i].x * T + poisson[i].y * B);
accum = ln_space_prefilter(1.0, accum, INV_SAMPLE_NUM, depth1);
for (int i = 4; i < CONCENTRIC_SAMPLE_NUM; i += 4) {
depths.x = texture(shadowTexture, get_texco(cos, concentric[i+0])).r;
depths.y = texture(shadowTexture, get_texco(cos, concentric[i+1])).r;
depths.z = texture(shadowTexture, get_texco(cos, concentric[i+2])).r;
depths.w = texture(shadowTexture, get_texco(cos, concentric[i+3])).r;
accum = ln_space_prefilter(1.0, accum, INV_SAMPLE_NUM, depths);
}
FragColor = vec4(accum);
accum.x = ln_space_prefilter(1.0, accum.x, 1.0, accum.y);
accum.x = ln_space_prefilter(1.0, accum.x, 1.0, accum.z);
accum.x = ln_space_prefilter(1.0, accum.x, 1.0, accum.w);
FragColor = accum.xxxx;
#else /* VSM */
vec2 accum = vec2(0.0);
/* Poisson disc blur. */
for (int i = 0; i < SAMPLE_NUM; ++i) {
float dist = get_cube_radial_distance(cubevec + poisson[i].x * T + poisson[i].y * B);
float dist_sqr = dist * dist;
accum += vec2(dist, dist_sqr);
/* disc blur. */
vec4 depths1, depths2;
for (int i = 0; i < CONCENTRIC_SAMPLE_NUM; i += 4) {
depths1.xy = texture(shadowTexture, get_texco(cos, concentric[i+0])).rg;
depths1.zw = texture(shadowTexture, get_texco(cos, concentric[i+1])).rg;
depths2.xy = texture(shadowTexture, get_texco(cos, concentric[i+2])).rg;
depths2.zw = texture(shadowTexture, get_texco(cos, concentric[i+3])).rg;
accum += depths1.xy + depths1.zw + depths2.xy + depths2.zw;
}
FragColor = accum.xyxy * shadowInvSampleCount;
#endif /* Prefilter */
#else /* PCF (no prefilter) */
FragColor = vec4(get_cube_radial_distance(cubevec));
FragColor = accum.xyxy * INV_SAMPLE_NUM;
#endif
}
#endif
}