From 32e96448b9d08b7975f6afd73b2569a6b81a125e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Fri, 1 Sep 2017 18:39:39 +0200 Subject: Eevee: Add Variance Shadow Mapping This is an alternative to ESM. It does not suffer the same bleeding artifacts. --- source/blender/draw/engines/eevee/eevee_effects.c | 2 +- source/blender/draw/engines/eevee/eevee_lights.c | 38 ++++++++++----- .../blender/draw/engines/eevee/eevee_materials.c | 55 +++++++++++++++++----- source/blender/draw/engines/eevee/eevee_private.h | 12 +++-- .../engines/eevee/shaders/bsdf_common_lib.glsl | 1 + .../draw/engines/eevee/shaders/lamps_lib.glsl | 31 ++++++++++-- .../engines/eevee/shaders/shadow_store_frag.glsl | 16 +++++-- 7 files changed, 118 insertions(+), 37 deletions(-) (limited to 'source/blender/draw/engines/eevee') diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index cacfd5a5957..73c7b4e96b3 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -804,7 +804,7 @@ void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) struct GPUMaterial *mat = EEVEE_material_world_volume_get( scene, wo, volumetrics->use_lights, volumetrics->use_volume_shadows, - false, volumetrics->use_colored_transmit); + false, volumetrics->use_colored_transmit, sldata->lamps->shadow_method); psl->volumetric_integrate_ps = DRW_pass_create("Volumetric Integration", DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_material_create(mat, psl->volumetric_integrate_ps); diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c index 6af1ad63fd7..20d46619787 100644 --- a/source/blender/draw/engines/eevee/eevee_lights.c +++ b/source/blender/draw/engines/eevee/eevee_lights.c @@ -55,8 +55,8 @@ typedef struct ShadowCaster { static struct { struct GPUShader *shadow_sh; - struct GPUShader *shadow_store_cube_sh; - struct GPUShader *shadow_store_cascade_sh; + struct GPUShader *shadow_store_cube_sh[SHADOW_METHOD_MAX]; + struct GPUShader *shadow_store_cascade_sh[SHADOW_METHOD_MAX]; } e_data = {NULL}; /* Engine data */ extern char datatoc_shadow_vert_glsl[]; @@ -79,8 +79,13 @@ 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 = DRW_shader_create_fullscreen(datatoc_shadow_store_frag_glsl, NULL); - e_data.shadow_store_cascade_sh = DRW_shader_create_fullscreen(datatoc_shadow_store_frag_glsl, "#define CSM"); + 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"); + + 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"); } if (!sldata->lamps) { @@ -92,14 +97,14 @@ void EEVEE_lights_init(EEVEE_SceneLayerData *sldata) int sh_method = BKE_collection_engine_property_value_get_int(props, "shadow_method"); int sh_size = BKE_collection_engine_property_value_get_int(props, "shadow_size"); - UNUSED_VARS(sh_method); EEVEE_LampsInfo *linfo = sldata->lamps; - if (linfo->shadow_size != sh_size) { + if ((linfo->shadow_size != sh_size) || (linfo->shadow_method != sh_method)) { BLI_assert((sh_size > 0) && (sh_size <= 8192)); DRW_TEXTURE_FREE_SAFE(sldata->shadow_pool); DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_target); + linfo->shadow_method = sh_method; linfo->shadow_size = sh_size; linfo->shadow_render_data.stored_texel_size = 1.0 / (float)linfo->shadow_size; @@ -130,7 +135,7 @@ void EEVEE_lights_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl) { psl->shadow_cube_store_pass = DRW_pass_create("Shadow Storage Pass", DRW_STATE_WRITE_COLOR); - DRWShadingGroup *grp = DRW_shgroup_create(e_data.shadow_store_cube_sh, psl->shadow_cube_store_pass); + 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_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); @@ -139,7 +144,7 @@ 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, psl->shadow_cascade_store_pass); + 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_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); @@ -273,8 +278,13 @@ void EEVEE_lights_cache_finish(EEVEE_SceneLayerData *sldata) linfo->update_flag |= LIGHT_UPDATE_SHADOW_CUBE; } - /* TODO Variance Shadow Map */ - shadow_pool_format = DRW_TEX_R_32; + switch (linfo->shadow_method) { + case SHADOW_ESM: shadow_pool_format = DRW_TEX_R_32; break; + case SHADOW_VSM: shadow_pool_format = DRW_TEX_RG_32; break; + default: + BLI_assert(!"Incorrect Shadow Method"); + break; + } if (!sldata->shadow_cube_target) { /* TODO render everything on the same 2d render target using clip planes and no Geom Shader. */ @@ -412,7 +422,7 @@ static void eevee_shadow_cube_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_La evsh->bias = 0.05f * la->bias; evsh->near = la->clipsta; evsh->far = la->clipend; - evsh->exp = la->bleedexp; + evsh->exp = (linfo->shadow_method == SHADOW_VSM) ? la->bleedbias : la->bleedexp; evli->shadowid = (float)(evsmp->shadow_id); } @@ -797,6 +807,8 @@ void EEVEE_draw_shadows(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl) void EEVEE_lights_free(void) { DRW_SHADER_FREE_SAFE(e_data.shadow_sh); - DRW_SHADER_FREE_SAFE(e_data.shadow_store_cube_sh); - DRW_SHADER_FREE_SAFE(e_data.shadow_store_cascade_sh); + 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]); + } } \ No newline at end of file diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index e1852e44722..296fc7b02a0 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -268,6 +268,19 @@ struct GPUTexture *EEVEE_materials_get_util_tex(void) return e_data.util_tex; } +static int eevee_material_shadow_option(int shadow_method) +{ + switch (shadow_method) { + case SHADOW_ESM: return VAR_MAT_ESM; + case SHADOW_VSM: return VAR_MAT_VSM; + default: + BLI_assert(!"Incorrect Shadow Method"); + break; + } + + return 0; +} + static char *eevee_get_defines(int options) { char *str = NULL; @@ -305,6 +318,12 @@ static char *eevee_get_defines(int options) if ((options & VAR_MAT_REFRACT) != 0) { BLI_dynstr_appendf(ds, "#define USE_REFRACTION\n"); } + if ((options & VAR_MAT_VSM) != 0) { + BLI_dynstr_appendf(ds, "#define SHADOW_VSM\n"); + } + if ((options & VAR_MAT_ESM) != 0) { + BLI_dynstr_appendf(ds, "#define SHADOW_ESM\n"); + } str = BLI_dynstr_get_cstring(ds); BLI_dynstr_free(ds); @@ -601,7 +620,7 @@ struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, Wor struct GPUMaterial *EEVEE_material_world_volume_get( struct Scene *scene, World *wo, - bool use_lights, bool use_volume_shadows, bool is_homogeneous, bool use_color_transmit) + bool use_lights, bool use_volume_shadows, bool is_homogeneous, bool use_color_transmit, int shadow_method) { const void *engine = &DRW_engine_viewport_eevee_type; int options = VAR_WORLD_VOLUME; @@ -611,6 +630,8 @@ struct GPUMaterial *EEVEE_material_world_volume_get( if (use_volume_shadows) options |= VAR_VOLUME_SHADOW; if (use_color_transmit) options |= VAR_VOLUME_COLOR; + options |= eevee_material_shadow_option(shadow_method); + GPUMaterial *mat = GPU_material_from_nodetree_find(&wo->gpumaterial, engine, options); if (mat != NULL) { return mat; @@ -630,7 +651,7 @@ struct GPUMaterial *EEVEE_material_world_volume_get( struct GPUMaterial *EEVEE_material_mesh_get( struct Scene *scene, Material *ma, - bool use_blend, bool use_multiply, bool use_refract) + bool use_blend, bool use_multiply, bool use_refract, int shadow_method) { const void *engine = &DRW_engine_viewport_eevee_type; int options = VAR_MAT_MESH; @@ -639,6 +660,8 @@ struct GPUMaterial *EEVEE_material_mesh_get( if (use_multiply) options |= VAR_MAT_MULT; if (use_refract) options |= VAR_MAT_REFRACT; + options |= eevee_material_shadow_option(shadow_method); + GPUMaterial *mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine, options); if (mat) { return mat; @@ -700,11 +723,13 @@ struct GPUMaterial *EEVEE_material_mesh_depth_get( } struct GPUMaterial *EEVEE_material_hair_get( - struct Scene *scene, Material *ma) + struct Scene *scene, Material *ma, int shadow_method) { const void *engine = &DRW_engine_viewport_eevee_type; int options = VAR_MAT_MESH | VAR_MAT_HAIR; + options |= eevee_material_shadow_option(shadow_method); + GPUMaterial *mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine, options); if (mat) { return mat; @@ -727,7 +752,7 @@ struct GPUMaterial *EEVEE_material_hair_get( **/ static struct DRWShadingGroup *EEVEE_default_shading_group_create( EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata, DRWPass *pass, - bool is_hair, bool is_flat_normal, bool use_blend, bool use_ssr) + bool is_hair, bool is_flat_normal, bool use_blend, bool use_ssr, int shadow_method) { static int ssr_id; ssr_id = (use_ssr) ? 0 : -1; @@ -737,6 +762,8 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_create( if (is_flat_normal) options |= VAR_MAT_FLAT; if (use_blend) options |= VAR_MAT_BLEND; + options |= eevee_material_shadow_option(shadow_method); + if (e_data.default_lit[options] == NULL) { create_default_shader(options); } @@ -752,7 +779,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_create( **/ static struct DRWShadingGroup *EEVEE_default_shading_group_get( EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata, - bool is_hair, bool is_flat_normal, bool use_ssr) + bool is_hair, bool is_flat_normal, bool use_ssr, int shadow_method) { static int ssr_id; ssr_id = (use_ssr) ? 0 : -1; @@ -761,6 +788,8 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_get( if (is_hair) options |= VAR_MAT_HAIR; if (is_flat_normal) options |= VAR_MAT_FLAT; + options |= eevee_material_shadow_option(shadow_method); + if (e_data.default_lit[options] == NULL) { create_default_shader(options); } @@ -920,6 +949,7 @@ static void material_opaque( Scene *scene = draw_ctx->scene; EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; + EEVEE_LampsInfo *linfo = sldata->lamps; float *color_p = &ma->r; float *metal_p = &ma->ray_mirror; @@ -938,7 +968,7 @@ static void material_opaque( /* This will have been created already, just perform a lookup. */ *gpumat = (use_gpumat) ? EEVEE_material_mesh_get( - scene, ma, false, false, use_refract) : NULL; + scene, ma, false, false, use_refract, linfo->shadow_method) : NULL; *gpumat_depth = (use_gpumat) ? EEVEE_material_mesh_depth_get( scene, ma, (ma->blend_method == MA_BM_HASHED), false) : NULL; return; @@ -946,7 +976,7 @@ static void material_opaque( if (use_gpumat) { /* Shading */ - *gpumat = EEVEE_material_mesh_get(scene, ma, false, false, use_refract); + *gpumat = EEVEE_material_mesh_get(scene, ma, false, false, use_refract, linfo->shadow_method); *shgrp = DRW_shgroup_material_create(*gpumat, use_refract ? psl->refract_pass : psl->material_pass); if (*shgrp) { @@ -990,7 +1020,7 @@ static void material_opaque( /* Fallback to default shader */ if (*shgrp == NULL) { - *shgrp = EEVEE_default_shading_group_get(sldata, vedata, false, use_flat_nor, stl->effects->use_ssr); + *shgrp = EEVEE_default_shading_group_get(sldata, vedata, false, use_flat_nor, stl->effects->use_ssr, linfo->shadow_method); DRW_shgroup_uniform_vec3(*shgrp, "basecol", color_p, 1); DRW_shgroup_uniform_float(*shgrp, "metallic", metal_p, 1); DRW_shgroup_uniform_float(*shgrp, "specular", spec_p, 1); @@ -1024,6 +1054,7 @@ static void material_transparent( Scene *scene = draw_ctx->scene; EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; + EEVEE_LampsInfo *linfo = sldata->lamps; const bool use_refract = ((ma->blend_flag & MA_BL_SS_REFRACTION) != 0) && ((stl->effects->enabled_effects & EFFECT_REFRACT) != 0); @@ -1034,7 +1065,7 @@ static void material_transparent( if (ma->use_nodes && ma->nodetree) { /* Shading */ - *gpumat = EEVEE_material_mesh_get(scene, ma, true, (ma->blend_method == MA_BM_MULTIPLY), use_refract); + *gpumat = EEVEE_material_mesh_get(scene, ma, true, (ma->blend_method == MA_BM_MULTIPLY), use_refract, linfo->shadow_method); *shgrp = DRW_shgroup_material_create(*gpumat, psl->transparent_pass); if (*shgrp) { @@ -1055,7 +1086,7 @@ static void material_transparent( if (*shgrp == NULL) { *shgrp = EEVEE_default_shading_group_create( sldata, vedata, psl->transparent_pass, - false, use_flat_nor, true, false); + false, use_flat_nor, true, false, linfo->shadow_method); DRW_shgroup_uniform_vec3(*shgrp, "basecol", color_p, 1); DRW_shgroup_uniform_float(*shgrp, "metallic", metal_p, 1); DRW_shgroup_uniform_float(*shgrp, "specular", spec_p, 1); @@ -1268,7 +1299,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sl } else { if (ma->use_nodes && ma->nodetree) { - struct GPUMaterial *gpumat = EEVEE_material_hair_get(scene, ma); + struct GPUMaterial *gpumat = EEVEE_material_hair_get(scene, ma, sldata->lamps->shadow_method); shgrp = DRW_shgroup_material_create(gpumat, psl->material_pass); if (shgrp) { @@ -1290,7 +1321,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sl /* Fallback to default shader */ if (shgrp == NULL) { - shgrp = EEVEE_default_shading_group_get(sldata, vedata, true, false, stl->effects->use_ssr); + shgrp = EEVEE_default_shading_group_get(sldata, vedata, true, false, stl->effects->use_ssr, sldata->lamps->shadow_method); DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1); DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1); DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1); diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 1089fd2c5b9..1507e8be08e 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -64,10 +64,12 @@ enum { VAR_MAT_HAIR = (1 << 2), VAR_MAT_FLAT = (1 << 3), VAR_MAT_BLEND = (1 << 4), + VAR_MAT_VSM = (1 << 5), + VAR_MAT_ESM = (1 << 6), /* Max number of variation */ /* IMPORTANT : Leave it last and set * it's value accordingly. */ - VAR_MAT_MAX = (1 << 5), + VAR_MAT_MAX = (1 << 7), /* These are options that are not counted in VAR_MAT_MAX * because they are not cumulative with the others above. */ VAR_MAT_CLIP = (1 << 8), @@ -81,6 +83,7 @@ enum { enum { SHADOW_ESM = 1, SHADOW_VSM = 2, + SHADOW_METHOD_MAX = 3, }; typedef struct EEVEE_PassList { @@ -516,11 +519,12 @@ void EEVEE_materials_cache_finish(EEVEE_Data *vedata); struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, struct World *wo); struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, struct World *wo); struct GPUMaterial *EEVEE_material_world_volume_get( - struct Scene *scene, struct World *wo, bool use_lights, bool use_volume_shadows, bool is_homogeneous, bool use_color_transmit); + struct Scene *scene, struct World *wo, bool use_lights, bool use_volume_shadows, bool is_homogeneous, bool use_color_transmit, + int shadow_method); struct GPUMaterial *EEVEE_material_mesh_get( - struct Scene *scene, Material *ma, bool use_blend, bool use_multiply, bool use_refract); + struct Scene *scene, Material *ma, bool use_blend, bool use_multiply, bool use_refract, int shadow_method); struct GPUMaterial *EEVEE_material_mesh_depth_get(struct Scene *scene, Material *ma, bool use_hashed_alpha, bool is_shadow); -struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma); +struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma, int shadow_method); void EEVEE_materials_free(void); void EEVEE_draw_default_passes(EEVEE_PassList *psl); void EEVEE_update_util_texture(float offset); 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 0da95349bba..713fb2a31d5 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -92,6 +92,7 @@ struct ShadowCascadeData { #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 /* ------- 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 79c04409161..a0b28a02dbc 100644 --- a/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl @@ -22,14 +22,37 @@ float shadow_cubemap(float shid, vec4 l_vector) ShadowCubeData scd = shadows_cube_data[int(shid)]; vec3 cubevec = -l_vector.xyz / l_vector.w; - float dist = l_vector.w - scd.sh_cube_bias; + float dist = l_vector.w; - float z = texture_octahedron(shadowTexture, vec4(cubevec, shid)).r; +#if defined(SHADOW_VSM) + vec2 moments = texture_octahedron(shadowTexture, vec4(cubevec, shid)).rg; + 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); + + 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); - float esm_test = saturate(exp(scd.sh_cube_exp * (z - dist))); - float sh_test = step(0, z - dist); + float vsm_test = max(p, p_max); + return vsm_test; +#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; + +#else + float z = texture_octahedron(shadowTexture, vec4(cubevec, shid)).r; + float sh_test = step(0, z - (dist - scd.sh_cube_bias)); + return sh_test; +#endif } float shadow_cascade(float shid, vec3 W) 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 1c0d2556e10..9a7161660f7 100644 --- a/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl @@ -117,8 +117,6 @@ float wang_hash_noise(uint s) return fract(value); } -#define ESM - void main() { vec2 uvs = gl_FragCoord.xy * storedTexelSize; @@ -144,13 +142,14 @@ void main() { /* TODO Can be optimized by groupping fetches * and by converting to radial distance beforehand. */ -#if defined(ESM) +#if defined(ESM) || defined(VSM) vec3 T, B; make_orthonormal_basis(cubevec, wang_hash_noise(0u), T, B); T *= 0.01; B *= 0.01; +#ifdef ESM float accum = 0.0; /* Poisson disc blur in log space. */ @@ -164,7 +163,18 @@ void main() { } FragColor = vec4(accum); +#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); + } + FragColor = accum.xyxy * shadowInvSampleCount; +#endif /* Prefilter */ #else /* PCF (no prefilter) */ FragColor = vec4(get_cube_radial_distance(cubevec)); #endif -- cgit v1.2.3