diff options
Diffstat (limited to 'source/blender/draw')
28 files changed, 1907 insertions, 2696 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 19ab96868ef..50851c41770 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -103,7 +103,11 @@ set(SRC engines/eevee/eevee_occlusion.c engines/eevee/eevee_render.c engines/eevee/eevee_screen_raytrace.c + engines/eevee/eevee_sampling.c engines/eevee/eevee_shaders.c + engines/eevee/eevee_shadows.c + engines/eevee/eevee_shadows_cube.c + engines/eevee/eevee_shadows_cascade.c engines/eevee/eevee_subsurface.c engines/eevee/eevee_temporal_sampling.c engines/eevee/eevee_volumes.c @@ -201,6 +205,7 @@ data_to_c_simple(engines/eevee/shaders/effect_mist_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/effect_subsurface_frag.glsl SRC) +data_to_c_simple(engines/eevee/shaders/effect_translucency_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/effect_temporal_aa.glsl SRC) data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl SRC) @@ -209,10 +214,6 @@ data_to_c_simple(engines/eevee/shaders/prepass_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/prepass_vert.glsl SRC) data_to_c_simple(engines/eevee/shaders/shadow_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/shadow_vert.glsl SRC) -data_to_c_simple(engines/eevee/shaders/shadow_process_vert.glsl SRC) -data_to_c_simple(engines/eevee/shaders/shadow_process_geom.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_common_lib.glsl SRC) diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c index b792f93ced2..dd70ee1bd4b 100644 --- a/source/blender/draw/engines/eevee/eevee_data.c +++ b/source/blender/draw/engines/eevee/eevee_data.c @@ -35,23 +35,13 @@ void EEVEE_view_layer_data_free(void *storage) MEM_SAFE_FREE(sldata->lights); DRW_UBO_FREE_SAFE(sldata->light_ubo); DRW_UBO_FREE_SAFE(sldata->shadow_ubo); - DRW_UBO_FREE_SAFE(sldata->shadow_render_ubo); - GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cube_target_fb); - GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cube_store_fb); - GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cube_copy_fb); - GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cascade_target_fb); - GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cascade_store_fb); - GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cascade_copy_fb); - DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_target); - DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_blur); + GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_fb); DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_pool); - DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_target); - DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_blur); DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_pool); - MEM_SAFE_FREE(sldata->shcasters_buffers[0].shadow_casters); - MEM_SAFE_FREE(sldata->shcasters_buffers[0].flags); - MEM_SAFE_FREE(sldata->shcasters_buffers[1].shadow_casters); - MEM_SAFE_FREE(sldata->shcasters_buffers[1].flags); + for (int i = 0; i < 2; i++) { + MEM_SAFE_FREE(sldata->shcasters_buffers[i].bbox); + MEM_SAFE_FREE(sldata->shcasters_buffers[i].update); + } if (sldata->fallback_lightcache) { EEVEE_lightcache_free(sldata->fallback_lightcache); @@ -153,7 +143,6 @@ static void eevee_light_data_init(DrawData *dd) { EEVEE_LightEngineData *led = (EEVEE_LightEngineData *)dd; led->need_update = true; - led->prev_cube_shadow_id = -1; } EEVEE_LightEngineData *EEVEE_light_data_get(Object *ob) diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index ab4eb7b8532..a1096390bce 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -84,7 +84,7 @@ static void eevee_engine_init(void *ved) /* EEVEE_effects_init needs to go first for TAA */ EEVEE_effects_init(sldata, vedata, camera, false); EEVEE_materials_init(sldata, stl, fbl); - EEVEE_lights_init(sldata); + EEVEE_shadows_init(sldata); EEVEE_lightprobes_init(sldata, vedata); } @@ -139,7 +139,7 @@ void EEVEE_cache_populate(void *vedata, Object *ob) } if (cast_shadow) { - EEVEE_lights_cache_shcaster_object_add(sldata, ob); + EEVEE_shadows_caster_register(sldata, ob); } } @@ -223,7 +223,7 @@ static void eevee_draw_background(void *vedata) /* Refresh shadows */ DRW_stats_group_start("Shadows"); - EEVEE_draw_shadows(sldata, vedata, stl->effects->taa_view); + EEVEE_shadows_draw(sldata, vedata, stl->effects->taa_view); DRW_stats_group_end(); if (((stl->effects->enabled_effects & EFFECT_TAA) != 0) && @@ -269,9 +269,7 @@ static void eevee_draw_background(void *vedata) if (DRW_state_draw_background()) { DRW_draw_pass(psl->background_pass); } - EEVEE_draw_default_passes(psl); - DRW_draw_pass(psl->material_pass); - DRW_draw_pass(psl->material_pass_cull); + EEVEE_materials_draw_opaque(sldata, psl); EEVEE_subsurface_data_render(sldata, vedata); DRW_stats_group_end(); @@ -368,11 +366,21 @@ static void eevee_draw_background(void *vedata) } break; case 8: - if (effects->sss_data) { - DRW_transform_to_display(effects->sss_data, false, false); + if (effects->sss_irradiance) { + DRW_transform_to_display(effects->sss_irradiance, false, false); } break; case 9: + if (effects->sss_radius) { + DRW_transform_to_display(effects->sss_radius, false, false); + } + break; + case 10: + if (effects->sss_albedo) { + DRW_transform_to_display(effects->sss_albedo, false, false); + } + break; + case 11: if (effects->velocity_tx) { DRW_transform_to_display(effects->velocity_tx, false, false); } @@ -467,7 +475,7 @@ static void eevee_engine_free(void) EEVEE_depth_of_field_free(); EEVEE_effects_free(); EEVEE_lightprobes_free(); - EEVEE_lights_free(); + EEVEE_shadows_free(); EEVEE_materials_free(); EEVEE_mist_free(); EEVEE_motion_blur_free(); diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c index 05aea652591..e32194a11de 100644 --- a/source/blender/draw/engines/eevee/eevee_lightcache.c +++ b/source/blender/draw/engines/eevee/eevee_lightcache.c @@ -743,7 +743,7 @@ static void eevee_lightbake_cache_create(EEVEE_Data *vedata, EEVEE_LightBake *lb EEVEE_effects_init(sldata, vedata, NULL, true); EEVEE_materials_init(sldata, stl, fbl); - EEVEE_lights_init(sldata); + EEVEE_shadows_init(sldata); EEVEE_lightprobes_init(sldata, vedata); EEVEE_effects_cache_init(sldata, vedata); diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index 8b1309e8537..2d23359a175 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -904,7 +904,7 @@ static void lightbake_render_scene_face(int face, EEVEE_BakeRenderData *user_dat struct GPUFrameBuffer **face_fb = user_data->face_fb; /* Be sure that cascaded shadow maps are updated. */ - EEVEE_draw_shadows(sldata, user_data->vedata, views[face]); + EEVEE_shadows_draw(sldata, user_data->vedata, views[face]); GPU_framebuffer_bind(face_fb[face]); GPU_framebuffer_clear_depth(face_fb[face], 1.0f); @@ -912,11 +912,9 @@ static void lightbake_render_scene_face(int face, EEVEE_BakeRenderData *user_dat DRW_draw_pass(psl->depth_pass); DRW_draw_pass(psl->depth_pass_cull); DRW_draw_pass(psl->probe_background); - DRW_draw_pass(psl->material_pass); - DRW_draw_pass(psl->material_pass_cull); + EEVEE_materials_draw_opaque(sldata, psl); DRW_draw_pass(psl->sss_pass); /* Only output standard pass */ DRW_draw_pass(psl->sss_pass_cull); - EEVEE_draw_default_passes(psl); DRW_draw_pass(psl->transparent_pass); } @@ -964,7 +962,7 @@ static void lightbake_render_scene_reflected(int layer, EEVEE_BakeRenderData *us DRW_stats_group_start("Planar Reflection"); /* Be sure that cascaded shadow maps are updated. */ - EEVEE_draw_shadows(sldata, vedata, stl->g_data->planar_views[layer]); + EEVEE_shadows_draw(sldata, vedata, stl->g_data->planar_views[layer]); GPU_framebuffer_bind(fbl->planarref_fb); GPU_framebuffer_clear_depth(fbl->planarref_fb, 1.0); @@ -987,9 +985,7 @@ static void lightbake_render_scene_reflected(int layer, EEVEE_BakeRenderData *us GPU_framebuffer_bind(fbl->planarref_fb); /* Shading pass */ - EEVEE_draw_default_passes(psl); - DRW_draw_pass(psl->material_pass); - DRW_draw_pass(psl->material_pass_cull); + EEVEE_materials_draw_opaque(sldata, psl); DRW_draw_pass(psl->sss_pass); /* Only output standard pass */ DRW_draw_pass(psl->sss_pass_cull); DRW_draw_pass(psl->refract_pass); diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c index 0bfc23b8354..126ec8d81c4 100644 --- a/source/blender/draw/engines/eevee/eevee_lights.c +++ b/source/blender/draw/engines/eevee/eevee_lights.c @@ -20,11 +20,7 @@ * \ingroup DNA */ -#include "DRW_render.h" - -#include "BLI_dynstr.h" -#include "BLI_rand.h" -#include "BLI_rect.h" +#include "BLI_sys_types.h" /* bool */ #include "BKE_object.h" @@ -32,623 +28,20 @@ #include "eevee_private.h" -#define SHADOW_CASTER_ALLOC_CHUNK 16 - -// #define DEBUG_CSM -// #define DEBUG_SHADOW_DISTRIBUTION - -static struct { - struct GPUShader *shadow_sh; - struct GPUShader *shadow_store_cube_sh[SHADOW_METHOD_MAX]; - struct GPUShader *shadow_store_cube_high_sh[SHADOW_METHOD_MAX]; - struct GPUShader *shadow_store_cascade_sh[SHADOW_METHOD_MAX]; - struct GPUShader *shadow_store_cascade_high_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_frag_glsl[]; -extern char datatoc_shadow_process_vert_glsl[]; -extern char datatoc_shadow_process_geom_glsl[]; -extern char datatoc_shadow_store_frag_glsl[]; -extern char datatoc_shadow_copy_frag_glsl[]; -extern char datatoc_concentric_samples_lib_glsl[]; - -extern char datatoc_common_view_lib_glsl[]; - -/* Prototypes */ -static void eevee_light_setup(Object *ob, EEVEE_Light *evli); -static float light_attenuation_radius_get(Light *la, float light_threshold); - -/* *********** LIGHT BITS *********** */ -static void lightbits_set_single(EEVEE_LightBits *bitf, uint idx, bool val) -{ - if (val) { - bitf->fields[idx / 8] |= (1 << (idx % 8)); - } - else { - bitf->fields[idx / 8] &= ~(1 << (idx % 8)); - } -} - -static void lightbits_set_all(EEVEE_LightBits *bitf, bool val) -{ - memset(bitf, (val) ? 0xFF : 0x00, sizeof(EEVEE_LightBits)); -} - -static void lightbits_or(EEVEE_LightBits *r, const EEVEE_LightBits *v) -{ - for (int i = 0; i < MAX_LIGHTBITS_FIELDS; ++i) { - r->fields[i] |= v->fields[i]; - } -} - -static bool lightbits_get(const EEVEE_LightBits *r, uint idx) -{ - return r->fields[idx / 8] & (1 << (idx % 8)); -} - -static void lightbits_convert(EEVEE_LightBits *r, - const EEVEE_LightBits *bitf, - const int *light_bit_conv_table, - uint table_length) -{ - for (int i = 0; i < table_length; ++i) { - if (lightbits_get(bitf, i) != 0) { - if (light_bit_conv_table[i] >= 0) { - r->fields[i / 8] |= (1 << (i % 8)); - } - } - } -} - -/* *********** FUNCTIONS *********** */ - -void EEVEE_lights_init(EEVEE_ViewLayerData *sldata) -{ - const uint 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(); - const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); - - if (!e_data.shadow_sh) { - e_data.shadow_sh = DRW_shader_create_with_lib(datatoc_shadow_vert_glsl, - NULL, - datatoc_shadow_frag_glsl, - datatoc_common_view_lib_glsl, - NULL); - } - - if (!sldata->lights) { - sldata->lights = MEM_callocN(sizeof(EEVEE_LightsInfo), "EEVEE_LightsInfo"); - sldata->light_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_Light) * MAX_LIGHT, NULL); - sldata->shadow_ubo = DRW_uniformbuffer_create(shadow_ubo_size, NULL); - sldata->shadow_render_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_ShadowRender), NULL); - - for (int i = 0; i < 2; ++i) { - sldata->shcasters_buffers[i].shadow_casters = MEM_callocN( - sizeof(EEVEE_ShadowCaster) * SHADOW_CASTER_ALLOC_CHUNK, "EEVEE_ShadowCaster buf"); - sldata->shcasters_buffers[i].flags = MEM_callocN(sizeof(sldata->shcasters_buffers[0].flags) * - SHADOW_CASTER_ALLOC_CHUNK, - "EEVEE_shcast_buffer flags buf"); - sldata->shcasters_buffers[i].alloc_count = SHADOW_CASTER_ALLOC_CHUNK; - sldata->shcasters_buffers[i].count = 0; - } - - sldata->lights->shcaster_frontbuffer = &sldata->shcasters_buffers[0]; - sldata->lights->shcaster_backbuffer = &sldata->shcasters_buffers[1]; - } - - /* Flip buffers */ - SWAP(EEVEE_ShadowCasterBuffer *, - sldata->lights->shcaster_frontbuffer, - sldata->lights->shcaster_backbuffer); - - const int sh_method = scene_eval->eevee.shadow_method; - int sh_cube_size = scene_eval->eevee.shadow_cube_size; - int sh_cascade_size = scene_eval->eevee.shadow_cascade_size; - const bool sh_high_bitdepth = (scene_eval->eevee.flag & SCE_EEVEE_SHADOW_HIGH_BITDEPTH) != 0; - sldata->lights->soft_shadows = (scene_eval->eevee.flag & SCE_EEVEE_SHADOW_SOFT) != 0; - - EEVEE_LightsInfo *linfo = sldata->lights; - if ((linfo->shadow_cube_size != sh_cube_size) || (linfo->shadow_method != sh_method) || - (linfo->shadow_high_bitdepth != sh_high_bitdepth)) { - BLI_assert((sh_cube_size > 0) && (sh_cube_size <= 4096)); - DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_pool); - DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_target); - DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_blur); - - /* Compute adequate size for the octahedral map. */ - linfo->shadow_cube_store_size = OCTAHEDRAL_SIZE_FROM_CUBESIZE(sh_cube_size); - - CLAMP(linfo->shadow_cube_store_size, 1, 4096); - CLAMP(sh_cube_size, 1, 4096); - - linfo->shadow_render_data.cube_texel_size = 1.0f / sh_cube_size; - } - - if ((linfo->shadow_cascade_size != sh_cascade_size) || (linfo->shadow_method != sh_method) || - (linfo->shadow_high_bitdepth != sh_high_bitdepth)) { - BLI_assert((sh_cascade_size > 0) && (sh_cascade_size <= 4096)); - DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_pool); - DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_target); - DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_blur); - - CLAMP(sh_cascade_size, 1, 4096); - } - - linfo->shadow_high_bitdepth = sh_high_bitdepth; - linfo->shadow_method = sh_method; - linfo->shadow_cube_size = sh_cube_size; - linfo->shadow_cascade_size = sh_cascade_size; - - /* only compile the ones needed. reduce startup time. */ - if ((sh_method == SHADOW_ESM) && !e_data.shadow_copy_cube_sh[SHADOW_ESM]) { - e_data.shadow_copy_cube_sh[SHADOW_ESM] = DRW_shader_create(datatoc_shadow_process_vert_glsl, - datatoc_shadow_process_geom_glsl, - datatoc_shadow_copy_frag_glsl, - "#define ESM\n" - "#define COPY\n"); - e_data.shadow_copy_cascade_sh[SHADOW_ESM] = DRW_shader_create(datatoc_shadow_process_vert_glsl, - datatoc_shadow_process_geom_glsl, - datatoc_shadow_copy_frag_glsl, - "#define ESM\n" - "#define COPY\n" - "#define CSM\n"); - } - else if ((sh_method == SHADOW_VSM) && !e_data.shadow_copy_cube_sh[SHADOW_VSM]) { - e_data.shadow_copy_cube_sh[SHADOW_VSM] = DRW_shader_create(datatoc_shadow_process_vert_glsl, - datatoc_shadow_process_geom_glsl, - datatoc_shadow_copy_frag_glsl, - "#define VSM\n" - "#define COPY\n"); - e_data.shadow_copy_cascade_sh[SHADOW_VSM] = DRW_shader_create(datatoc_shadow_process_vert_glsl, - datatoc_shadow_process_geom_glsl, - datatoc_shadow_copy_frag_glsl, - "#define VSM\n" - "#define COPY\n" - "#define CSM\n"); - } -} - -static GPUShader *eevee_lights_get_store_sh(int shadow_method, bool high_blur, bool cascade) -{ - GPUShader **shader; - - if (cascade) { - shader = (high_blur) ? &e_data.shadow_store_cascade_high_sh[shadow_method] : - &e_data.shadow_store_cascade_sh[shadow_method]; - } - else { - shader = (high_blur) ? &e_data.shadow_store_cube_high_sh[shadow_method] : - &e_data.shadow_store_cube_sh[shadow_method]; - } - - if (*shader == NULL) { - 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); - - ds_frag = BLI_dynstr_new(); - BLI_dynstr_append(ds_frag, (shadow_method == SHADOW_VSM) ? "#define VSM\n" : "#define ESM\n"); - if (high_blur) { - BLI_dynstr_append(ds_frag, "#define HIGH_BLUR\n"); - } - if (cascade) { - BLI_dynstr_append(ds_frag, "#define CSM\n"); - } - char *define_str = BLI_dynstr_get_cstring(ds_frag); - BLI_dynstr_free(ds_frag); - - *shader = DRW_shader_create(datatoc_shadow_process_vert_glsl, - datatoc_shadow_process_geom_glsl, - store_shadow_shader_str, - define_str); - - MEM_freeN(store_shadow_shader_str); - MEM_freeN(define_str); - } - - return *shader; -} - -static DRWPass *eevee_lights_cube_store_pass_get(EEVEE_PassList *psl, - EEVEE_ViewLayerData *sldata, - int shadow_method, - int shadow_samples_len) -{ - bool high_blur = shadow_samples_len > 16; - DRWPass **pass = (high_blur) ? &psl->shadow_cube_store_pass : &psl->shadow_cube_store_high_pass; - if (*pass == NULL) { - *pass = DRW_pass_create("Shadow Cube Storage Pass", DRW_STATE_WRITE_COLOR); - GPUShader *shader = eevee_lights_get_store_sh(shadow_method, high_blur, false); - DRWShadingGroup *grp = DRW_shgroup_create(shader, *pass); - DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cube_blur); - DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo); - - DRW_shgroup_call_procedural_triangles(grp, NULL, 6); - } - return *pass; -} - -static DRWPass *eevee_lights_cascade_store_pass_get(EEVEE_PassList *psl, - EEVEE_ViewLayerData *sldata, - int shadow_method, - int shadow_samples_len) -{ - bool high_blur = shadow_samples_len > 16; - DRWPass **pass = (high_blur) ? &psl->shadow_cascade_store_pass : - &psl->shadow_cascade_store_high_pass; - if (*pass == NULL) { - *pass = DRW_pass_create("Shadow Cascade Storage Pass", DRW_STATE_WRITE_COLOR); - GPUShader *shader = eevee_lights_get_store_sh(shadow_method, high_blur, true); - DRWShadingGroup *grp = DRW_shgroup_create(shader, *pass); - DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cascade_blur); - DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo); - - DRW_shgroup_call_procedural_triangles(grp, NULL, MAX_CASCADE_NUM); - } - return *pass; -} - -void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) -{ - EEVEE_LightsInfo *linfo = sldata->lights; - EEVEE_StorageList *stl = vedata->stl; - EEVEE_PassList *psl = vedata->psl; - - linfo->shcaster_frontbuffer->count = 0; - linfo->num_light = 0; - linfo->num_cube_layer = 0; - linfo->num_cascade_layer = 0; - linfo->gpu_cube_len = linfo->gpu_cascade_len = linfo->gpu_shadow_len = 0; - linfo->cpu_cube_len = linfo->cpu_cascade_len = 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)); - memset(linfo->new_shadow_id, -1, sizeof(linfo->new_shadow_id)); - - /* Shadow Casters: Reset flags. */ - memset(linfo->shcaster_backbuffer->flags, - (char)SHADOW_CASTER_PRUNED, - linfo->shcaster_backbuffer->alloc_count); - memset(linfo->shcaster_frontbuffer->flags, 0x00, linfo->shcaster_frontbuffer->alloc_count); - - psl->shadow_cube_store_pass = NULL; - psl->shadow_cube_store_high_pass = NULL; - psl->shadow_cascade_store_pass = NULL; - psl->shadow_cascade_store_high_pass = NULL; - - { - DRW_PASS_CREATE(psl->shadow_cube_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_texture_ref(grp, "shadowTexture", &sldata->shadow_cube_target); - DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo); - - DRW_shgroup_call_procedural_triangles(grp, NULL, 6); - } - - { - DRW_PASS_CREATE(psl->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_texture_ref(grp, "shadowTexture", &sldata->shadow_cascade_target); - DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo); - - DRW_shgroup_call_procedural_triangles(grp, NULL, MAX_CASCADE_NUM); - } - - { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; - DRW_PASS_CREATE(psl->shadow_pass, state); - - stl->g_data->shadow_shgrp = DRW_shgroup_create(e_data.shadow_sh, psl->shadow_pass); - } -} - -void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob) +/* Reconstruct local obmat from EEVEE_light. (normalized) */ +void eevee_light_matrix_get(const EEVEE_Light *evli, float r_mat[4][4]) { - EEVEE_LightsInfo *linfo = sldata->lights; - - const DRWContextState *draw_ctx = DRW_context_state_get(); - const float threshold = draw_ctx->scene->eevee.light_threshold; - /* Step 1 find all lights in the scene and setup them */ - if (linfo->num_light >= MAX_LIGHT) { - printf("Too many lights in the scene !!!\n"); - } - else { - Light *la = (Light *)ob->data; - - /* Early out if light has no power. */ - if (la->energy == 0.0f || is_zero_v3(&la->r)) { - return; - } - - EEVEE_Light *evli = linfo->light_data + linfo->num_light; - eevee_light_setup(ob, evli); - - /* We do not support shadowmaps for dupli lights. */ - if ((ob->base_flag & BASE_FROM_DUPLI) != 0) { - linfo->num_light++; - return; - } - - EEVEE_LightEngineData *led = EEVEE_light_data_ensure(ob); - - /* Save previous shadow id. */ - int prev_cube_sh_id = led->prev_cube_shadow_id; - - /* Default light without shadows */ - led->data.ld.shadow_id = -1; - led->prev_cube_shadow_id = -1; - - if (la->mode & LA_SHADOW) { - if (la->type == LA_SUN) { - int cascade_nbr = la->cascade_count; - - if ((linfo->gpu_cascade_len + 1) <= MAX_SHADOW_CASCADE) { - /* Save Light object. */ - linfo->shadow_cascade_ref[linfo->cpu_cascade_len] = ob; - - /* Store indices. */ - EEVEE_ShadowCascadeData *data = &led->data.scad; - data->shadow_id = linfo->gpu_shadow_len; - data->cascade_id = linfo->gpu_cascade_len; - data->layer_id = linfo->num_cascade_layer; - - /* Increment indices. */ - linfo->gpu_shadow_len += 1; - linfo->gpu_cascade_len += 1; - linfo->num_cascade_layer += cascade_nbr; - - linfo->cpu_cascade_len += 1; - } - } - else if (la->type == LA_SPOT || la->type == LA_LOCAL || la->type == LA_AREA) { - if ((linfo->gpu_cube_len + 1) <= MAX_SHADOW_CUBE) { - /* Save Light object. */ - linfo->shadow_cube_ref[linfo->cpu_cube_len] = ob; - - /* For light update tracking. */ - if ((prev_cube_sh_id >= 0) && (prev_cube_sh_id < linfo->shcaster_backbuffer->count)) { - linfo->new_shadow_id[prev_cube_sh_id] = linfo->cpu_cube_len; - } - led->prev_cube_shadow_id = linfo->cpu_cube_len; - - /* Saving light bounds for later. */ - BLI_assert(linfo->cpu_cube_len >= 0 && linfo->cpu_cube_len < MAX_LIGHT); - copy_v3_v3(linfo->shadow_bounds[linfo->cpu_cube_len].center, ob->obmat[3]); - linfo->shadow_bounds[linfo->cpu_cube_len].radius = light_attenuation_radius_get( - la, threshold); - - EEVEE_ShadowCubeData *data = &led->data.scd; - /* Store indices. */ - data->shadow_id = linfo->gpu_shadow_len; - data->cube_id = linfo->gpu_cube_len; - data->layer_id = linfo->num_cube_layer; - - /* Increment indices. */ - linfo->gpu_shadow_len += 1; - linfo->gpu_cube_len += 1; - linfo->num_cube_layer += 1; - - linfo->cpu_cube_len += 1; - } - } - } - - led->data.ld.light_id = linfo->num_light; - linfo->light_ref[linfo->num_light] = ob; - linfo->num_light++; - } -} - -/* Add a shadow caster to the shadowpasses */ -void EEVEE_lights_cache_shcaster_add(EEVEE_ViewLayerData *UNUSED(sldata), - EEVEE_StorageList *stl, - struct GPUBatch *geom, - Object *ob) -{ - DRW_shgroup_call(stl->g_data->shadow_shgrp, geom, ob); -} - -void EEVEE_lights_cache_shcaster_material_add(EEVEE_ViewLayerData *sldata, - EEVEE_PassList *psl, - struct GPUMaterial *gpumat, - struct GPUBatch *geom, - struct Object *ob, - const float *alpha_threshold) -{ - /* TODO / PERF : reuse the same shading group for objects with the same material */ - DRWShadingGroup *grp = DRW_shgroup_material_create(gpumat, psl->shadow_pass); - - if (grp == NULL) { - return; - } - - /* Grrr needed for correctness but not 99% of the time not needed. - * TODO detect when needed? */ - DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); - DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo); - DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); - DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); - DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); - DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - - if (alpha_threshold != NULL) { - DRW_shgroup_uniform_float(grp, "alphaThreshold", alpha_threshold, 1); - } - - DRW_shgroup_call(grp, geom, ob); + copy_v3_v3(r_mat[0], evli->rightvec); + copy_v3_v3(r_mat[1], evli->upvec); + negate_v3_v3(r_mat[2], evli->forwardvec); + copy_v3_v3(r_mat[3], evli->position); + r_mat[0][3] = 0.0f; + r_mat[1][3] = 0.0f; + r_mat[2][3] = 0.0f; + r_mat[3][3] = 1.0f; } -/* Make that object update shadow casting lights inside its influence bounding box. */ -void EEVEE_lights_cache_shcaster_object_add(EEVEE_ViewLayerData *sldata, Object *ob) -{ - if ((ob->base_flag & BASE_FROM_DUPLI) != 0) { - /* TODO: Special case for dupli objects because we cannot save the object pointer. */ - return; - } - - EEVEE_ObjectEngineData *oedata = EEVEE_object_data_ensure(ob); - EEVEE_LightsInfo *linfo = sldata->lights; - EEVEE_ShadowCasterBuffer *backbuffer = linfo->shcaster_backbuffer; - EEVEE_ShadowCasterBuffer *frontbuffer = linfo->shcaster_frontbuffer; - int past_id = oedata->shadow_caster_id; - - /* Update flags in backbuffer. */ - if (past_id > -1 && past_id < backbuffer->count) { - backbuffer->flags[past_id] &= ~SHADOW_CASTER_PRUNED; - - if (oedata->need_update) { - backbuffer->flags[past_id] |= SHADOW_CASTER_UPDATED; - } - } - - /* Update id. */ - oedata->shadow_caster_id = frontbuffer->count++; - - /* Make sure shadow_casters is big enough. */ - if (oedata->shadow_caster_id >= frontbuffer->alloc_count) { - frontbuffer->alloc_count += SHADOW_CASTER_ALLOC_CHUNK; - frontbuffer->shadow_casters = MEM_reallocN( - frontbuffer->shadow_casters, sizeof(EEVEE_ShadowCaster) * frontbuffer->alloc_count); - frontbuffer->flags = MEM_reallocN(frontbuffer->flags, - sizeof(EEVEE_ShadowCaster) * frontbuffer->alloc_count); - } - - EEVEE_ShadowCaster *shcaster = frontbuffer->shadow_casters + oedata->shadow_caster_id; - - if (oedata->need_update) { - frontbuffer->flags[oedata->shadow_caster_id] = SHADOW_CASTER_UPDATED; - } - - /* Update World AABB in frontbuffer. */ - BoundBox *bb = BKE_object_boundbox_get(ob); - float min[3], max[3]; - INIT_MINMAX(min, max); - for (int i = 0; i < 8; ++i) { - float vec[3]; - copy_v3_v3(vec, bb->vec[i]); - mul_m4_v3(ob->obmat, vec); - minmax_v3v3_v3(min, max, vec); - } - - EEVEE_BoundBox *aabb = &shcaster->bbox; - add_v3_v3v3(aabb->center, min, max); - mul_v3_fl(aabb->center, 0.5f); - sub_v3_v3v3(aabb->halfdim, aabb->center, max); - - aabb->halfdim[0] = fabsf(aabb->halfdim[0]); - aabb->halfdim[1] = fabsf(aabb->halfdim[1]); - aabb->halfdim[2] = fabsf(aabb->halfdim[2]); - - oedata->need_update = false; -} - -void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) -{ - EEVEE_LightsInfo *linfo = sldata->lights; - eGPUTextureFormat shadow_pool_format = GPU_R32F; - - sldata->common_data.la_num_light = linfo->num_light; - - /* Setup enough layers. */ - /* Free textures if number mismatch. */ - if (linfo->num_cube_layer != linfo->cache_num_cube_layer) { - DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_pool); - linfo->cache_num_cube_layer = linfo->num_cube_layer; - linfo->update_flag |= LIGHT_UPDATE_SHADOW_CUBE; - } - - if (linfo->num_cascade_layer != linfo->cache_num_cascade_layer) { - DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_pool); - linfo->cache_num_cascade_layer = linfo->num_cascade_layer; - } - - switch (linfo->shadow_method) { - case SHADOW_ESM: - shadow_pool_format = ((linfo->shadow_high_bitdepth) ? GPU_R32F : GPU_R16F); - break; - case SHADOW_VSM: - shadow_pool_format = ((linfo->shadow_high_bitdepth) ? GPU_RG32F : GPU_RG16F); - break; - default: - BLI_assert(!"Incorrect Shadow Method"); - break; - } - - /* Cubemaps */ - if (!sldata->shadow_cube_target) { - sldata->shadow_cube_target = DRW_texture_create_cube( - linfo->shadow_cube_size, GPU_DEPTH_COMPONENT24, 0, NULL); - sldata->shadow_cube_blur = DRW_texture_create_cube( - linfo->shadow_cube_size, shadow_pool_format, DRW_TEX_FILTER, NULL); - } - GPU_framebuffer_ensure_config( - &sldata->shadow_cube_copy_fb, - {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(sldata->shadow_cube_blur)}); - - if (!sldata->shadow_cube_pool) { - sldata->shadow_cube_pool = DRW_texture_create_2d_array(linfo->shadow_cube_store_size, - linfo->shadow_cube_store_size, - max_ii(1, linfo->num_cube_layer), - shadow_pool_format, - DRW_TEX_FILTER, - NULL); - } - GPU_framebuffer_ensure_config(&sldata->shadow_cube_target_fb, - {GPU_ATTACHMENT_TEXTURE(sldata->shadow_cube_target)}); - GPU_framebuffer_ensure_config( - &sldata->shadow_cube_store_fb, - {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(sldata->shadow_cube_pool)}); - - /* CSM */ - if (!sldata->shadow_cascade_target) { - sldata->shadow_cascade_target = DRW_texture_create_2d_array(linfo->shadow_cascade_size, - linfo->shadow_cascade_size, - MAX_CASCADE_NUM, - GPU_DEPTH_COMPONENT24, - 0, - NULL); - sldata->shadow_cascade_blur = DRW_texture_create_2d_array(linfo->shadow_cascade_size, - linfo->shadow_cascade_size, - MAX_CASCADE_NUM, - shadow_pool_format, - DRW_TEX_FILTER, - NULL); - } - GPU_framebuffer_ensure_config( - &sldata->shadow_cascade_copy_fb, - {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(sldata->shadow_cascade_blur)}); - - if (!sldata->shadow_cascade_pool) { - sldata->shadow_cascade_pool = DRW_texture_create_2d_array(linfo->shadow_cascade_size, - linfo->shadow_cascade_size, - max_ii(1, linfo->num_cascade_layer), - shadow_pool_format, - DRW_TEX_FILTER, - NULL); - } - GPU_framebuffer_ensure_config(&sldata->shadow_cascade_target_fb, - {GPU_ATTACHMENT_TEXTURE(sldata->shadow_cascade_target)}); - GPU_framebuffer_ensure_config( - &sldata->shadow_cascade_store_fb, - {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(sldata->shadow_cascade_pool)}); - - /* Update Lights UBOs. */ - EEVEE_lights_update(sldata, vedata); -} - -float light_attenuation_radius_get(Light *la, float light_threshold) +static float light_attenuation_radius_get(const Light *la, float light_threshold) { if (la->mode & LA_CUSTOM_ATTENUATION) { return la->att_dist; @@ -664,7 +57,7 @@ float light_attenuation_radius_get(Light *la, float light_threshold) return distance; } -static void light_shape_parameters_set(EEVEE_Light *evli, const Light *la, float scale[3]) +static void light_shape_parameters_set(EEVEE_Light *evli, const Light *la, const float scale[3]) { if (la->type == LA_SPOT) { /* Spot size & blend */ @@ -684,7 +77,7 @@ static void light_shape_parameters_set(EEVEE_Light *evli, const Light *la, float } } else if (la->type == LA_SUN) { - evli->radius = max_ff(0.001f, tanf(la->sun_angle / 2.0f)); + evli->radius = max_ff(0.001f, tanf(min_ff(la->sun_angle, DEG2RADF(179.9f)) / 2.0f)); } else { evli->radius = max_ff(0.001f, la->area_size); @@ -774,809 +167,54 @@ static void eevee_light_setup(Object *ob, EEVEE_Light *evli) mul_v3_fl(evli->color, power * la->energy); /* No shadow by default */ - evli->shadowid = -1.0f; -} - -/** - * Special ball distribution: - * Point are distributed in a way that when they are orthogonally - * projected into any plane, the resulting distribution is (close to) - * a uniform disc distribution. - */ -static void sample_ball(int sample_ofs, float radius, float rsample[3]) -{ - double ht_point[3]; - double ht_offset[3] = {0.0, 0.0, 0.0}; - uint ht_primes[3] = {2, 3, 7}; - - BLI_halton_3d(ht_primes, ht_offset, sample_ofs, ht_point); - - float omega = ht_point[1] * 2.0f * M_PI; - - rsample[2] = ht_point[0] * 2.0f - 1.0f; /* cos theta */ - - float r = sqrtf(fmaxf(0.0f, 1.0f - rsample[2] * rsample[2])); /* sin theta */ - - rsample[0] = r * cosf(omega); - rsample[1] = r * sinf(omega); - - radius *= sqrt(sqrt(ht_point[2])); - mul_v3_fl(rsample, radius); -} - -static void sample_rectangle( - int sample_ofs, float x_axis[3], float y_axis[3], float size_x, float size_y, float rsample[3]) -{ - double ht_point[2]; - double ht_offset[2] = {0.0, 0.0}; - uint ht_primes[2] = {2, 3}; - - BLI_halton_2d(ht_primes, ht_offset, sample_ofs, ht_point); - - /* Change ditribution center to be 0,0 */ - ht_point[0] = (ht_point[0] > 0.5f) ? ht_point[0] - 1.0f : ht_point[0]; - ht_point[1] = (ht_point[1] > 0.5f) ? ht_point[1] - 1.0f : ht_point[1]; - - zero_v3(rsample); - madd_v3_v3fl(rsample, x_axis, (ht_point[0] * 2.0f) * size_x); - madd_v3_v3fl(rsample, y_axis, (ht_point[1] * 2.0f) * size_y); -} - -static void sample_ellipse( - int sample_ofs, float x_axis[3], float y_axis[3], float size_x, float size_y, float rsample[3]) -{ - double ht_point[2]; - double ht_offset[2] = {0.0, 0.0}; - uint ht_primes[2] = {2, 3}; - - BLI_halton_2d(ht_primes, ht_offset, sample_ofs, ht_point); - - /* Uniform disc sampling. */ - float omega = ht_point[1] * 2.0f * M_PI; - float r = sqrtf(ht_point[0]); - ht_point[0] = r * cosf(omega) * size_x; - ht_point[1] = r * sinf(omega) * size_y; - - zero_v3(rsample); - madd_v3_v3fl(rsample, x_axis, ht_point[0]); - madd_v3_v3fl(rsample, y_axis, ht_point[1]); -} - -static void shadow_cube_random_position_set(EEVEE_Light *evli, - Light *la, - int sample_ofs, - float ws_sample_pos[3]) -{ - float jitter[3]; - -#ifndef DEBUG_SHADOW_DISTRIBUTION - int i = sample_ofs; -#else - for (int i = 0; i <= sample_ofs; ++i) { -#endif - switch (la->type) { - case LA_AREA: - if (ELEM(la->area_shape, LA_AREA_RECT, LA_AREA_SQUARE)) { - sample_rectangle(i, evli->rightvec, evli->upvec, evli->sizex, evli->sizey, jitter); - } - else { - sample_ellipse(i, evli->rightvec, evli->upvec, evli->sizex, evli->sizey, jitter); - } - break; - default: - sample_ball(i, evli->radius, jitter); - } -#ifdef DEBUG_SHADOW_DISTRIBUTION - float p[3]; - add_v3_v3v3(p, jitter, ws_sample_pos); - DRW_debug_sphere(p, 0.01f, (float[4]){1.0f, (sample_ofs == i) ? 1.0f : 0.0f, 0.0f, 1.0f}); -} -#endif -add_v3_v3(ws_sample_pos, jitter); -} - -static void eevee_shadow_cube_setup(Object *ob, - EEVEE_LightsInfo *linfo, - EEVEE_LightEngineData *led, - int sample_ofs) -{ - EEVEE_ShadowCubeData *sh_data = &led->data.scd; - 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; - Light *la = (Light *)ob->data; - - copy_v3_v3(cube_data->position, ob->obmat[3]); - - if (linfo->soft_shadows) { - shadow_cube_random_position_set(evli, la, sample_ofs, cube_data->position); - } - - ubo_data->bias = 0.05f * la->bias; - ubo_data->near = la->clipsta; - ubo_data->far = 1.0f / (evli->invsqrdist * evli->invsqrdist); - 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->cube_id); - ubo_data->shadow_blur = la->soft * 0.02f; /* Used by translucence shadowmap blur */ - - ubo_data->contact_dist = (la->mode & LA_SHAD_CONTACT) ? la->contact_dist : 0.0f; - ubo_data->contact_bias = 0.05f * la->contact_bias; - ubo_data->contact_spread = la->contact_spread; - ubo_data->contact_thickness = la->contact_thickness; -} - -static void shadow_cascade_random_matrix_set(float mat[4][4], float radius, int sample_ofs) -{ - float jitter[3]; - -#ifndef DEBUG_SHADOW_DISTRIBUTION - int i = sample_ofs; -#else - for (int i = 0; i <= sample_ofs; ++i) { -#endif - sample_ellipse(i, mat[0], mat[1], radius, radius, jitter); -#ifdef DEBUG_SHADOW_DISTRIBUTION - float p[3]; - add_v3_v3v3(p, jitter, mat[2]); - DRW_debug_sphere(p, 0.01f, (float[4]){1.0f, (sample_ofs == i) ? 1.0f : 0.0f, 0.0f, 1.0f}); -} -#endif - -add_v3_v3(mat[2], jitter); -orthogonalize_m4(mat, 2); -} - -#define LERP(t, a, b) ((a) + (t) * ((b) - (a))) - -static double round_to_digits(double value, int digits) -{ - double factor = pow(10.0, digits - ceil(log10(fabs(value)))); - return round(value * factor) / factor; -} - -static void frustum_min_bounding_sphere(const float corners[8][3], - float r_center[3], - float *r_radius) -{ -#if 0 /* Simple solution but waste too much space. */ - float minvec[3], maxvec[3]; - - /* compute the bounding box */ - INIT_MINMAX(minvec, maxvec); - for (int i = 0; i < 8; ++i) { - minmax_v3v3_v3(minvec, maxvec, corners[i]); - } - - /* compute the bounding sphere of this box */ - r_radius = len_v3v3(minvec, maxvec) * 0.5f; - add_v3_v3v3(r_center, minvec, maxvec); - mul_v3_fl(r_center, 0.5f); -#else - /* Find averaged center. */ - zero_v3(r_center); - for (int i = 0; i < 8; ++i) { - add_v3_v3(r_center, corners[i]); - } - mul_v3_fl(r_center, 1.0f / 8.0f); - - /* Search the largest distance from the sphere center. */ - *r_radius = 0.0f; - for (int i = 0; i < 8; ++i) { - float rad = len_squared_v3v3(corners[i], r_center); - if (rad > *r_radius) { - *r_radius = rad; - } - } - - /* TODO try to reduce the radius further by moving the center. - * Remember we need a __stable__ solution! */ - - /* Try to reduce float imprecision leading to shimmering. */ - *r_radius = (float)round_to_digits(sqrtf(*r_radius), 3); -#endif -} - -static void eevee_shadow_cascade_setup(Object *ob, - EEVEE_LightsInfo *linfo, - EEVEE_LightEngineData *led, - DRWView *view, - float view_near, - float view_far, - int sample_ofs) -{ - Light *la = (Light *)ob->data; - - /* Camera Matrices */ - float persinv[4][4], vp_projmat[4][4]; - DRW_view_persmat_get(view, persinv, true); - DRW_view_winmat_get(view, vp_projmat, false); - bool is_persp = DRW_view_is_persp_get(view); - - /* Lights Matrices */ - int cascade_nbr = la->cascade_count; - - EEVEE_ShadowCascadeData *sh_data = &led->data.scad; - 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; - - /* obmat = Object Space > World Space */ - /* viewmat = World Space > View Space */ - float(*viewmat)[4] = sh_data->viewmat; -#if 0 /* done at culling time */ - normalize_m4_m4(viewmat, ob->obmat); -#endif - - if (linfo->soft_shadows) { - shadow_cascade_random_matrix_set(viewmat, evli->radius, sample_ofs); - } - - copy_m4_m4(sh_data->viewinv, viewmat); - invert_m4(viewmat); - - /* The technique consists into splitting - * the view frustum into several sub-frustum - * that are individually receiving one shadow map */ - - float csm_start, csm_end; - - if (is_persp) { - csm_start = view_near; - csm_end = max_ff(view_far, -la->cascade_max_dist); - /* Avoid artifacts */ - csm_end = min_ff(view_near, csm_end); - } - else { - csm_start = -view_far; - csm_end = view_far; - } - - /* init near/far */ - for (int c = 0; c < MAX_CASCADE_NUM; ++c) { - cascade_data->split_start[c] = csm_end; - cascade_data->split_end[c] = csm_end; - } - - /* Compute split planes */ - float splits_start_ndc[MAX_CASCADE_NUM]; - float splits_end_ndc[MAX_CASCADE_NUM]; - - { - /* Nearest plane */ - float p[4] = {1.0f, 1.0f, csm_start, 1.0f}; - /* TODO: we don't need full m4 multiply here */ - mul_m4_v4(vp_projmat, p); - splits_start_ndc[0] = p[2]; - if (is_persp) { - splits_start_ndc[0] /= p[3]; - } - } - - { - /* Farthest plane */ - float p[4] = {1.0f, 1.0f, csm_end, 1.0f}; - /* TODO: we don't need full m4 multiply here */ - mul_m4_v4(vp_projmat, p); - splits_end_ndc[cascade_nbr - 1] = p[2]; - if (is_persp) { - splits_end_ndc[cascade_nbr - 1] /= p[3]; - } - } - - cascade_data->split_start[0] = csm_start; - cascade_data->split_end[cascade_nbr - 1] = csm_end; - - for (int c = 1; c < cascade_nbr; ++c) { - /* View Space */ - float linear_split = LERP(((float)(c) / (float)cascade_nbr), csm_start, csm_end); - float exp_split = csm_start * powf(csm_end / csm_start, (float)(c) / (float)cascade_nbr); - - if (is_persp) { - cascade_data->split_start[c] = LERP(la->cascade_exponent, linear_split, exp_split); - } - else { - cascade_data->split_start[c] = linear_split; - } - cascade_data->split_end[c - 1] = cascade_data->split_start[c]; - - /* Add some overlap for smooth transition */ - cascade_data->split_start[c] = LERP(la->cascade_fade, - cascade_data->split_end[c - 1], - (c > 1) ? cascade_data->split_end[c - 2] : - cascade_data->split_start[0]); - - /* NDC Space */ - { - float p[4] = {1.0f, 1.0f, cascade_data->split_start[c], 1.0f}; - /* TODO: we don't need full m4 multiply here */ - mul_m4_v4(vp_projmat, p); - splits_start_ndc[c] = p[2]; - - if (is_persp) { - splits_start_ndc[c] /= p[3]; - } - } - - { - float p[4] = {1.0f, 1.0f, cascade_data->split_end[c - 1], 1.0f}; - /* TODO: we don't need full m4 multiply here */ - mul_m4_v4(vp_projmat, p); - splits_end_ndc[c - 1] = p[2]; - - if (is_persp) { - splits_end_ndc[c - 1] /= p[3]; - } - } - } - - /* Set last cascade split fade distance into the first split_start. */ - float prev_split = (cascade_nbr > 1) ? cascade_data->split_end[cascade_nbr - 2] : - cascade_data->split_start[0]; - cascade_data->split_start[0] = LERP( - la->cascade_fade, cascade_data->split_end[cascade_nbr - 1], prev_split); - - /* For each cascade */ - for (int c = 0; c < cascade_nbr; ++c) { - float(*projmat)[4] = sh_data->projmat[c]; - /* Given 8 frustum corners */ - float corners[8][3] = { - /* Near Cap */ - {1.0f, -1.0f, splits_start_ndc[c]}, - {-1.0f, -1.0f, splits_start_ndc[c]}, - {-1.0f, 1.0f, splits_start_ndc[c]}, - {1.0f, 1.0f, splits_start_ndc[c]}, - /* Far Cap */ - {1.0f, -1.0f, splits_end_ndc[c]}, - {-1.0f, -1.0f, splits_end_ndc[c]}, - {-1.0f, 1.0f, splits_end_ndc[c]}, - {1.0f, 1.0f, splits_end_ndc[c]}, - }; - - /* Transform them into world space */ - for (int i = 0; i < 8; ++i) { - mul_project_m4_v3(persinv, corners[i]); - } - - float center[3]; - frustum_min_bounding_sphere(corners, center, &(sh_data->radius[c])); - -#ifdef DEBUG_CSM - float dbg_col[4] = {0.0f, 0.0f, 0.0f, 1.0f}; - if (c < 3) { - dbg_col[c] = 1.0f; - } - DRW_debug_bbox((BoundBox *)&corners, dbg_col); - DRW_debug_sphere(center, sh_data->radius[c], dbg_col); -#endif - - /* Project into lightspace */ - mul_m4_v3(viewmat, center); - - /* Snap projection center to nearest texel to cancel shimmering. */ - float shadow_origin[2], shadow_texco[2]; - /* Light to texture space. */ - mul_v2_v2fl(shadow_origin, center, linfo->shadow_cascade_size / (2.0f * sh_data->radius[c])); - - /* Find the nearest texel. */ - shadow_texco[0] = roundf(shadow_origin[0]); - shadow_texco[1] = roundf(shadow_origin[1]); - - /* Compute offset. */ - sub_v2_v2(shadow_texco, shadow_origin); - /* Texture to light space. */ - mul_v2_fl(shadow_texco, (2.0f * sh_data->radius[c]) / linfo->shadow_cascade_size); - - /* Apply offset. */ - add_v2_v2(center, shadow_texco); - - /* Expand the projection to cover frustum range */ - rctf rect_cascade; - BLI_rctf_init_pt_radius(&rect_cascade, center, sh_data->radius[c]); - orthographic_m4(projmat, - rect_cascade.xmin, - rect_cascade.xmax, - rect_cascade.ymin, - rect_cascade.ymax, - la->clipsta, - la->clipend); - - mul_m4_m4m4(sh_data->viewprojmat[c], projmat, viewmat); - mul_m4_m4m4(cascade_data->shadowmat[c], texcomat, sh_data->viewprojmat[c]); - -#ifdef DEBUG_CSM - DRW_debug_m4_as_bbox(sh_data->viewprojmat[c], dbg_col, true); -#endif - } - - 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->shadow_blur = la->soft * 0.02f; /* Used by translucence shadowmap blur */ - - ubo_data->contact_dist = (la->mode & LA_SHAD_CONTACT) ? la->contact_dist : 0.0f; - ubo_data->contact_bias = 0.05f * la->contact_bias; - ubo_data->contact_spread = la->contact_spread; - ubo_data->contact_thickness = la->contact_thickness; + evli->shadow_id = -1.0f; } -/* Used for checking if object is inside the shadow volume. */ -static bool sphere_bbox_intersect(const EEVEE_BoundSphere *bs, const EEVEE_BoundBox *bb) +void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { - /* We are testing using a rougher AABB vs AABB test instead of full AABB vs Sphere. */ - /* TODO test speed with AABB vs Sphere. */ - bool x = fabsf(bb->center[0] - bs->center[0]) <= (bb->halfdim[0] + bs->radius); - bool y = fabsf(bb->center[1] - bs->center[1]) <= (bb->halfdim[1] + bs->radius); - bool z = fabsf(bb->center[2] - bs->center[2]) <= (bb->halfdim[2] + bs->radius); + EEVEE_LightsInfo *linfo = sldata->lights; + linfo->num_light = 0; - return x && y && z; + EEVEE_shadows_cache_init(sldata, vedata); } -void EEVEE_lights_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob) { - EEVEE_StorageList *stl = vedata->stl; - EEVEE_EffectsInfo *effects = stl->effects; EEVEE_LightsInfo *linfo = sldata->lights; - Object *ob; - int i; - char *flag; - EEVEE_ShadowCaster *shcaster; - EEVEE_BoundSphere *bsphere; - EEVEE_ShadowCasterBuffer *frontbuffer = linfo->shcaster_frontbuffer; - EEVEE_ShadowCasterBuffer *backbuffer = linfo->shcaster_backbuffer; - - EEVEE_LightBits update_bits = {{0}}; - if ((linfo->update_flag & LIGHT_UPDATE_SHADOW_CUBE) != 0) { - /* Update all lights. */ - lightbits_set_all(&update_bits, true); - } - else { - /* Search for deleted shadow casters and if shcaster WAS in shadow radius. */ - /* No need to run this if we already update all lights. */ - EEVEE_LightBits past_bits = {{0}}; - EEVEE_LightBits curr_bits = {{0}}; - shcaster = backbuffer->shadow_casters; - flag = backbuffer->flags; - for (i = 0; i < backbuffer->count; ++i, ++flag, ++shcaster) { - /* If the shadowcaster has been deleted or updated. */ - if (*flag != 0) { - /* Add the lights that were intersecting with its BBox. */ - lightbits_or(&past_bits, &shcaster->bits); - } - } - /* Convert old bits to new bits and add result to final update bits. */ - /* NOTE: This might be overkill since all lights are tagged to refresh if - * the light count changes. */ - lightbits_convert(&curr_bits, &past_bits, linfo->new_shadow_id, MAX_LIGHT); - lightbits_or(&update_bits, &curr_bits); - } - - /* Search for updates in current shadow casters. */ - shcaster = frontbuffer->shadow_casters; - flag = frontbuffer->flags; - for (i = 0; i < frontbuffer->count; i++, flag++, shcaster++) { - /* Run intersection checks to fill the bitfields. */ - bsphere = linfo->shadow_bounds; - for (int j = 0; j < linfo->cpu_cube_len; j++, bsphere++) { - bool iter = sphere_bbox_intersect(bsphere, &shcaster->bbox); - lightbits_set_single(&shcaster->bits, j, iter); - } - /* Only add to final bits if objects has been updated. */ - if (*flag != 0) { - lightbits_or(&update_bits, &shcaster->bits); - } - } + const Light *la = (Light *)ob->data; - /* Setup shadow cube in UBO and tag for update if necessary. */ - for (i = 0; (i < MAX_SHADOW_CUBE) && (ob = linfo->shadow_cube_ref[i]); i++) { - EEVEE_LightEngineData *led = EEVEE_light_data_ensure(ob); - - eevee_shadow_cube_setup(ob, linfo, led, effects->taa_current_sample - 1); - if (lightbits_get(&update_bits, i) != 0 || linfo->soft_shadows) { - led->need_update = true; - } + if (linfo->num_light >= MAX_LIGHT) { + printf("Too many lights in the scene !!!\n"); + return; } - /* Resize shcasters buffers if too big. */ - if (frontbuffer->alloc_count - frontbuffer->count > SHADOW_CASTER_ALLOC_CHUNK) { - frontbuffer->alloc_count = (frontbuffer->count / SHADOW_CASTER_ALLOC_CHUNK) * - SHADOW_CASTER_ALLOC_CHUNK; - frontbuffer->alloc_count += (frontbuffer->count % SHADOW_CASTER_ALLOC_CHUNK != 0) ? - SHADOW_CASTER_ALLOC_CHUNK : - 0; - frontbuffer->shadow_casters = MEM_reallocN( - frontbuffer->shadow_casters, sizeof(EEVEE_ShadowCaster) * frontbuffer->alloc_count); - frontbuffer->flags = MEM_reallocN(frontbuffer->flags, - sizeof(EEVEE_ShadowCaster) * frontbuffer->alloc_count); + /* Early out if light has no power. */ + if (la->energy == 0.0f || is_zero_v3(&la->r)) { + return; } -} - -static void eevee_ensure_cube_views(float near, float far, const float pos[3], DRWView *view[6]) -{ - float winmat[4][4], viewmat[4][4]; - perspective_m4(winmat, -near, near, -near, near, near, far); - for (int i = 0; i < 6; i++) { - unit_m4(viewmat); - negate_v3_v3(viewmat[3], pos); - mul_m4_m4m4(viewmat, cubefacemat[i], viewmat); + EEVEE_Light *evli = linfo->light_data + linfo->num_light; + eevee_light_setup(ob, evli); - if (view[i] == NULL) { - view[i] = DRW_view_create(viewmat, winmat, NULL, NULL, NULL); + if (la->mode & LA_SHADOW) { + if (la->type == LA_SUN) { + EEVEE_shadows_cascade_add(linfo, evli, ob); } - else { - DRW_view_update(view[i], viewmat, winmat, NULL, NULL); + else if (ELEM(la->type, LA_SPOT, LA_LOCAL, LA_AREA)) { + EEVEE_shadows_cube_add(linfo, evli, ob); } } -} -static void eevee_ensure_cascade_views(EEVEE_ShadowCascadeData *cascade_data, - int cascade_count, - DRWView *view[4]) -{ - for (int i = 0; i < cascade_count; i++) { - if (view[i] == NULL) { - view[i] = DRW_view_create(cascade_data->viewmat, cascade_data->projmat[i], NULL, NULL, NULL); - } - else { - DRW_view_update(view[i], cascade_data->viewmat, cascade_data->projmat[i], NULL, NULL); - } - } + linfo->num_light++; } -/* this refresh lights shadow buffers */ -void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, DRWView *view) +void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { - EEVEE_PassList *psl = vedata->psl; - EEVEE_StorageList *stl = vedata->stl; - EEVEE_EffectsInfo *effects = stl->effects; - EEVEE_PrivateData *g_data = stl->g_data; EEVEE_LightsInfo *linfo = sldata->lights; - const DRWContextState *draw_ctx = DRW_context_state_get(); - const float light_threshold = draw_ctx->scene->eevee.light_threshold; - Object *ob; - int i; - - int saved_ray_type = sldata->common_data.ray_type; - - /* TODO: make it optional if we don't draw shadows. */ - sldata->common_data.ray_type = EEVEE_RAY_SHADOW; - DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data); - - /* Precompute all shadow/view test before rendering and trashing the culling cache. */ - bool cube_visible[MAX_SHADOW_CUBE]; - for (i = 0; (ob = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) { - Light *la = (Light *)ob->data; - BoundSphere bsphere = { - .center = {ob->obmat[3][0], ob->obmat[3][1], ob->obmat[3][2]}, - .radius = light_attenuation_radius_get(la, light_threshold), - }; - cube_visible[i] = DRW_culling_sphere_test(view, &bsphere); - } - - bool cascade_visible[MAX_SHADOW_CASCADE]; - for (i = 0; (ob = linfo->shadow_cascade_ref[i]) && (i < MAX_SHADOW_CASCADE); i++) { - EEVEE_LightEngineData *led = EEVEE_light_data_get(ob); - EEVEE_ShadowCascadeData *sh_data = &led->data.scad; - float plane[4]; - normalize_m4_m4(sh_data->viewmat, ob->obmat); - plane_from_point_normal_v3(plane, sh_data->viewmat[3], sh_data->viewmat[2]); - /* TODO: check against near/far instead of "local Z = 0" plane. - * Or even the cascades AABB. */ - cascade_visible[i] = DRW_culling_plane_test(view, plane); - } - - /* Cube Shadow Maps */ - DRW_stats_group_start("Cube Shadow Maps"); - /* Render each shadow to one layer of the array */ - for (i = 0; (ob = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) { - EEVEE_LightEngineData *led = EEVEE_light_data_ensure(ob); - Light *la = (Light *)ob->data; - - if (!led->need_update || !cube_visible[i]) { - continue; - } - - EEVEE_ShadowRender *srd = &linfo->shadow_render_data; - EEVEE_ShadowCubeData *evscd = &led->data.scd; - EEVEE_ShadowCube *cube_data = linfo->shadow_cube_data + evscd->cube_id; - - srd->clip_near = la->clipsta; - srd->clip_far = light_attenuation_radius_get(la, light_threshold); - srd->stored_texel_size = 1.0 / (float)linfo->shadow_cube_store_size; - srd->exponent = la->bleedexp; - - eevee_ensure_cube_views( - srd->clip_near, srd->clip_far, cube_data->position, g_data->cube_views); - - /* Render shadow cube */ - /* Render 6 faces separately: seems to be faster for the general case. - * The only time it's more beneficial is when the CPU culling overhead - * outweigh the instancing overhead. which is rarely the case. */ - for (int j = 0; j < 6; j++) { - DRW_view_set_active(g_data->cube_views[j]); - - GPU_framebuffer_texture_cubeface_attach( - sldata->shadow_cube_target_fb, sldata->shadow_cube_target, 0, j, 0); - GPU_framebuffer_bind(sldata->shadow_cube_target_fb); - GPU_framebuffer_clear_depth(sldata->shadow_cube_target_fb, 1.0f); - DRW_draw_pass(psl->shadow_pass); - } - - /* 0.001f is arbitrary, but it should be relatively small so that filter size is not too big. - */ - float filter_texture_size = la->soft * 0.001f; - float filter_pixel_size = ceil(filter_texture_size / srd->cube_texel_size); - - /* TODO: OPTI: Don't do this intermediate step if no filter is needed. */ - { - srd->filter_size[0] = srd->cube_texel_size * ((filter_pixel_size > 1.0f) ? 1.5f : 0.0f); - srd->view_count = 6; - srd->base_id = 0; - DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd); - - /* Copy using a small 3x3 box filter */ - GPU_framebuffer_bind(sldata->shadow_cube_copy_fb); - DRW_draw_pass(psl->shadow_cube_copy_pass); - } - /* Push it to shadowmap array */ - { - /* Adjust constants if concentric samples change. */ - const float max_filter_size = 7.5f; - const float magic = 4.5f; /* Dunno why but that works. */ - const int max_sample = 256; - - if (filter_pixel_size > 2.0f) { - srd->filter_size[0] = srd->cube_texel_size * max_filter_size * magic; - filter_pixel_size = max_ff(0.0f, filter_pixel_size - 3.0f); - /* Compute number of concentric samples. Depends directly on filter size. */ - float pix_size_sqr = filter_pixel_size * filter_pixel_size; - srd->shadow_samples_len[0] = min_ii( - max_sample, 4 + 8 * (int)filter_pixel_size + 4 * (int)(pix_size_sqr)); - } - else { - srd->filter_size[0] = 0.0f; - srd->shadow_samples_len[0] = 4; - } - srd->view_count = 1; - srd->base_id = evscd->layer_id; - srd->shadow_samples_len_inv[0] = 1.0f / (float)srd->shadow_samples_len[0]; - DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd); - - DRWPass *store_pass = eevee_lights_cube_store_pass_get( - psl, sldata, linfo->shadow_method, srd->shadow_samples_len[0]); - - GPU_framebuffer_bind(sldata->shadow_cube_store_fb); - DRW_draw_pass(store_pass); - } - - if (linfo->soft_shadows == false) { - led->need_update = false; - } - } - linfo->update_flag &= ~LIGHT_UPDATE_SHADOW_CUBE; - DRW_stats_group_end(); - - float near = DRW_view_near_distance_get(view); - float far = DRW_view_far_distance_get(view); - - /* Cascaded Shadow Maps */ - DRW_stats_group_start("Cascaded Shadow Maps"); - for (i = 0; (ob = linfo->shadow_cascade_ref[i]) && (i < MAX_SHADOW_CASCADE); i++) { - if (!cascade_visible[i]) { - continue; - } - - EEVEE_LightEngineData *led = EEVEE_light_data_ensure(ob); - Light *la = (Light *)ob->data; - - EEVEE_ShadowCascadeData *evscd = &led->data.scad; - EEVEE_ShadowRender *srd = &linfo->shadow_render_data; - - srd->clip_near = la->clipsta; - srd->clip_far = la->clipend; - srd->view_count = la->cascade_count; - srd->stored_texel_size = 1.0 / (float)linfo->shadow_cascade_size; - - DRW_uniformbuffer_update(sldata->shadow_render_ubo, &linfo->shadow_render_data); - - eevee_shadow_cascade_setup(ob, linfo, led, view, near, far, effects->taa_current_sample - 1); - - /* Meh, Reusing the cube views. */ - BLI_assert(MAX_CASCADE_NUM <= 6); - eevee_ensure_cascade_views(evscd, la->cascade_count, g_data->cube_views); - - /* Render shadow cascades */ - /* Render cascade separately: seems to be faster for the general case. - * The only time it's more beneficial is when the CPU culling overhead - * outweigh the instancing overhead. which is rarely the case. */ - for (int j = 0; j < la->cascade_count; j++) { - DRW_view_set_active(g_data->cube_views[j]); - - GPU_framebuffer_texture_layer_attach( - sldata->shadow_cascade_target_fb, sldata->shadow_cascade_target, 0, j, 0); - GPU_framebuffer_bind(sldata->shadow_cascade_target_fb); - GPU_framebuffer_clear_depth(sldata->shadow_cascade_target_fb, 1.0f); - DRW_draw_pass(psl->shadow_pass); - } - /* Copy using a small 3x3 box filter */ - { - /* NOTE: We always do it in the case of CSM because of artifacts in the farthest cascade. */ - copy_v4_fl(srd->filter_size, srd->stored_texel_size); - srd->base_id = 0; - DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd); - - GPU_framebuffer_bind(sldata->shadow_cascade_copy_fb); - DRW_draw_pass(psl->shadow_cascade_copy_pass); - } - /* Push it to shadowmap array and blur more */ - { - int max_pass_sample = 0; - - for (int j = 0; j < la->cascade_count; j++) { - /* 0.01f factor to convert to percentage */ - float filter_texture_size = la->soft * 0.01f / evscd->radius[j]; - float filter_pixel_size = ceil(linfo->shadow_cascade_size * filter_texture_size); - /* Adjust constants if concentric samples change. */ - const float max_filter_size = 7.5f; - const float magic = 3.2f; /* Arbitrary: less banding */ - const int max_sample = 256; - - if (filter_pixel_size > 2.0f) { - srd->filter_size[j] = srd->stored_texel_size * max_filter_size * magic; - filter_pixel_size = max_ff(0.0f, filter_pixel_size - 3.0f); - /* Compute number of concentric samples. Depends directly on filter size. */ - float pix_size_sqr = filter_pixel_size * filter_pixel_size; - srd->shadow_samples_len[j] = min_ii( - max_sample, 4 + 8 * (int)filter_pixel_size + 4 * (int)(pix_size_sqr)); - } - else { - srd->filter_size[j] = 0.0f; - srd->shadow_samples_len[j] = 4; - } - srd->shadow_samples_len_inv[j] = 1.0f / (float)srd->shadow_samples_len[j]; - max_pass_sample = max_ii(max_pass_sample, srd->shadow_samples_len[j]); - } - srd->base_id = evscd->layer_id; - DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd); - - /* XXX(fclem) this create drawcalls outside of cache generation. */ - DRWPass *store_pass = eevee_lights_cascade_store_pass_get( - psl, sldata, linfo->shadow_method, max_pass_sample); - - GPU_framebuffer_bind(sldata->shadow_cascade_store_fb); - DRW_draw_pass(store_pass); - } - } - - DRW_stats_group_end(); - - DRW_view_set_active(view); + sldata->common_data.la_num_light = linfo->num_light; DRW_uniformbuffer_update(sldata->light_ubo, &linfo->light_data); - DRW_uniformbuffer_update(sldata->shadow_ubo, &linfo->shadow_data); /* Update all data at once */ - - sldata->common_data.ray_type = saved_ray_type; - DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data); -} -void EEVEE_lights_free(void) -{ - DRW_SHADER_FREE_SAFE(e_data.shadow_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_cube_high_sh[i]); - DRW_SHADER_FREE_SAFE(e_data.shadow_store_cascade_sh[i]); - DRW_SHADER_FREE_SAFE(e_data.shadow_store_cascade_high_sh[i]); - DRW_SHADER_FREE_SAFE(e_data.shadow_copy_cube_sh[i]); - DRW_SHADER_FREE_SAFE(e_data.shadow_copy_cascade_sh[i]); - } + EEVEE_shadows_update(sldata, vedata); } diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index 738745f3072..99bfba0d203 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -63,8 +63,6 @@ static struct { struct GPUTexture *util_tex; struct GPUTexture *noise_tex; - struct GPUUniformBuffer *dummy_sss_profile; - uint sss_count; float alpha_hash_offset; @@ -273,21 +271,6 @@ 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; @@ -322,23 +305,8 @@ static char *eevee_get_defines(int options) if ((options & VAR_MAT_REFRACT) != 0) { BLI_dynstr_append(ds, "#define USE_REFRACTION\n"); } - if ((options & VAR_MAT_SSSALBED) != 0) { - BLI_dynstr_append(ds, "#define USE_SSS_ALBEDO\n"); - } - if ((options & VAR_MAT_TRANSLUC) != 0) { - BLI_dynstr_append(ds, "#define USE_TRANSLUCENCY\n"); - } - if ((options & VAR_MAT_VSM) != 0) { - BLI_dynstr_append(ds, "#define SHADOW_VSM\n"); - } - if ((options & VAR_MAT_ESM) != 0) { - BLI_dynstr_append(ds, "#define SHADOW_ESM\n"); - } if ((options & VAR_MAT_LOOKDEV) != 0) { - /* Auto config shadow method. Avoid more permutation. */ - BLI_assert((options & (VAR_MAT_VSM | VAR_MAT_ESM)) == 0); BLI_dynstr_append(ds, "#define LOOKDEV\n"); - BLI_dynstr_append(ds, "#define SHADOW_ESM\n"); } str = BLI_dynstr_get_cstring(ds); @@ -435,11 +403,6 @@ static void create_default_shader(int options) MEM_freeN(frag_str); } -static void eevee_init_dummys(void) -{ - e_data.dummy_sss_profile = GPU_material_create_sss_profile_ubo(); -} - static void eevee_init_noise_texture(void) { e_data.noise_tex = DRW_texture_create_2d(64, 64, GPU_RGBA16F, 0, (float *)blue_noise); @@ -631,7 +594,6 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, eevee_init_util_texture(); eevee_init_noise_texture(); - eevee_init_dummys(); } if (!DRW_state_is_image_render() && ((stl->effects->enabled_effects & EFFECT_TAA) == 0)) { @@ -731,22 +693,15 @@ struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, World * struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene, Material *ma, - EEVEE_Data *vedata, + EEVEE_Data *UNUSED(vedata), bool use_blend, - bool use_refract, - bool use_translucency, - int shadow_method) + bool use_refract) { - EEVEE_EffectsInfo *effects = vedata->stl->effects; const void *engine = &DRW_engine_viewport_eevee_type; int options = VAR_MAT_MESH; SET_FLAG_FROM_TEST(options, use_blend, VAR_MAT_BLEND); SET_FLAG_FROM_TEST(options, use_refract, VAR_MAT_REFRACT); - SET_FLAG_FROM_TEST(options, effects->sss_separate_albedo, VAR_MAT_SSSALBED); - SET_FLAG_FROM_TEST(options, use_translucency, VAR_MAT_TRANSLUC); - - options |= eevee_material_shadow_option(shadow_method); GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true); if (mat) { @@ -835,13 +790,11 @@ struct GPUMaterial *EEVEE_material_mesh_depth_get(struct Scene *scene, return mat; } -struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma, int shadow_method) +struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma) { 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 = DRW_shader_find_from_material(ma, engine, options, true); if (mat) { return mat; @@ -872,8 +825,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_create(EEVEE_ViewLaye DRWPass *pass, bool is_hair, bool use_blend, - bool use_ssr, - int shadow_method) + bool use_ssr) { static int ssr_id; ssr_id = (use_ssr) ? 1 : -1; @@ -882,8 +834,6 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_create(EEVEE_ViewLaye SET_FLAG_FROM_TEST(options, is_hair, VAR_MAT_HAIR); SET_FLAG_FROM_TEST(options, use_blend, VAR_MAT_BLEND); - options |= eevee_material_shadow_option(shadow_method); - if (e_data.default_lit[options] == NULL) { create_default_shader(options); } @@ -903,8 +853,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_get(EEVEE_ViewLayerDa ParticleSystem *psys, ModifierData *md, bool is_hair, - bool use_ssr, - int shadow_method) + bool use_ssr) { static int ssr_id; ssr_id = (use_ssr) ? 1 : -1; @@ -916,8 +865,6 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_get(EEVEE_ViewLayerDa SET_FLAG_FROM_TEST(options, is_hair, VAR_MAT_HAIR); - options |= eevee_material_shadow_option(shadow_method); - if (e_data.default_lit[options] == NULL) { create_default_shader(options); } @@ -1164,7 +1111,6 @@ static void material_opaque(Material *ma, Scene *scene = draw_ctx->scene; EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; - EEVEE_LightsInfo *linfo = sldata->lights; bool use_diffuse, use_glossy, use_refract; float *color_p = &ma->r; @@ -1186,11 +1132,8 @@ static void material_opaque(Material *ma, *shgrp_depth_clip = emsg->depth_clip_grp; /* This will have been created already, just perform a lookup. */ - *gpumat = - (use_gpumat) ? - EEVEE_material_mesh_get( - scene, ma, vedata, false, use_ssrefract, use_translucency, linfo->shadow_method) : - NULL; + *gpumat = (use_gpumat) ? EEVEE_material_mesh_get(scene, ma, vedata, false, use_ssrefract) : + NULL; *gpumat_depth = (use_gpumat) ? EEVEE_material_mesh_depth_get( scene, ma, (ma->blend_method == MA_BM_HASHED), false) : NULL; @@ -1203,8 +1146,7 @@ static void material_opaque(Material *ma, static float half = 0.5f; /* Shading */ - *gpumat = EEVEE_material_mesh_get( - scene, ma, vedata, false, use_ssrefract, use_translucency, linfo->shadow_method); + *gpumat = EEVEE_material_mesh_get(scene, ma, vedata, false, use_ssrefract); eGPUMaterialStatus status_mat_surface = GPU_material_status(*gpumat); @@ -1311,15 +1253,15 @@ static void material_opaque(Material *ma, *gpumat, stl->effects->sss_sample_count, &sss_tex_profile); if (sss_profile) { - if (use_translucency) { - DRW_shgroup_uniform_block(*shgrp, "sssProfile", sss_profile); - DRW_shgroup_uniform_texture(*shgrp, "sssTexProfile", sss_tex_profile); - } - /* Limit of 8 bit stencil buffer. ID 255 is refraction. */ if (e_data.sss_count < 254) { - DRW_shgroup_stencil_mask(*shgrp, e_data.sss_count + 1); - EEVEE_subsurface_add_pass(sldata, vedata, e_data.sss_count + 1, sss_profile); + int sss_id = e_data.sss_count + 1; + DRW_shgroup_stencil_mask(*shgrp, sss_id); + EEVEE_subsurface_add_pass(sldata, vedata, sss_id, sss_profile); + if (use_translucency) { + EEVEE_subsurface_translucency_add_pass( + sldata, vedata, sss_id, sss_profile, sss_tex_profile); + } e_data.sss_count++; } else { @@ -1327,19 +1269,6 @@ static void material_opaque(Material *ma, printf("Error: Too many different Subsurface shader in the scene.\n"); } } - else { - if (use_translucency) { - /* NOTE: This is a nasty workaround, because the sss profile might not have been - * generated but the UBO is still declared in this case even if not used. - * But rendering without a bound UBO might result in crashes on certain platform. */ - DRW_shgroup_uniform_block(*shgrp, "sssProfile", e_data.dummy_sss_profile); - } - } - } - else { - if (use_translucency) { - DRW_shgroup_uniform_block(*shgrp, "sssProfile", e_data.dummy_sss_profile); - } } break; } @@ -1360,8 +1289,7 @@ static void material_opaque(Material *ma, /* Fallback to default shader */ if (*shgrp == NULL) { bool use_ssr = ((effects->enabled_effects & EFFECT_SSR) != 0); - *shgrp = EEVEE_default_shading_group_get( - sldata, vedata, NULL, NULL, NULL, false, use_ssr, linfo->shadow_method); + *shgrp = EEVEE_default_shading_group_get(sldata, vedata, NULL, NULL, NULL, false, use_ssr); 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); @@ -1401,7 +1329,6 @@ static void material_transparent(Material *ma, Scene *scene = draw_ctx->scene; EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; - EEVEE_LightsInfo *linfo = sldata->lights; const bool do_cull = (ma->blend_flag & MA_BL_CULL_BACKFACE) != 0; const bool use_ssrefract = (((ma->blend_flag & MA_BL_SS_REFRACTION) != 0) && @@ -1417,8 +1344,7 @@ static void material_transparent(Material *ma, static float half = 0.5f; /* Shading */ - *gpumat = EEVEE_material_mesh_get( - scene, ma, vedata, true, use_ssrefract, false, linfo->shadow_method); + *gpumat = EEVEE_material_mesh_get(scene, ma, vedata, true, use_ssrefract); switch (GPU_material_status(*gpumat)) { case GPU_MAT_SUCCESS: { @@ -1461,7 +1387,7 @@ static void material_transparent(Material *ma, /* Fallback to default shader */ if (*shgrp == NULL) { *shgrp = EEVEE_default_shading_group_create( - sldata, vedata, psl->transparent_pass, false, true, false, linfo->shadow_method); + sldata, vedata, psl->transparent_pass, false, true, false); 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); @@ -1650,18 +1576,18 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, struct GPUMaterial *gpumat; switch (ma_array[i]->blend_shadow) { case MA_BS_SOLID: - EEVEE_lights_cache_shcaster_add(sldata, stl, mat_geom[i], ob); + EEVEE_shadows_caster_add(sldata, stl, mat_geom[i], ob); *cast_shadow = true; break; case MA_BS_CLIP: gpumat = EEVEE_material_mesh_depth_get(scene, ma_array[i], false, true); - EEVEE_lights_cache_shcaster_material_add( + EEVEE_shadows_caster_material_add( sldata, psl, gpumat, mat_geom[i], ob, &ma_array[i]->alpha_threshold); *cast_shadow = true; break; case MA_BS_HASHED: gpumat = EEVEE_material_mesh_depth_get(scene, ma_array[i], true, true); - EEVEE_lights_cache_shcaster_material_add(sldata, psl, gpumat, mat_geom[i], ob, NULL); + EEVEE_shadows_caster_material_add(sldata, psl, gpumat, mat_geom[i], ob, NULL); *cast_shadow = true; break; case MA_BS_NONE: @@ -1728,8 +1654,7 @@ void EEVEE_hair_cache_populate(EEVEE_Data *vedata, static float half = 0.5f; static float error_col[3] = {1.0f, 0.0f, 1.0f}; static float compile_col[3] = {0.5f, 0.5f, 0.5f}; - struct GPUMaterial *gpumat = EEVEE_material_hair_get( - scene, ma, sldata->lights->shadow_method); + struct GPUMaterial *gpumat = EEVEE_material_hair_get(scene, ma); switch (GPU_material_status(gpumat)) { case GPU_MAT_SUCCESS: { @@ -1774,8 +1699,7 @@ void EEVEE_hair_cache_populate(EEVEE_Data *vedata, /* Fallback to default shader */ if (shgrp == NULL) { - shgrp = EEVEE_default_shading_group_get( - sldata, vedata, ob, psys, md, true, use_ssr, sldata->lights->shadow_method); + shgrp = EEVEE_default_shading_group_get(sldata, vedata, ob, psys, md, true, use_ssr); 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); @@ -1819,14 +1743,16 @@ void EEVEE_materials_free(void) DRW_SHADER_FREE_SAFE(e_data.update_noise_sh); DRW_TEXTURE_FREE_SAFE(e_data.util_tex); DRW_TEXTURE_FREE_SAFE(e_data.noise_tex); - DRW_UBO_FREE_SAFE(e_data.dummy_sss_profile); } -void EEVEE_draw_default_passes(EEVEE_PassList *psl) +void EEVEE_materials_draw_opaque(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_PassList *psl) { for (int i = 0; i < VAR_MAT_MAX; ++i) { if (psl->default_pass[i]) { DRW_draw_pass(psl->default_pass[i]); } } + + DRW_draw_pass(psl->material_pass); + DRW_draw_pass(psl->material_pass_cull); } diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index fefdaef970a..28a8983cfee 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -23,9 +23,12 @@ #ifndef __EEVEE_PRIVATE_H__ #define __EEVEE_PRIVATE_H__ +#include "DRW_render.h" + +#include "BLI_bitmap.h" + #include "DNA_lightprobe_types.h" -struct EEVEE_BoundSphere; struct EEVEE_ShadowCasterBuffer; struct GPUFrameBuffer; struct Object; @@ -39,11 +42,13 @@ extern struct DrawEngineType draw_engine_eevee_type; #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_CASCADE_NUM 4 -#define MAX_SHADOW 256 /* TODO : Make this depends on GL_MAX_ARRAY_TEXTURE_LAYERS */ +#define MAX_SHADOW 128 /* 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 +// #define DEBUG_SHADOW_DISTRIBUTION + /* Only define one of these. */ // #define IRRADIANCE_SH_L2 // #define IRRADIANCE_CUBEMAP @@ -150,14 +155,12 @@ enum { VAR_MAT_PROBE = (1 << 1), VAR_MAT_HAIR = (1 << 2), VAR_MAT_BLEND = (1 << 3), - VAR_MAT_VSM = (1 << 4), - VAR_MAT_ESM = (1 << 5), - VAR_MAT_VOLUME = (1 << 6), - VAR_MAT_LOOKDEV = (1 << 7), + VAR_MAT_VOLUME = (1 << 4), + VAR_MAT_LOOKDEV = (1 << 5), /* Max number of variation */ /* IMPORTANT : Leave it last and set * it's value accordingly. */ - VAR_MAT_MAX = (1 << 8), + VAR_MAT_MAX = (1 << 6), /* These are options that are not counted in VAR_MAT_MAX * because they are not cumulative with the others above. */ VAR_MAT_CLIP = (1 << 9), @@ -165,8 +168,6 @@ enum { VAR_MAT_MULT = (1 << 11), VAR_MAT_SHADOW = (1 << 12), VAR_MAT_REFRACT = (1 << 13), - VAR_MAT_TRANSLUC = (1 << 15), - VAR_MAT_SSSALBED = (1 << 16), }; /* ************ PROBE UBO ************* */ @@ -190,10 +191,6 @@ typedef struct EEVEE_PlanarReflection { /* --------------------------------------- */ -typedef struct EEVEE_BoundSphere { - float center[3], radius; -} EEVEE_BoundSphere; - typedef struct EEVEE_BoundBox { float center[3], halfdim[3]; } EEVEE_BoundBox; @@ -201,12 +198,6 @@ typedef struct EEVEE_BoundBox { typedef struct EEVEE_PassList { /* Shadows */ struct DRWPass *shadow_pass; - struct DRWPass *shadow_cube_copy_pass; - struct DRWPass *shadow_cube_store_pass; - struct DRWPass *shadow_cube_store_high_pass; - struct DRWPass *shadow_cascade_copy_pass; - struct DRWPass *shadow_cascade_store_pass; - struct DRWPass *shadow_cascade_store_high_pass; /* Probes */ struct DRWPass *probe_background; @@ -242,6 +233,7 @@ typedef struct EEVEE_PassList { struct DRWPass *sss_blur_ps; struct DRWPass *sss_resolve_ps; struct DRWPass *sss_accum_ps; + struct DRWPass *sss_translucency_ps; struct DRWPass *color_downsample_ps; struct DRWPass *color_downsample_cube_ps; struct DRWPass *velocity_resolve; @@ -292,6 +284,7 @@ typedef struct EEVEE_FramebufferList { struct GPUFrameBuffer *sss_blit_fb; struct GPUFrameBuffer *sss_resolve_fb; struct GPUFrameBuffer *sss_clear_fb; + struct GPUFrameBuffer *sss_translucency_fb; struct GPUFrameBuffer *sss_accum_fb; struct GPUFrameBuffer *dof_down_fb; struct GPUFrameBuffer *dof_scatter_fb; @@ -368,7 +361,7 @@ typedef struct EEVEE_StorageList { typedef struct EEVEE_Light { float position[3], invsqrdist; float color[3], spec; - float spotsize, spotblend, radius, shadowid; + float spotsize, spotblend, radius, shadow_id; float rightvec[3], sizex; float upvec[3], sizey; float forwardvec[3], light_type; @@ -378,13 +371,13 @@ typedef struct EEVEE_Light { #define LAMPTYPE_AREA_ELLIPSE 100.0f typedef struct EEVEE_Shadow { - float near, far, bias, exp; - float shadow_start, data_start, multi_shadow_count, shadow_blur; + float near, far, bias, type_data_id; float contact_dist, contact_bias, contact_spread, contact_thickness; } EEVEE_Shadow; typedef struct EEVEE_ShadowCube { - float position[3], pad; + float shadowmat[4][4]; + float position[3], _pad0[1]; } EEVEE_ShadowCube; typedef struct EEVEE_ShadowCascade { @@ -392,42 +385,34 @@ typedef struct EEVEE_ShadowCascade { float shadowmat[MAX_CASCADE_NUM][4][4]; float split_start[4]; float split_end[4]; + float shadow_vec[3], tex_id; } EEVEE_ShadowCascade; -typedef struct EEVEE_ShadowRender { - int shadow_samples_len[MAX_CASCADE_NUM]; - float shadow_samples_len_inv[MAX_CASCADE_NUM]; - float filter_size[MAX_CASCADE_NUM]; - int view_count; - int base_id; - float cube_texel_size; - float stored_texel_size; - float clip_near; - float clip_far; - float exponent; - float pad; -} EEVEE_ShadowRender; +typedef struct EEVEE_ShadowCascadeRender { + /* World->Light->NDC : used for rendering the shadow map. */ + float projmat[MAX_CASCADE_NUM][4][4]; + float viewmat[4][4], viewinv[4][4]; + float radius[MAX_CASCADE_NUM]; + float cascade_max_dist; + float cascade_exponent; + float cascade_fade; + int cascade_count; +} EEVEE_ShadowCascadeRender; BLI_STATIC_ASSERT_ALIGN(EEVEE_Light, 16) BLI_STATIC_ASSERT_ALIGN(EEVEE_Shadow, 16) BLI_STATIC_ASSERT_ALIGN(EEVEE_ShadowCube, 16) BLI_STATIC_ASSERT_ALIGN(EEVEE_ShadowCascade, 16) -BLI_STATIC_ASSERT_ALIGN(EEVEE_ShadowRender, 16) - -/* This is just a really long bitflag with special function to access it. */ -#define MAX_LIGHTBITS_FIELDS (MAX_LIGHT / 8) -typedef struct EEVEE_LightBits { - uchar fields[MAX_LIGHTBITS_FIELDS]; -} EEVEE_LightBits; -typedef struct EEVEE_ShadowCaster { - struct EEVEE_LightBits bits; - struct EEVEE_BoundBox bbox; -} EEVEE_ShadowCaster; +BLI_STATIC_ASSERT(sizeof(EEVEE_Shadow) * MAX_SHADOW + + sizeof(EEVEE_ShadowCascade) * MAX_SHADOW_CASCADE + + sizeof(EEVEE_ShadowCube) * MAX_SHADOW_CUBE < + 16384, + "Shadow UBO is too big!!!") typedef struct EEVEE_ShadowCasterBuffer { - struct EEVEE_ShadowCaster *shadow_casters; - char *flags; + struct EEVEE_BoundBox *bbox; + BLI_bitmap *update; uint alloc_count; uint count; } EEVEE_ShadowCasterBuffer; @@ -437,42 +422,31 @@ typedef struct EEVEE_LightsInfo { int num_light, cache_num_light; int num_cube_layer, cache_num_cube_layer; int num_cascade_layer, cache_num_cascade_layer; - int gpu_cube_len, gpu_cascade_len, gpu_shadow_len; - int cpu_cube_len, cpu_cascade_len; - int update_flag; - int shadow_cube_size, shadow_cascade_size, shadow_method; + int cube_len, cascade_len, shadow_len; + int shadow_cube_size, shadow_cascade_size; bool shadow_high_bitdepth, soft_shadows; - int shadow_cube_store_size; - /* List of lights in the scene. */ - /* XXX This is fragile, can get out of sync quickly. */ - struct Object *light_ref[MAX_LIGHT]; - struct Object *shadow_cube_ref[MAX_SHADOW_CUBE]; - struct Object *shadow_cascade_ref[MAX_SHADOW_CASCADE]; /* 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]; + /* Additionnal rendering info for cascade. */ + struct EEVEE_ShadowCascadeRender shadow_cascade_render[MAX_SHADOW_CASCADE]; + /* Back index in light_data. */ + uchar shadow_cube_light_indices[MAX_SHADOW_CUBE]; + uchar shadow_cascade_light_indices[MAX_SHADOW_CASCADE]; + /* Update bitmap. */ + BLI_bitmap sh_cube_update[BLI_BITMAP_SIZE(MAX_SHADOW_CUBE)]; /* Lights tracking */ - int new_shadow_id[MAX_LIGHT]; /* To be able to convert old bitfield to new bitfield */ - struct EEVEE_BoundSphere shadow_bounds[MAX_LIGHT]; /* Tightly packed light bounds */ - /* Pointers only. */ - struct EEVEE_ShadowCasterBuffer *shcaster_frontbuffer; - struct EEVEE_ShadowCasterBuffer *shcaster_backbuffer; + struct BoundSphere shadow_bounds[MAX_LIGHT]; /* Tightly packed light bounds */ + /* List of bbox and update bitmap. Double buffered. */ + struct EEVEE_ShadowCasterBuffer *shcaster_frontbuffer, *shcaster_backbuffer; + /* AABB of all shadow casters combined. */ + struct { + float min[3], max[3]; + } shcaster_aabb; } EEVEE_LightsInfo; -/* EEVEE_LightsInfo->shadow_casters_flag */ -enum { - SHADOW_CASTER_PRUNED = (1 << 0), - SHADOW_CASTER_UPDATED = (1 << 1), -}; - -/* EEVEE_LightsInfo->update_flag */ -enum { - LIGHT_UPDATE_SHADOW_CUBE = (1 << 0), -}; - /* ************ PROBE DATA ************* */ typedef struct EEVEE_LightProbeVisTest { struct Collection *collection; /* Skip test if NULL */ @@ -552,8 +526,8 @@ typedef struct EEVEE_EffectsInfo { bool swap_double_buffer; /* SSSS */ int sss_sample_count; - bool sss_separate_albedo; - struct GPUTexture *sss_data; /* Textures from pool */ + struct GPUTexture *sss_irradiance; /* Textures from pool */ + struct GPUTexture *sss_radius; struct GPUTexture *sss_albedo; struct GPUTexture *sss_blur; struct GPUTexture *sss_stencil; @@ -711,20 +685,10 @@ typedef struct EEVEE_ViewLayerData { struct GPUUniformBuffer *light_ubo; struct GPUUniformBuffer *shadow_ubo; - struct GPUUniformBuffer *shadow_render_ubo; struct GPUUniformBuffer *shadow_samples_ubo; - struct GPUFrameBuffer *shadow_cube_target_fb; - struct GPUFrameBuffer *shadow_cube_store_fb; - struct GPUFrameBuffer *shadow_cube_copy_fb; - struct GPUFrameBuffer *shadow_cascade_target_fb; - struct GPUFrameBuffer *shadow_cascade_store_fb; - struct GPUFrameBuffer *shadow_cascade_copy_fb; - - struct GPUTexture *shadow_cube_target; - struct GPUTexture *shadow_cube_blur; - struct GPUTexture *shadow_cascade_target; - struct GPUTexture *shadow_cascade_blur; + struct GPUFrameBuffer *shadow_fb; + struct GPUTexture *shadow_cube_pool; struct GPUTexture *shadow_cascade_pool; @@ -746,23 +710,6 @@ typedef struct EEVEE_ViewLayerData { /* ************ OBJECT DATA ************ */ -typedef struct EEVEE_LightData { - short light_id, shadow_id; -} EEVEE_LightData; - -typedef struct EEVEE_ShadowCubeData { - short light_id, shadow_id, cube_id, layer_id; -} EEVEE_ShadowCubeData; - -typedef struct EEVEE_ShadowCascadeData { - short light_id, shadow_id, cascade_id, layer_id; - /* World->Light->NDC : used for rendering the shadow map. */ - float viewprojmat[MAX_CASCADE_NUM][4][4]; /* Could be removed. */ - float projmat[MAX_CASCADE_NUM][4][4]; - float viewmat[4][4], viewinv[4][4]; - float radius[MAX_CASCADE_NUM]; -} EEVEE_ShadowCascadeData; - /* These are the structs stored inside Objects. * It works even if the object is in multiple layers * because we don't get the same "Object *" for each layer. */ @@ -770,13 +717,6 @@ typedef struct EEVEE_LightEngineData { DrawData dd; bool need_update; - /* This needs to be out of the union to avoid undefined behavior. */ - short prev_cube_shadow_id; - union { - struct EEVEE_LightData ld; - struct EEVEE_ShadowCubeData scd; - struct EEVEE_ShadowCascadeData scad; - } data; } EEVEE_LightEngineData; typedef struct EEVEE_LightProbeEngineData { @@ -895,43 +835,67 @@ void EEVEE_materials_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat 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); -struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene, - Material *ma, - EEVEE_Data *vedata, - bool use_blend, - bool use_refract, - bool use_translucency, - int shadow_method); +struct GPUMaterial *EEVEE_material_mesh_get( + struct Scene *scene, Material *ma, EEVEE_Data *vedata, bool use_blend, bool use_refract); struct GPUMaterial *EEVEE_material_mesh_volume_get(struct Scene *scene, Material *ma); 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, int shadow_method); +struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma); void EEVEE_materials_free(void); -void EEVEE_draw_default_passes(EEVEE_PassList *psl); +void EEVEE_materials_draw_opaque(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl); void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, const double offsets[3]); void EEVEE_update_viewvecs(float invproj[4][4], float winmat[4][4], float (*r_viewvecs)[4]); /* eevee_lights.c */ -void EEVEE_lights_init(EEVEE_ViewLayerData *sldata); +void eevee_light_matrix_get(const EEVEE_Light *evli, float r_mat[4][4]); void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, struct Object *ob); -void EEVEE_lights_cache_shcaster_add(EEVEE_ViewLayerData *sldata, - EEVEE_StorageList *stl, - struct GPUBatch *geom, - Object *ob); -void EEVEE_lights_cache_shcaster_material_add(EEVEE_ViewLayerData *sldata, - EEVEE_PassList *psl, - struct GPUMaterial *gpumat, - struct GPUBatch *geom, - struct Object *ob, - const float *alpha_threshold); -void EEVEE_lights_cache_shcaster_object_add(EEVEE_ViewLayerData *sldata, struct Object *ob); void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); -void EEVEE_lights_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); -void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct DRWView *view); -void EEVEE_lights_free(void); + +/* eevee_shadows.c */ +void eevee_contact_shadow_setup(const Light *la, EEVEE_Shadow *evsh); +void EEVEE_shadows_init(EEVEE_ViewLayerData *sldata); +void EEVEE_shadows_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_shadows_caster_add(EEVEE_ViewLayerData *sldata, + EEVEE_StorageList *stl, + struct GPUBatch *geom, + Object *ob); +void EEVEE_shadows_caster_material_add(EEVEE_ViewLayerData *sldata, + EEVEE_PassList *psl, + struct GPUMaterial *gpumat, + struct GPUBatch *geom, + struct Object *ob, + const float *alpha_threshold); +void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, struct Object *ob); +void EEVEE_shadows_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_shadows_cube_add(EEVEE_LightsInfo *linfo, EEVEE_Light *evli, struct Object *ob); +bool EEVEE_shadows_cube_setup(EEVEE_LightsInfo *linfo, const EEVEE_Light *evli, int sample_ofs); +void EEVEE_shadows_cascade_add(EEVEE_LightsInfo *linfo, EEVEE_Light *evli, struct Object *ob); +void EEVEE_shadows_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct DRWView *view); +void EEVEE_shadows_draw_cubemap(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, int cube_index); +void EEVEE_shadows_draw_cascades(EEVEE_ViewLayerData *sldata, + EEVEE_Data *vedata, + DRWView *view, + int cascade_index); +void EEVEE_shadows_free(void); + +/* eevee_sampling.c */ +void EEVEE_sample_ball(int sample_ofs, float radius, float rsample[3]); +void EEVEE_sample_rectangle(int sample_ofs, + const float x_axis[3], + const float y_axis[3], + float size_x, + float size_y, + float rsample[3]); +void EEVEE_sample_ellipse(int sample_ofs, + const float x_axis[3], + const float y_axis[3], + float size_x, + float size_y, + float rsample[3]); +void EEVEE_random_rotation_m4(int sample_ofs, float scale, float r_mat[4][4]); /* eevee_shaders.c */ void EEVEE_shaders_lightprobe_shaders_init(void); @@ -1044,6 +1008,11 @@ void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint sss_id, struct GPUUniformBuffer *sss_profile); +void EEVEE_subsurface_translucency_add_pass(EEVEE_ViewLayerData *sldata, + EEVEE_Data *vedata, + uint sss_id, + struct GPUUniformBuffer *sss_profile, + struct GPUTexture *sss_tex_profile); void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_subsurface_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_subsurface_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c index f840fa23bd2..da957239f42 100644 --- a/source/blender/draw/engines/eevee/eevee_render.c +++ b/source/blender/draw/engines/eevee/eevee_render.c @@ -133,7 +133,7 @@ void EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph * /* EEVEE_effects_init needs to go first for TAA */ EEVEE_effects_init(sldata, vedata, ob_camera_eval, false); EEVEE_materials_init(sldata, stl, fbl); - EEVEE_lights_init(sldata); + EEVEE_shadows_init(sldata); EEVEE_lightprobes_init(sldata, vedata); /* INIT CACHE */ @@ -198,7 +198,7 @@ void EEVEE_render_cache(void *vedata, } if (cast_shadow) { - EEVEE_lights_cache_shcaster_object_add(sldata, ob); + EEVEE_shadows_caster_register(sldata, ob); } } @@ -478,7 +478,8 @@ static void eevee_render_draw_background(EEVEE_Data *vedata) GPU_ATTACHMENT_LEAVE, GPU_ATTACHMENT_TEXTURE(stl->effects->ssr_normal_input), GPU_ATTACHMENT_TEXTURE(stl->effects->ssr_specrough_input), - GPU_ATTACHMENT_TEXTURE(stl->effects->sss_data), + GPU_ATTACHMENT_TEXTURE(stl->effects->sss_irradiance), + GPU_ATTACHMENT_TEXTURE(stl->effects->sss_radius), GPU_ATTACHMENT_TEXTURE(stl->effects->sss_albedo)}); GPU_framebuffer_bind(fbl->main_fb); } @@ -582,8 +583,8 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl EEVEE_lightprobes_refresh_planar(sldata, vedata); /* Refresh Shadows */ - EEVEE_lights_update(sldata, vedata); - EEVEE_draw_shadows(sldata, vedata, stl->effects->taa_view); + EEVEE_shadows_update(sldata, vedata); + EEVEE_shadows_draw(sldata, vedata, stl->effects->taa_view); /* Set matrices. */ DRW_view_set_active(stl->effects->taa_view); @@ -605,9 +606,7 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl /* Shading pass */ eevee_render_draw_background(vedata); GPU_framebuffer_bind(fbl->main_fb); - EEVEE_draw_default_passes(psl); - DRW_draw_pass(psl->material_pass); - DRW_draw_pass(psl->material_pass_cull); + EEVEE_materials_draw_opaque(sldata, psl); EEVEE_subsurface_data_render(sldata, vedata); /* Effects pre-transparency */ EEVEE_subsurface_compute(sldata, vedata); diff --git a/source/blender/draw/engines/eevee/eevee_sampling.c b/source/blender/draw/engines/eevee/eevee_sampling.c new file mode 100644 index 00000000000..9d91e000562 --- /dev/null +++ b/source/blender/draw/engines/eevee/eevee_sampling.c @@ -0,0 +1,111 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2019, Blender Foundation. + */ + +/** \file + * \ingroup EEVEE + */ + +#include "eevee_private.h" + +#include "BLI_rand.h" + +/** + * Special ball distribution: + * Point are distributed in a way that when they are orthogonally + * projected into any plane, the resulting distribution is (close to) + * a uniform disc distribution. + */ +void EEVEE_sample_ball(int sample_ofs, float radius, float rsample[3]) +{ + double ht_point[3]; + double ht_offset[3] = {0.0, 0.0, 0.0}; + uint ht_primes[3] = {2, 3, 7}; + + BLI_halton_3d(ht_primes, ht_offset, sample_ofs, ht_point); + + float omega = ht_point[1] * 2.0f * M_PI; + + rsample[2] = ht_point[0] * 2.0f - 1.0f; /* cos theta */ + + float r = sqrtf(fmaxf(0.0f, 1.0f - rsample[2] * rsample[2])); /* sin theta */ + + rsample[0] = r * cosf(omega); + rsample[1] = r * sinf(omega); + + radius *= sqrt(sqrt(ht_point[2])); + mul_v3_fl(rsample, radius); +} + +void EEVEE_sample_rectangle(int sample_ofs, + const float x_axis[3], + const float y_axis[3], + float size_x, + float size_y, + float rsample[3]) +{ + double ht_point[2]; + double ht_offset[2] = {0.0, 0.0}; + uint ht_primes[2] = {2, 3}; + + BLI_halton_2d(ht_primes, ht_offset, sample_ofs, ht_point); + + /* Change ditribution center to be 0,0 */ + ht_point[0] = (ht_point[0] > 0.5f) ? ht_point[0] - 1.0f : ht_point[0]; + ht_point[1] = (ht_point[1] > 0.5f) ? ht_point[1] - 1.0f : ht_point[1]; + + zero_v3(rsample); + madd_v3_v3fl(rsample, x_axis, (ht_point[0] * 2.0f) * size_x); + madd_v3_v3fl(rsample, y_axis, (ht_point[1] * 2.0f) * size_y); +} + +void EEVEE_sample_ellipse(int sample_ofs, + const float x_axis[3], + const float y_axis[3], + float size_x, + float size_y, + float rsample[3]) +{ + double ht_point[2]; + double ht_offset[2] = {0.0, 0.0}; + uint ht_primes[2] = {2, 3}; + + BLI_halton_2d(ht_primes, ht_offset, sample_ofs, ht_point); + + /* Uniform disc sampling. */ + float omega = ht_point[1] * 2.0f * M_PI; + float r = sqrtf(ht_point[0]); + ht_point[0] = r * cosf(omega) * size_x; + ht_point[1] = r * sinf(omega) * size_y; + + zero_v3(rsample); + madd_v3_v3fl(rsample, x_axis, ht_point[0]); + madd_v3_v3fl(rsample, y_axis, ht_point[1]); +} + +void EEVEE_random_rotation_m4(int sample_ofs, float scale, float r_mat[4][4]) +{ + double ht_point[3]; + double ht_offset[3] = {0.0, 0.0, 0.0}; + uint ht_primes[3] = {2, 3, 5}; + + BLI_halton_3d(ht_primes, ht_offset, sample_ofs, ht_point); + + rotate_m4(r_mat, 'X', ht_point[0] * scale); + rotate_m4(r_mat, 'Y', ht_point[1] * scale); + rotate_m4(r_mat, 'Z', ht_point[2] * scale); +}
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/eevee_shadows.c b/source/blender/draw/engines/eevee/eevee_shadows.c new file mode 100644 index 00000000000..a709e668f34 --- /dev/null +++ b/source/blender/draw/engines/eevee/eevee_shadows.c @@ -0,0 +1,412 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2019, Blender Foundation. + */ + +/** \file + * \ingroup EEVEE + */ + +#include "BLI_sys_types.h" /* bool */ + +// #include "BLI_dynstr.h" +// #include "BLI_rand.h" + +#include "BKE_object.h" + +#include "DEG_depsgraph_query.h" + +#include "eevee_private.h" + +#define SH_CASTER_ALLOC_CHUNK 32 + +static struct { + struct GPUShader *shadow_sh; +} e_data = {NULL}; /* Engine data */ + +extern char datatoc_shadow_vert_glsl[]; +extern char datatoc_shadow_frag_glsl[]; +extern char datatoc_common_view_lib_glsl[]; + +void eevee_contact_shadow_setup(const Light *la, EEVEE_Shadow *evsh) +{ + evsh->contact_dist = (la->mode & LA_SHAD_CONTACT) ? la->contact_dist : 0.0f; + evsh->contact_bias = 0.05f * la->contact_bias; + evsh->contact_thickness = la->contact_thickness; +} + +void EEVEE_shadows_init(EEVEE_ViewLayerData *sldata) +{ + const uint 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(); + const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); + + if (!e_data.shadow_sh) { + e_data.shadow_sh = DRW_shader_create_with_lib(datatoc_shadow_vert_glsl, + NULL, + datatoc_shadow_frag_glsl, + datatoc_common_view_lib_glsl, + NULL); + } + + if (!sldata->lights) { + sldata->lights = MEM_callocN(sizeof(EEVEE_LightsInfo), "EEVEE_LightsInfo"); + sldata->light_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_Light) * MAX_LIGHT, NULL); + sldata->shadow_ubo = DRW_uniformbuffer_create(shadow_ubo_size, NULL); + + for (int i = 0; i < 2; ++i) { + sldata->shcasters_buffers[i].bbox = MEM_callocN( + sizeof(EEVEE_BoundBox) * SH_CASTER_ALLOC_CHUNK, __func__); + sldata->shcasters_buffers[i].update = BLI_BITMAP_NEW(SH_CASTER_ALLOC_CHUNK, __func__); + sldata->shcasters_buffers[i].alloc_count = SH_CASTER_ALLOC_CHUNK; + sldata->shcasters_buffers[i].count = 0; + } + sldata->lights->shcaster_frontbuffer = &sldata->shcasters_buffers[0]; + sldata->lights->shcaster_backbuffer = &sldata->shcasters_buffers[1]; + } + + /* Flip buffers */ + SWAP(EEVEE_ShadowCasterBuffer *, + sldata->lights->shcaster_frontbuffer, + sldata->lights->shcaster_backbuffer); + + int sh_cube_size = scene_eval->eevee.shadow_cube_size; + int sh_cascade_size = scene_eval->eevee.shadow_cascade_size; + const bool sh_high_bitdepth = (scene_eval->eevee.flag & SCE_EEVEE_SHADOW_HIGH_BITDEPTH) != 0; + sldata->lights->soft_shadows = (scene_eval->eevee.flag & SCE_EEVEE_SHADOW_SOFT) != 0; + + EEVEE_LightsInfo *linfo = sldata->lights; + if ((linfo->shadow_cube_size != sh_cube_size) || + (linfo->shadow_high_bitdepth != sh_high_bitdepth)) { + BLI_assert((sh_cube_size > 0) && (sh_cube_size <= 4096)); + DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_pool); + CLAMP(sh_cube_size, 1, 4096); + } + + if ((linfo->shadow_cascade_size != sh_cascade_size) || + (linfo->shadow_high_bitdepth != sh_high_bitdepth)) { + BLI_assert((sh_cascade_size > 0) && (sh_cascade_size <= 4096)); + DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_pool); + CLAMP(sh_cascade_size, 1, 4096); + } + + linfo->shadow_high_bitdepth = sh_high_bitdepth; + linfo->shadow_cube_size = sh_cube_size; + linfo->shadow_cascade_size = sh_cascade_size; +} + +void EEVEE_shadows_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +{ + EEVEE_LightsInfo *linfo = sldata->lights; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_PassList *psl = vedata->psl; + + EEVEE_ShadowCasterBuffer *backbuffer = linfo->shcaster_backbuffer; + EEVEE_ShadowCasterBuffer *frontbuffer = linfo->shcaster_frontbuffer; + + frontbuffer->count = 0; + linfo->num_cube_layer = 0; + linfo->num_cascade_layer = 0; + linfo->cube_len = linfo->cascade_len = linfo->shadow_len = 0; + + /* Shadow Casters: Reset flags. */ + BLI_bitmap_set_all(backbuffer->update, true, backbuffer->alloc_count); + /* Is this one needed? */ + BLI_bitmap_set_all(frontbuffer->update, false, frontbuffer->alloc_count); + + INIT_MINMAX(linfo->shcaster_aabb.min, linfo->shcaster_aabb.max); + + { + DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_SHADOW_OFFSET; + DRW_PASS_CREATE(psl->shadow_pass, state); + + stl->g_data->shadow_shgrp = DRW_shgroup_create(e_data.shadow_sh, psl->shadow_pass); + } +} + +/* Add a shadow caster to the shadowpasses */ +void EEVEE_shadows_caster_add(EEVEE_ViewLayerData *UNUSED(sldata), + EEVEE_StorageList *stl, + struct GPUBatch *geom, + Object *ob) +{ + DRW_shgroup_call(stl->g_data->shadow_shgrp, geom, ob); +} + +void EEVEE_shadows_caster_material_add(EEVEE_ViewLayerData *sldata, + EEVEE_PassList *psl, + struct GPUMaterial *gpumat, + struct GPUBatch *geom, + struct Object *ob, + const float *alpha_threshold) +{ + /* TODO / PERF : reuse the same shading group for objects with the same material */ + DRWShadingGroup *grp = DRW_shgroup_material_create(gpumat, psl->shadow_pass); + + if (grp == NULL) { + return; + } + + /* Grrr needed for correctness but not 99% of the time not needed. + * TODO detect when needed? */ + DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); + DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo); + DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); + DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); + DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + + if (alpha_threshold != NULL) { + DRW_shgroup_uniform_float(grp, "alphaThreshold", alpha_threshold, 1); + } + + DRW_shgroup_call(grp, geom, ob); +} + +/* Make that object update shadow casting lights inside its influence bounding box. */ +void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, Object *ob) +{ + EEVEE_LightsInfo *linfo = sldata->lights; + EEVEE_ShadowCasterBuffer *backbuffer = linfo->shcaster_backbuffer; + EEVEE_ShadowCasterBuffer *frontbuffer = linfo->shcaster_frontbuffer; + bool update = true; + int id = frontbuffer->count; + + /* Make sure shadow_casters is big enough. */ + if (id + 1 >= frontbuffer->alloc_count) { + frontbuffer->alloc_count += SH_CASTER_ALLOC_CHUNK; + frontbuffer->bbox = MEM_reallocN(frontbuffer->bbox, + sizeof(EEVEE_BoundBox) * frontbuffer->alloc_count); + BLI_BITMAP_RESIZE(frontbuffer->update, frontbuffer->alloc_count); + } + + if (ob->base_flag & BASE_FROM_DUPLI) { + /* Duplis will always refresh the shadowmaps as if they were deleted each frame. */ + /* TODO(fclem) fix this. */ + update = true; + } + else { + EEVEE_ObjectEngineData *oedata = EEVEE_object_data_ensure(ob); + int past_id = oedata->shadow_caster_id; + oedata->shadow_caster_id = id; + /* Update flags in backbuffer. */ + if (past_id > -1 && past_id < backbuffer->count) { + BLI_BITMAP_SET(backbuffer->update, past_id, oedata->need_update); + } + update = oedata->need_update; + oedata->need_update = false; + } + + if (update) { + BLI_BITMAP_ENABLE(frontbuffer->update, id); + } + + /* Update World AABB in frontbuffer. */ + BoundBox *bb = BKE_object_boundbox_get(ob); + float min[3], max[3]; + INIT_MINMAX(min, max); + for (int i = 0; i < 8; ++i) { + float vec[3]; + copy_v3_v3(vec, bb->vec[i]); + mul_m4_v3(ob->obmat, vec); + minmax_v3v3_v3(min, max, vec); + } + + EEVEE_BoundBox *aabb = &frontbuffer->bbox[id]; + add_v3_v3v3(aabb->center, min, max); + mul_v3_fl(aabb->center, 0.5f); + sub_v3_v3v3(aabb->halfdim, aabb->center, max); + + aabb->halfdim[0] = fabsf(aabb->halfdim[0]); + aabb->halfdim[1] = fabsf(aabb->halfdim[1]); + aabb->halfdim[2] = fabsf(aabb->halfdim[2]); + + minmax_v3v3_v3(linfo->shcaster_aabb.min, linfo->shcaster_aabb.max, min); + minmax_v3v3_v3(linfo->shcaster_aabb.min, linfo->shcaster_aabb.max, max); + + frontbuffer->count++; +} + +/* Used for checking if object is inside the shadow volume. */ +static bool sphere_bbox_intersect(const BoundSphere *bs, const EEVEE_BoundBox *bb) +{ + /* We are testing using a rougher AABB vs AABB test instead of full AABB vs Sphere. */ + /* TODO test speed with AABB vs Sphere. */ + bool x = fabsf(bb->center[0] - bs->center[0]) <= (bb->halfdim[0] + bs->radius); + bool y = fabsf(bb->center[1] - bs->center[1]) <= (bb->halfdim[1] + bs->radius); + bool z = fabsf(bb->center[2] - bs->center[2]) <= (bb->halfdim[2] + bs->radius); + + return x && y && z; +} + +void EEVEE_shadows_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +{ + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; + EEVEE_LightsInfo *linfo = sldata->lights; + EEVEE_ShadowCasterBuffer *backbuffer = linfo->shcaster_backbuffer; + EEVEE_ShadowCasterBuffer *frontbuffer = linfo->shcaster_frontbuffer; + + eGPUTextureFormat shadow_pool_format = (linfo->shadow_high_bitdepth) ? GPU_DEPTH_COMPONENT24 : + GPU_DEPTH_COMPONENT16; + /* Setup enough layers. */ + /* Free textures if number mismatch. */ + if (linfo->num_cube_layer != linfo->cache_num_cube_layer) { + DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_pool); + linfo->cache_num_cube_layer = linfo->num_cube_layer; + /* Update all lights. */ + BLI_bitmap_set_all(&linfo->sh_cube_update[0], true, MAX_LIGHT); + } + + if (linfo->num_cascade_layer != linfo->cache_num_cascade_layer) { + DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_pool); + linfo->cache_num_cascade_layer = linfo->num_cascade_layer; + } + + if (!sldata->shadow_cube_pool) { + /* TODO shadowcube array. */ + int cube_size = linfo->shadow_cube_size + ((true) ? 2 : 0); + sldata->shadow_cube_pool = DRW_texture_create_2d_array(cube_size, + cube_size, + max_ii(1, linfo->num_cube_layer * 6), + shadow_pool_format, + DRW_TEX_FILTER | DRW_TEX_COMPARE, + NULL); + } + + if (!sldata->shadow_cascade_pool) { + sldata->shadow_cascade_pool = DRW_texture_create_2d_array(linfo->shadow_cascade_size, + linfo->shadow_cascade_size, + max_ii(1, linfo->num_cascade_layer), + shadow_pool_format, + DRW_TEX_FILTER | DRW_TEX_COMPARE, + NULL); + } + + if (sldata->shadow_fb == NULL) { + sldata->shadow_fb = GPU_framebuffer_create(); + } + + /* Gather all light own update bits. to avoid costly intersection check. */ + for (int j = 0; j < linfo->cube_len; j++) { + const EEVEE_Light *evli = linfo->light_data + linfo->shadow_cube_light_indices[j]; + /* Setup shadow cube in UBO and tag for update if necessary. */ + if (EEVEE_shadows_cube_setup(linfo, evli, effects->taa_current_sample - 1)) { + BLI_BITMAP_ENABLE(&linfo->sh_cube_update[0], j); + } + } + + /* TODO(fclem) This part can be slow, optimize it. */ + EEVEE_BoundBox *bbox = backbuffer->bbox; + BoundSphere *bsphere = linfo->shadow_bounds; + /* Search for deleted shadow casters or if shcaster WAS in shadow radius. */ + for (int i = 0; i < backbuffer->count; ++i) { + /* If the shadowcaster has been deleted or updated. */ + if (BLI_BITMAP_TEST(backbuffer->update, i)) { + for (int j = 0; j < linfo->cube_len; j++) { + if (!BLI_BITMAP_TEST(&linfo->sh_cube_update[0], j)) { + if (sphere_bbox_intersect(&bsphere[j], &bbox[i])) { + BLI_BITMAP_ENABLE(&linfo->sh_cube_update[0], j); + } + } + } + } + } + /* Search for updates in current shadow casters. */ + bbox = frontbuffer->bbox; + for (int i = 0; i < frontbuffer->count; i++) { + /* If the shadowcaster has been updated. */ + if (BLI_BITMAP_TEST(frontbuffer->update, i)) { + for (int j = 0; j < linfo->cube_len; j++) { + if (!BLI_BITMAP_TEST(&linfo->sh_cube_update[0], j)) { + if (sphere_bbox_intersect(&bsphere[j], &bbox[i])) { + BLI_BITMAP_ENABLE(&linfo->sh_cube_update[0], j); + } + } + } + } + } + + /* Resize shcasters buffers if too big. */ + if (frontbuffer->alloc_count - frontbuffer->count > SH_CASTER_ALLOC_CHUNK) { + frontbuffer->alloc_count = (frontbuffer->count / SH_CASTER_ALLOC_CHUNK) * + SH_CASTER_ALLOC_CHUNK; + frontbuffer->alloc_count += (frontbuffer->count % SH_CASTER_ALLOC_CHUNK != 0) ? + SH_CASTER_ALLOC_CHUNK : + 0; + frontbuffer->bbox = MEM_reallocN(frontbuffer->bbox, + sizeof(EEVEE_BoundBox) * frontbuffer->alloc_count); + BLI_BITMAP_RESIZE(frontbuffer->update, frontbuffer->alloc_count); + } +} + +/* this refresh lights shadow buffers */ +void EEVEE_shadows_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, DRWView *view) +{ + EEVEE_LightsInfo *linfo = sldata->lights; + + int saved_ray_type = sldata->common_data.ray_type; + + /* Precompute all shadow/view test before rendering and trashing the culling cache. */ + BLI_bitmap *cube_visible = BLI_BITMAP_NEW_ALLOCA(MAX_SHADOW_CUBE); + bool any_visible = false; + for (int cube = 0; cube < linfo->cube_len; cube++) { + if (DRW_culling_sphere_test(view, linfo->shadow_bounds + cube)) { + BLI_BITMAP_ENABLE(cube_visible, cube); + any_visible = true; + } + } + + if (!any_visible && linfo->cascade_len == 0) { + sldata->common_data.ray_type = EEVEE_RAY_SHADOW; + DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data); + } + + DRW_stats_group_start("Cube Shadow Maps"); + { + for (int cube = 0; cube < linfo->cube_len; cube++) { + if (BLI_BITMAP_TEST(cube_visible, cube) && BLI_BITMAP_TEST(linfo->sh_cube_update, cube)) { + EEVEE_shadows_draw_cubemap(sldata, vedata, cube); + } + } + } + DRW_stats_group_end(); + + DRW_stats_group_start("Cascaded Shadow Maps"); + { + for (int cascade = 0; cascade < linfo->cascade_len; cascade++) { + EEVEE_shadows_draw_cascades(sldata, vedata, view, cascade); + } + } + DRW_stats_group_end(); + + DRW_view_set_active(view); + + DRW_uniformbuffer_update(sldata->shadow_ubo, &linfo->shadow_data); /* Update all data at once */ + + if (!any_visible && linfo->cascade_len == 0) { + sldata->common_data.ray_type = saved_ray_type; + DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data); + } +} + +void EEVEE_shadows_free(void) +{ + DRW_SHADER_FREE_SAFE(e_data.shadow_sh); +}
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/eevee_shadows_cascade.c b/source/blender/draw/engines/eevee/eevee_shadows_cascade.c new file mode 100644 index 00000000000..d5e038f716c --- /dev/null +++ b/source/blender/draw/engines/eevee/eevee_shadows_cascade.c @@ -0,0 +1,439 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2019, Blender Foundation. + */ + +/** \file + * \ingroup EEVEE + */ + +#include "BLI_rect.h" +#include "BLI_sys_types.h" /* bool */ + +#include "BKE_object.h" + +#include "eevee_private.h" + +#include "BLI_rand.h" /* needs to be after for some reason. */ + +void EEVEE_shadows_cascade_add(EEVEE_LightsInfo *linfo, EEVEE_Light *evli, Object *ob) +{ + if (linfo->cascade_len >= MAX_SHADOW_CASCADE) { + return; + } + + const Light *la = (Light *)ob->data; + EEVEE_Shadow *sh_data = linfo->shadow_data + linfo->shadow_len; + EEVEE_ShadowCascade *csm_data = linfo->shadow_cascade_data + linfo->cascade_len; + EEVEE_ShadowCascadeRender *csm_render = linfo->shadow_cascade_render + linfo->cascade_len; + + sh_data->bias = max_ff(la->bias * 0.00002f, 0.0f); + eevee_contact_shadow_setup(la, sh_data); + + linfo->shadow_cascade_light_indices[linfo->cascade_len] = linfo->num_light; + evli->shadow_id = linfo->shadow_len++; + sh_data->type_data_id = linfo->cascade_len++; + csm_data->tex_id = linfo->num_cascade_layer; + csm_render->cascade_fade = la->cascade_fade; + csm_render->cascade_count = la->cascade_count; + csm_render->cascade_exponent = la->cascade_exponent; + csm_render->cascade_max_dist = la->cascade_max_dist; + + linfo->num_cascade_layer += la->cascade_count; +} + +static void shadow_cascade_random_matrix_set(float mat[4][4], float radius, int sample_ofs) +{ + float jitter[3]; +#ifndef DEBUG_SHADOW_DISTRIBUTION + EEVEE_sample_ellipse(sample_ofs, mat[0], mat[1], radius, radius, jitter); +#else + for (int i = 0; i <= sample_ofs; ++i) { + EEVEE_sample_ellipse(i, mat[0], mat[1], radius, radius, jitter); + float p[3]; + add_v3_v3v3(p, jitter, mat[2]); + DRW_debug_sphere(p, 0.01f, (float[4]){1.0f, (sample_ofs == i) ? 1.0f : 0.0f, 0.0f, 1.0f}); + } +#endif + add_v3_v3(mat[2], jitter); + orthogonalize_m4(mat, 2); +} + +static double round_to_digits(double value, int digits) +{ + double factor = pow(10.0, digits - ceil(log10(fabs(value)))); + return round(value * factor) / factor; +} + +static void frustum_min_bounding_sphere(const float corners[8][3], + float r_center[3], + float *r_radius) +{ +#if 0 /* Simple solution but waste too much space. */ + float minvec[3], maxvec[3]; + + /* compute the bounding box */ + INIT_MINMAX(minvec, maxvec); + for (int i = 0; i < 8; ++i) { + minmax_v3v3_v3(minvec, maxvec, corners[i]); + } + + /* compute the bounding sphere of this box */ + r_radius = len_v3v3(minvec, maxvec) * 0.5f; + add_v3_v3v3(r_center, minvec, maxvec); + mul_v3_fl(r_center, 0.5f); +#else + /* Find averaged center. */ + zero_v3(r_center); + for (int i = 0; i < 8; ++i) { + add_v3_v3(r_center, corners[i]); + } + mul_v3_fl(r_center, 1.0f / 8.0f); + + /* Search the largest distance from the sphere center. */ + *r_radius = 0.0f; + for (int i = 0; i < 8; ++i) { + float rad = len_squared_v3v3(corners[i], r_center); + if (rad > *r_radius) { + *r_radius = rad; + } + } + + /* TODO try to reduce the radius further by moving the center. + * Remember we need a __stable__ solution! */ + + /* Try to reduce float imprecision leading to shimmering. */ + *r_radius = (float)round_to_digits(sqrtf(*r_radius), 3); +#endif +} + +BLI_INLINE float lerp(float t, float a, float b) +{ + return ((a) + (t) * ((b) - (a))); +} + +static void eevee_shadow_cascade_setup(EEVEE_LightsInfo *linfo, + EEVEE_Light *evli, + DRWView *view, + float view_near, + float view_far, + int sample_ofs) +{ + EEVEE_Shadow *shdw_data = linfo->shadow_data + (int)evli->shadow_id; + EEVEE_ShadowCascade *csm_data = linfo->shadow_cascade_data + (int)shdw_data->type_data_id; + EEVEE_ShadowCascadeRender *csm_render = linfo->shadow_cascade_render + + (int)shdw_data->type_data_id; + int cascade_nbr = csm_render->cascade_count; + float cascade_fade = csm_render->cascade_fade; + float cascade_max_dist = csm_render->cascade_max_dist; + float cascade_exponent = csm_render->cascade_exponent; + + float jitter_ofs[2]; + double ht_point[2]; + double ht_offset[2] = {0.0, 0.0}; + uint ht_primes[2] = {2, 3}; + + BLI_halton_2d(ht_primes, ht_offset, sample_ofs, ht_point); + + /* Not really sure why we need 4.0 factor here. */ + jitter_ofs[0] = (ht_point[0] * 2.0 - 1.0) * 4.0 / linfo->shadow_cascade_size; + jitter_ofs[1] = (ht_point[1] * 2.0 - 1.0) * 4.0 / linfo->shadow_cascade_size; + + /* Camera Matrices */ + float persinv[4][4], vp_projmat[4][4]; + DRW_view_persmat_get(view, persinv, true); + DRW_view_winmat_get(view, vp_projmat, false); + bool is_persp = DRW_view_is_persp_get(view); + + /* obmat = Object Space > World Space */ + /* viewmat = World Space > View Space */ + float(*viewmat)[4] = csm_render->viewmat; + eevee_light_matrix_get(evli, viewmat); + /* At this point, viewmat == normalize_m4(obmat) */ + + if (linfo->soft_shadows) { + shadow_cascade_random_matrix_set(viewmat, evli->radius, sample_ofs); + } + + copy_m4_m4(csm_render->viewinv, viewmat); + invert_m4(viewmat); + + copy_v3_v3(csm_data->shadow_vec, csm_render->viewinv[2]); + + /* Compute near and far value based on all shadow casters cumulated AABBs. */ + float sh_near = -1.0e30f, sh_far = 1.0e30f; + BoundBox shcaster_bounds; + BKE_boundbox_init_from_minmax( + &shcaster_bounds, linfo->shcaster_aabb.min, linfo->shcaster_aabb.max); +#ifdef DEBUG_CSM + float dbg_col1[4] = {1.0f, 0.5f, 0.6f, 1.0f}; + DRW_debug_bbox(&shcaster_bounds, dbg_col1); +#endif + for (int i = 0; i < 8; i++) { + mul_m4_v3(viewmat, shcaster_bounds.vec[i]); + sh_near = max_ff(sh_near, shcaster_bounds.vec[i][2]); + sh_far = min_ff(sh_far, shcaster_bounds.vec[i][2]); + } +#ifdef DEBUG_CSM + float dbg_col2[4] = {0.5f, 1.0f, 0.6f, 1.0f}; + float pts[2][3] = {{0.0, 0.0, sh_near}, {0.0, 0.0, sh_far}}; + mul_m4_v3(csm_render->viewinv, pts[0]); + mul_m4_v3(csm_render->viewinv, pts[1]); + DRW_debug_sphere(pts[0], 1.0f, dbg_col1); + DRW_debug_sphere(pts[1], 1.0f, dbg_col2); +#endif + /* The rest of the function is assuming inverted Z. */ + /* Add a little bias to avoid invalid matrices. */ + sh_far = -(sh_far - 1e-3); + sh_near = -sh_near; + + /* The technique consists into splitting + * the view frustum into several sub-frustum + * that are individually receiving one shadow map */ + + float csm_start, csm_end; + + if (is_persp) { + csm_start = view_near; + csm_end = max_ff(view_far, -cascade_max_dist); + /* Avoid artifacts */ + csm_end = min_ff(view_near, csm_end); + } + else { + csm_start = -view_far; + csm_end = view_far; + } + + /* init near/far */ + for (int c = 0; c < MAX_CASCADE_NUM; ++c) { + csm_data->split_start[c] = csm_end; + csm_data->split_end[c] = csm_end; + } + + /* Compute split planes */ + float splits_start_ndc[MAX_CASCADE_NUM]; + float splits_end_ndc[MAX_CASCADE_NUM]; + + { + /* Nearest plane */ + float p[4] = {1.0f, 1.0f, csm_start, 1.0f}; + /* TODO: we don't need full m4 multiply here */ + mul_m4_v4(vp_projmat, p); + splits_start_ndc[0] = p[2]; + if (is_persp) { + splits_start_ndc[0] /= p[3]; + } + } + + { + /* Farthest plane */ + float p[4] = {1.0f, 1.0f, csm_end, 1.0f}; + /* TODO: we don't need full m4 multiply here */ + mul_m4_v4(vp_projmat, p); + splits_end_ndc[cascade_nbr - 1] = p[2]; + if (is_persp) { + splits_end_ndc[cascade_nbr - 1] /= p[3]; + } + } + + csm_data->split_start[0] = csm_start; + csm_data->split_end[cascade_nbr - 1] = csm_end; + + for (int c = 1; c < cascade_nbr; ++c) { + /* View Space */ + float linear_split = lerp(((float)(c) / (float)cascade_nbr), csm_start, csm_end); + float exp_split = csm_start * powf(csm_end / csm_start, (float)(c) / (float)cascade_nbr); + + if (is_persp) { + csm_data->split_start[c] = lerp(cascade_exponent, linear_split, exp_split); + } + else { + csm_data->split_start[c] = linear_split; + } + csm_data->split_end[c - 1] = csm_data->split_start[c]; + + /* Add some overlap for smooth transition */ + csm_data->split_start[c] = lerp(cascade_fade, + csm_data->split_end[c - 1], + (c > 1) ? csm_data->split_end[c - 2] : + csm_data->split_start[0]); + + /* NDC Space */ + { + float p[4] = {1.0f, 1.0f, csm_data->split_start[c], 1.0f}; + /* TODO: we don't need full m4 multiply here */ + mul_m4_v4(vp_projmat, p); + splits_start_ndc[c] = p[2]; + + if (is_persp) { + splits_start_ndc[c] /= p[3]; + } + } + + { + float p[4] = {1.0f, 1.0f, csm_data->split_end[c - 1], 1.0f}; + /* TODO: we don't need full m4 multiply here */ + mul_m4_v4(vp_projmat, p); + splits_end_ndc[c - 1] = p[2]; + + if (is_persp) { + splits_end_ndc[c - 1] /= p[3]; + } + } + } + + /* Set last cascade split fade distance into the first split_start. */ + float prev_split = (cascade_nbr > 1) ? csm_data->split_end[cascade_nbr - 2] : + csm_data->split_start[0]; + csm_data->split_start[0] = lerp(cascade_fade, csm_data->split_end[cascade_nbr - 1], prev_split); + + /* For each cascade */ + for (int c = 0; c < cascade_nbr; ++c) { + float(*projmat)[4] = csm_render->projmat[c]; + /* Given 8 frustum corners */ + float corners[8][3] = { + /* Near Cap */ + {1.0f, -1.0f, splits_start_ndc[c]}, + {-1.0f, -1.0f, splits_start_ndc[c]}, + {-1.0f, 1.0f, splits_start_ndc[c]}, + {1.0f, 1.0f, splits_start_ndc[c]}, + /* Far Cap */ + {1.0f, -1.0f, splits_end_ndc[c]}, + {-1.0f, -1.0f, splits_end_ndc[c]}, + {-1.0f, 1.0f, splits_end_ndc[c]}, + {1.0f, 1.0f, splits_end_ndc[c]}, + }; + + /* Transform them into world space */ + for (int i = 0; i < 8; ++i) { + mul_project_m4_v3(persinv, corners[i]); + } + + float center[3]; + frustum_min_bounding_sphere(corners, center, &(csm_render->radius[c])); + +#ifdef DEBUG_CSM + float dbg_col[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + if (c < 3) { + dbg_col[c] = 1.0f; + } + DRW_debug_bbox((BoundBox *)&corners, dbg_col); + DRW_debug_sphere(center, csm_render->radius[c], dbg_col); +#endif + + /* Project into lightspace */ + mul_m4_v3(viewmat, center); + + /* Snap projection center to nearest texel to cancel shimmering. */ + float shadow_origin[2], shadow_texco[2]; + /* Light to texture space. */ + mul_v2_v2fl( + shadow_origin, center, linfo->shadow_cascade_size / (2.0f * csm_render->radius[c])); + + /* Find the nearest texel. */ + shadow_texco[0] = roundf(shadow_origin[0]); + shadow_texco[1] = roundf(shadow_origin[1]); + + /* Compute offset. */ + sub_v2_v2(shadow_texco, shadow_origin); + /* Texture to light space. */ + mul_v2_fl(shadow_texco, (2.0f * csm_render->radius[c]) / linfo->shadow_cascade_size); + + /* Apply offset. */ + add_v2_v2(center, shadow_texco); + + /* Expand the projection to cover frustum range */ + rctf rect_cascade; + BLI_rctf_init_pt_radius(&rect_cascade, center, csm_render->radius[c]); + orthographic_m4(projmat, + rect_cascade.xmin, + rect_cascade.xmax, + rect_cascade.ymin, + rect_cascade.ymax, + sh_near, + sh_far); + + /* Anti-Aliasing */ + if (linfo->soft_shadows) { + add_v2_v2(projmat[3], jitter_ofs); + } + + float viewprojmat[4][4]; + mul_m4_m4m4(viewprojmat, projmat, viewmat); + mul_m4_m4m4(csm_data->shadowmat[c], texcomat, viewprojmat); + +#ifdef DEBUG_CSM + DRW_debug_m4_as_bbox(viewprojmat, dbg_col, true); +#endif + } + + shdw_data->near = sh_near; + shdw_data->far = sh_far; +} + +static void eevee_ensure_cascade_views(EEVEE_ShadowCascadeRender *csm_render, + DRWView *view[MAX_CASCADE_NUM]) +{ + for (int i = 0; i < csm_render->cascade_count; i++) { + if (view[i] == NULL) { + view[i] = DRW_view_create(csm_render->viewmat, csm_render->projmat[i], NULL, NULL, NULL); + } + else { + DRW_view_update(view[i], csm_render->viewmat, csm_render->projmat[i], NULL, NULL); + } + } +} + +void EEVEE_shadows_draw_cascades(EEVEE_ViewLayerData *sldata, + EEVEE_Data *vedata, + DRWView *view, + int cascade_index) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; + EEVEE_PrivateData *g_data = stl->g_data; + EEVEE_LightsInfo *linfo = sldata->lights; + + EEVEE_Light *evli = linfo->light_data + linfo->shadow_cascade_light_indices[cascade_index]; + EEVEE_Shadow *shdw_data = linfo->shadow_data + (int)evli->shadow_id; + EEVEE_ShadowCascade *csm_data = linfo->shadow_cascade_data + (int)shdw_data->type_data_id; + EEVEE_ShadowCascadeRender *csm_render = linfo->shadow_cascade_render + + (int)shdw_data->type_data_id; + + float near = DRW_view_near_distance_get(view); + float far = DRW_view_far_distance_get(view); + + eevee_shadow_cascade_setup(linfo, evli, view, near, far, effects->taa_current_sample - 1); + + /* Meh, Reusing the cube views. */ + BLI_assert(MAX_CASCADE_NUM <= 6); + eevee_ensure_cascade_views(csm_render, g_data->cube_views); + + /* Render shadow cascades */ + /* Render cascade separately: seems to be faster for the general case. + * The only time it's more beneficial is when the CPU culling overhead + * outweigh the instancing overhead. which is rarely the case. */ + for (int j = 0; j < csm_render->cascade_count; j++) { + DRW_view_set_active(g_data->cube_views[j]); + int layer = csm_data->tex_id + j; + GPU_framebuffer_texture_layer_attach( + sldata->shadow_fb, sldata->shadow_cascade_pool, 0, layer, 0); + GPU_framebuffer_bind(sldata->shadow_fb); + GPU_framebuffer_clear_depth(sldata->shadow_fb, 1.0f); + DRW_draw_pass(psl->shadow_pass); + } +}
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/eevee_shadows_cube.c b/source/blender/draw/engines/eevee/eevee_shadows_cube.c new file mode 100644 index 00000000000..b10c206703a --- /dev/null +++ b/source/blender/draw/engines/eevee/eevee_shadows_cube.c @@ -0,0 +1,223 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2019, Blender Foundation. + */ + +/** \file + * \ingroup EEVEE + */ + +#include "eevee_private.h" + +void EEVEE_shadows_cube_add(EEVEE_LightsInfo *linfo, EEVEE_Light *evli, Object *ob) +{ + if (linfo->cube_len >= MAX_SHADOW_CUBE) { + return; + } + + const Light *la = (Light *)ob->data; + EEVEE_Shadow *sh_data = linfo->shadow_data + linfo->shadow_len; + + /* Always update dupli lights as EEVEE_LightEngineData is not saved. + * Same issue with dupli shadow casters. */ + bool update = (ob->base_flag & BASE_FROM_DUPLI) != 0; + if (!update) { + EEVEE_LightEngineData *led = EEVEE_light_data_ensure(ob); + if (led->need_update) { + update = true; + led->need_update = false; + } + } + + if (update) { + BLI_BITMAP_ENABLE(&linfo->sh_cube_update[0], linfo->cube_len); + } + + sh_data->near = max_ff(la->clipsta, 1e-8f); + sh_data->bias = max_ff(la->bias * 0.05f, 0.0f); + eevee_contact_shadow_setup(la, sh_data); + + /* Saving light bounds for later. */ + BoundSphere *cube_bound = linfo->shadow_bounds + linfo->cube_len; + copy_v3_v3(cube_bound->center, evli->position); + cube_bound->radius = sqrt(1.0f / evli->invsqrdist); + + linfo->shadow_cube_light_indices[linfo->cube_len] = linfo->num_light; + evli->shadow_id = linfo->shadow_len++; + sh_data->type_data_id = linfo->cube_len++; + + /* Same as linfo->cube_len, no need to save. */ + linfo->num_cube_layer++; +} + +static void shadow_cube_random_position_set(const EEVEE_Light *evli, + int sample_ofs, + float ws_sample_pos[3]) +{ + float jitter[3]; +#ifdef DEBUG_SHADOW_DISTRIBUTION + int i = 0; +start: +#else + int i = sample_ofs; +#endif + switch ((int)evli->light_type) { + case LA_AREA: + EEVEE_sample_rectangle(i, evli->rightvec, evli->upvec, evli->sizex, evli->sizey, jitter); + break; + case (int)LAMPTYPE_AREA_ELLIPSE: + EEVEE_sample_ellipse(i, evli->rightvec, evli->upvec, evli->sizex, evli->sizey, jitter); + break; + default: + EEVEE_sample_ball(i, evli->radius, jitter); + } +#ifdef DEBUG_SHADOW_DISTRIBUTION + float p[3]; + add_v3_v3v3(p, jitter, ws_sample_pos); + DRW_debug_sphere(p, 0.01f, (float[4]){1.0f, (sample_ofs == i) ? 1.0f : 0.0f, 0.0f, 1.0f}); + if (i++ < sample_ofs) { + goto start; + } +#endif + add_v3_v3(ws_sample_pos, jitter); +} + +/* Return true if sample has changed and light needs to be updated. */ +bool EEVEE_shadows_cube_setup(EEVEE_LightsInfo *linfo, const EEVEE_Light *evli, int sample_ofs) +{ + EEVEE_Shadow *shdw_data = linfo->shadow_data + (int)evli->shadow_id; + EEVEE_ShadowCube *cube_data = linfo->shadow_cube_data + (int)shdw_data->type_data_id; + + eevee_light_matrix_get(evli, cube_data->shadowmat); + + shdw_data->far = max_ff(sqrt(1.0f / evli->invsqrdist), 3e-4); + shdw_data->near = min_ff(shdw_data->near, shdw_data->far - 1e-4); + + bool update = false; + + if (linfo->soft_shadows) { + shadow_cube_random_position_set(evli, sample_ofs, cube_data->shadowmat[3]); + /* Update if position changes (avoid infinite update if soft shadows does not move). + * Other changes are caught by depsgraph tagging. This one is for update between samples. */ + update = !compare_v3v3(cube_data->shadowmat[3], cube_data->position, 1e-10f); + /** + * Anti-Aliasing jitter: Add random rotation. + * + * The 2.0 factor is because texel angular size is not even across the cubemap, + * so we make the rotation range a bit bigger. + * This will not blur the shadow even if the spread is too big since we are just + * rotating the shadow cubemap. + * Note that this may be a rough approximation an may not converge to a perfectly + * smooth shadow (because sample distribution is quite non-uniform) but is enought + * in practice. + **/ + /* NOTE: this has implication for spotlight rendering optimization + * (see EEVEE_shadows_draw_cubemap). */ + float angular_texel_size = 2.0f * DEG2RADF(90) / (float)linfo->shadow_cube_size; + EEVEE_random_rotation_m4(sample_ofs, angular_texel_size, cube_data->shadowmat); + } + + copy_v3_v3(cube_data->position, cube_data->shadowmat[3]); + invert_m4(cube_data->shadowmat); + + return update; +} + +static void eevee_ensure_cube_views( + float near, float far, int cube_res, const float viewmat[4][4], DRWView *view[6]) +{ + float winmat[4][4]; + float side = near; + + /* TODO shadowcube array. */ + if (true) { + /* This half texel offset is used to ensure correct filtering between faces. */ + /* FIXME: This exhibit float precision issue with lower cube_res. + * But it seems to be caused by the perspective_m4. */ + side *= ((float)cube_res + 1.0f) / (float)(cube_res); + } + + perspective_m4(winmat, -side, side, -side, side, near, far); + + for (int i = 0; i < 6; i++) { + float tmp[4][4]; + mul_m4_m4m4(tmp, cubefacemat[i], viewmat); + + if (view[i] == NULL) { + view[i] = DRW_view_create(tmp, winmat, NULL, NULL, NULL); + } + else { + DRW_view_update(view[i], tmp, winmat, NULL, NULL); + } + } +} + +/* Does a spot angle fits a single cubeface. */ +static bool spot_angle_fit_single_face(const EEVEE_Light *evli) +{ + /* alpha = spot/cone half angle. */ + /* beta = scaled spot/cone half angle. */ + float cos_alpha = evli->spotsize; + float sin_alpha = sqrtf(max_ff(0.0f, 1.0f - cos_alpha * cos_alpha)); + float cos_beta = min_ff(cos_alpha / hypotf(cos_alpha, sin_alpha * evli->sizex), + cos_alpha / hypotf(cos_alpha, sin_alpha * evli->sizey)); + /* Don't use 45 degrees because AA jitter can offset the face. */ + return cos_beta > cosf(DEG2RADF(42.0f)); +} + +void EEVEE_shadows_draw_cubemap(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, int cube_index) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_PrivateData *g_data = stl->g_data; + EEVEE_LightsInfo *linfo = sldata->lights; + + EEVEE_Light *evli = linfo->light_data + linfo->shadow_cube_light_indices[cube_index]; + EEVEE_Shadow *shdw_data = linfo->shadow_data + (int)evli->shadow_id; + EEVEE_ShadowCube *cube_data = linfo->shadow_cube_data + (int)shdw_data->type_data_id; + + eevee_ensure_cube_views(shdw_data->near, + shdw_data->far, + linfo->shadow_cube_size, + cube_data->shadowmat, + g_data->cube_views); + + /* Render shadow cube */ + /* Render 6 faces separately: seems to be faster for the general case. + * The only time it's more beneficial is when the CPU culling overhead + * outweigh the instancing overhead. which is rarely the case. */ + for (int j = 0; j < 6; j++) { + /* Optimization: Only render the needed faces. */ + /* Skip all but -Z face. */ + if (evli->light_type == LA_SPOT && j != 5 && spot_angle_fit_single_face(evli)) + continue; + /* Skip +Z face. */ + if (evli->light_type != LA_LOCAL && j == 4) + continue; + /* TODO(fclem) some cube sides can be invisible in the main views. Cull them. */ + // if (frustum_intersect(g_data->cube_views[j], main_view)) + // continue; + + DRW_view_set_active(g_data->cube_views[j]); + int layer = cube_index * 6 + j; + GPU_framebuffer_texture_layer_attach(sldata->shadow_fb, sldata->shadow_cube_pool, 0, layer, 0); + GPU_framebuffer_bind(sldata->shadow_fb); + GPU_framebuffer_clear_depth(sldata->shadow_fb, 1.0f); + DRW_draw_pass(psl->shadow_pass); + } + + BLI_BITMAP_SET(&linfo->sh_cube_update[0], cube_index, false); +}
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c index 24956239508..30ad8482f76 100644 --- a/source/blender/draw/engines/eevee/eevee_subsurface.c +++ b/source/blender/draw/engines/eevee/eevee_subsurface.c @@ -38,7 +38,13 @@ static struct { extern char datatoc_common_view_lib_glsl[]; extern char datatoc_common_uniforms_lib_glsl[]; +extern char datatoc_lights_lib_glsl[]; +extern char datatoc_raytrace_lib_glsl[]; +extern char datatoc_octahedron_lib_glsl[]; +extern char datatoc_bsdf_sampling_lib_glsl[]; +extern char datatoc_bsdf_common_lib_glsl[]; extern char datatoc_effect_subsurface_frag_glsl[]; +extern char datatoc_effect_translucency_frag_glsl[]; static void eevee_create_shader_subsurface(void) { @@ -46,16 +52,23 @@ static void eevee_create_shader_subsurface(void) datatoc_common_uniforms_lib_glsl, datatoc_effect_subsurface_frag_glsl); + /* TODO(fclem) remove some of these dependencies. */ + char *frag_translucent_str = BLI_string_joinN(datatoc_common_view_lib_glsl, + datatoc_common_uniforms_lib_glsl, + datatoc_bsdf_common_lib_glsl, + datatoc_bsdf_sampling_lib_glsl, + datatoc_raytrace_lib_glsl, + datatoc_octahedron_lib_glsl, + datatoc_lights_lib_glsl, + datatoc_effect_translucency_frag_glsl); + e_data.sss_sh[0] = DRW_shader_create_fullscreen(frag_str, "#define FIRST_PASS\n"); e_data.sss_sh[1] = DRW_shader_create_fullscreen(frag_str, "#define SECOND_PASS\n"); - e_data.sss_sh[2] = DRW_shader_create_fullscreen(frag_str, - "#define SECOND_PASS\n" - "#define USE_SEP_ALBEDO\n"); - e_data.sss_sh[3] = DRW_shader_create_fullscreen(frag_str, - "#define SECOND_PASS\n" - "#define USE_SEP_ALBEDO\n" - "#define RESULT_ACCUM\n"); + e_data.sss_sh[2] = DRW_shader_create_fullscreen(frag_str, "#define RESULT_ACCUM\n"); + e_data.sss_sh[3] = DRW_shader_create_fullscreen(frag_translucent_str, + "#define EEVEE_TRANSLUCENCY\n" SHADER_DEFINES); + MEM_freeN(frag_translucent_str); MEM_freeN(frag_str); } @@ -69,7 +82,6 @@ void EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); effects->sss_sample_count = 1 + scene_eval->eevee.sss_samples * 2; - effects->sss_separate_albedo = (scene_eval->eevee.flag & SCE_EEVEE_SSS_SEPARATE_ALBEDO) != 0; common_data->sss_jitter_threshold = scene_eval->eevee.sss_jitter_threshold; } @@ -90,9 +102,13 @@ void EEVEE_subsurface_draw_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data effects->sss_stencil = DRW_texture_pool_query_2d( fs_size[0], fs_size[1], GPU_DEPTH24_STENCIL8, &draw_engine_eevee_type); effects->sss_blur = DRW_texture_pool_query_2d( - fs_size[0], fs_size[1], GPU_RGBA16F, &draw_engine_eevee_type); - effects->sss_data = DRW_texture_pool_query_2d( - fs_size[0], fs_size[1], GPU_RGBA16F, &draw_engine_eevee_type); + fs_size[0], fs_size[1], GPU_R11F_G11F_B10F, &draw_engine_eevee_type); + effects->sss_irradiance = DRW_texture_pool_query_2d( + fs_size[0], fs_size[1], GPU_R11F_G11F_B10F, &draw_engine_eevee_type); + effects->sss_radius = DRW_texture_pool_query_2d( + fs_size[0], fs_size[1], GPU_R16F, &draw_engine_eevee_type); + effects->sss_albedo = DRW_texture_pool_query_2d( + fs_size[0], fs_size[1], GPU_R11F_G11F_B10F, &draw_engine_eevee_type); GPUTexture *stencil_tex = effects->sss_stencil; @@ -115,15 +131,13 @@ void EEVEE_subsurface_draw_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data {GPU_ATTACHMENT_TEXTURE(stencil_tex), GPU_ATTACHMENT_TEXTURE(txl->color)}); GPU_framebuffer_ensure_config( - &fbl->sss_clear_fb, {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(effects->sss_data)}); + &fbl->sss_translucency_fb, + {GPU_ATTACHMENT_TEXTURE(stencil_tex), GPU_ATTACHMENT_TEXTURE(effects->sss_irradiance)}); - if (effects->sss_separate_albedo) { - effects->sss_albedo = DRW_texture_pool_query_2d( - fs_size[0], fs_size[1], GPU_R11F_G11F_B10F, &draw_engine_eevee_type); - } - else { - effects->sss_albedo = NULL; - } + GPU_framebuffer_ensure_config(&fbl->sss_clear_fb, + {GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(effects->sss_irradiance), + GPU_ATTACHMENT_TEXTURE(effects->sss_radius)}); } else { /* Cleanup to release memory */ @@ -132,7 +146,8 @@ void EEVEE_subsurface_draw_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_clear_fb); effects->sss_stencil = NULL; effects->sss_blur = NULL; - effects->sss_data = NULL; + effects->sss_irradiance = NULL; + effects->sss_radius = NULL; } } @@ -202,6 +217,7 @@ void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data DRW_PASS_CREATE(psl->sss_blur_ps, state); DRW_PASS_CREATE(psl->sss_resolve_ps, state | DRW_STATE_BLEND_ADD); DRW_PASS_CREATE(psl->sss_accum_ps, state | DRW_STATE_BLEND_ADD); + DRW_PASS_CREATE(psl->sss_translucency_ps, state | DRW_STATE_BLEND_ADD); } void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata, @@ -219,42 +235,66 @@ void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata, DRWShadingGroup *grp = DRW_shgroup_create(e_data.sss_sh[0], psl->sss_blur_ps); DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src); - DRW_shgroup_uniform_texture_ref(grp, "sssData", &effects->sss_data); + DRW_shgroup_uniform_texture_ref(grp, "sssIrradiance", &effects->sss_irradiance); + DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius); DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_stencil_mask(grp, sss_id); DRW_shgroup_call(grp, quad, NULL); - struct GPUShader *sh = (effects->sss_separate_albedo) ? e_data.sss_sh[2] : e_data.sss_sh[1]; - grp = DRW_shgroup_create(sh, psl->sss_resolve_ps); + grp = DRW_shgroup_create(e_data.sss_sh[1], psl->sss_resolve_ps); DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src); - DRW_shgroup_uniform_texture_ref(grp, "sssData", &effects->sss_blur); + DRW_shgroup_uniform_texture_ref(grp, "sssIrradiance", &effects->sss_blur); + DRW_shgroup_uniform_texture_ref(grp, "sssAlbedo", &effects->sss_albedo); + DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius); DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_stencil_mask(grp, sss_id); DRW_shgroup_call(grp, quad, NULL); - if (effects->sss_separate_albedo) { - DRW_shgroup_uniform_texture_ref(grp, "sssAlbedo", &effects->sss_albedo); - } - if (DRW_state_is_image_render()) { - grp = DRW_shgroup_create(e_data.sss_sh[3], psl->sss_accum_ps); + grp = DRW_shgroup_create(e_data.sss_sh[2], psl->sss_accum_ps); DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src); - DRW_shgroup_uniform_texture_ref(grp, "sssData", &effects->sss_blur); + DRW_shgroup_uniform_texture_ref(grp, "sssIrradiance", &effects->sss_blur); + DRW_shgroup_uniform_texture_ref(grp, "sssAlbedo", &effects->sss_albedo); + DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius); DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_stencil_mask(grp, sss_id); DRW_shgroup_call(grp, quad, NULL); - - if (effects->sss_separate_albedo) { - DRW_shgroup_uniform_texture_ref(grp, "sssAlbedo", &effects->sss_albedo); - } } } +void EEVEE_subsurface_translucency_add_pass(EEVEE_ViewLayerData *sldata, + EEVEE_Data *vedata, + uint sss_id, + struct GPUUniformBuffer *sss_profile, + GPUTexture *sss_tex_profile) +{ + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; + struct GPUBatch *quad = DRW_cache_fullscreen_quad_get(); + GPUTexture **depth_src = GPU_depth_blitting_workaround() ? &effects->sss_stencil : &dtxl->depth; + + DRWShadingGroup *grp = DRW_shgroup_create(e_data.sss_sh[3], psl->sss_translucency_ps); + DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); + DRW_shgroup_uniform_texture(grp, "sssTexProfile", sss_tex_profile); + DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src); + DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius); + DRW_shgroup_uniform_texture_ref(grp, "sssShadowCubes", &sldata->shadow_cube_pool); + DRW_shgroup_uniform_texture_ref(grp, "sssShadowCascades", &sldata->shadow_cascade_pool); + DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); + DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); + DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_stencil_mask(grp, sss_id); + DRW_shgroup_call(grp, quad, NULL); +} + void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) { EEVEE_PassList *psl = vedata->psl; @@ -273,7 +313,8 @@ void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat GPU_ATTACHMENT_LEAVE, GPU_ATTACHMENT_LEAVE, GPU_ATTACHMENT_LEAVE, - GPU_ATTACHMENT_TEXTURE(effects->sss_data), + GPU_ATTACHMENT_TEXTURE(effects->sss_irradiance), + GPU_ATTACHMENT_TEXTURE(effects->sss_radius), GPU_ATTACHMENT_TEXTURE(effects->sss_albedo)}); GPU_framebuffer_bind(fbl->main_fb); @@ -287,11 +328,12 @@ void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat GPU_ATTACHMENT_LEAVE, GPU_ATTACHMENT_LEAVE, GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_NONE}); } } -void EEVEE_subsurface_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +void EEVEE_subsurface_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; @@ -313,6 +355,28 @@ void EEVEE_subsurface_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v GPU_framebuffer_blit(fbl->main_fb, 0, fbl->sss_blur_fb, 0, GPU_STENCIL_BIT); } + if (!DRW_pass_is_empty(psl->sss_translucency_ps)) { + /* We sample the shadowmaps using normal sampler. We need to disable Comparison mode. + * TODO(fclem) avoid this by using sampler objects.*/ + GPU_texture_bind(sldata->shadow_cube_pool, 0); + GPU_texture_compare_mode(sldata->shadow_cube_pool, false); + GPU_texture_unbind(sldata->shadow_cube_pool); + GPU_texture_bind(sldata->shadow_cascade_pool, 0); + GPU_texture_compare_mode(sldata->shadow_cascade_pool, false); + GPU_texture_unbind(sldata->shadow_cascade_pool); + + GPU_framebuffer_bind(fbl->sss_translucency_fb); + DRW_draw_pass(psl->sss_translucency_ps); + + /* Reset original state. */ + GPU_texture_bind(sldata->shadow_cube_pool, 0); + GPU_texture_compare_mode(sldata->shadow_cube_pool, true); + GPU_texture_unbind(sldata->shadow_cube_pool); + GPU_texture_bind(sldata->shadow_cascade_pool, 0); + GPU_texture_compare_mode(sldata->shadow_cascade_pool, true); + GPU_texture_unbind(sldata->shadow_cascade_pool); + } + /* 1. horizontal pass */ GPU_framebuffer_bind(fbl->sss_blur_fb); GPU_framebuffer_clear_color(fbl->sss_blur_fb, clear); diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index 7fb5c25ffc6..8a2576e174d 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -595,7 +595,7 @@ void EEVEE_volumes_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) effects->volume_transmit = e_data.dummy_transmit; } -void EEVEE_volumes_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +void EEVEE_volumes_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_PassList *psl = vedata->psl; EEVEE_TextureList *txl = vedata->txl; @@ -605,6 +605,15 @@ void EEVEE_volumes_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *veda if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) { DRW_stats_group_start("Volumetrics"); + /* We sample the shadowmaps using shadow sampler. We need to enable Comparison mode. + * TODO(fclem) avoid this by using sampler objects.*/ + GPU_texture_bind(sldata->shadow_cube_pool, 0); + GPU_texture_compare_mode(sldata->shadow_cube_pool, true); + GPU_texture_unbind(sldata->shadow_cube_pool); + GPU_texture_bind(sldata->shadow_cascade_pool, 0); + GPU_texture_compare_mode(sldata->shadow_cascade_pool, true); + GPU_texture_unbind(sldata->shadow_cascade_pool); + GPU_framebuffer_bind(fbl->volumetric_fb); DRW_draw_pass(psl->volumetric_world_ps); DRW_draw_pass(psl->volumetric_objects_ps); 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 7f795eaac2b..98012aea303 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -56,12 +56,12 @@ struct LightData { #endif struct ShadowData { - vec4 near_far_bias_exp; - vec4 shadow_data_start_end; + vec4 near_far_bias_id; vec4 contact_shadow_data; }; struct ShadowCubeData { + mat4 shadowmat; vec4 position; }; @@ -69,22 +69,20 @@ struct ShadowCascadeData { mat4 shadowmat[MAX_CASCADE_NUM]; vec4 split_start_distances; vec4 split_end_distances; + vec4 shadow_vec_id; }; /* convenience aliases */ -#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 -#define sh_blur shadow_data_start_end.w +#define sh_near near_far_bias_id.x +#define sh_far near_far_bias_id.y +#define sh_bias near_far_bias_id.z +#define sh_data_index near_far_bias_id.w #define sh_contact_dist contact_shadow_data.x #define sh_contact_offset contact_shadow_data.y #define sh_contact_spread contact_shadow_data.z #define sh_contact_thickness contact_shadow_data.w +#define sh_shadow_vec shadow_vec_id.xyz +#define sh_tex_index shadow_vec_id.w /* ------- Convenience functions --------- */ @@ -777,10 +775,9 @@ struct Closure { vec3 transmittance; float holdout; # ifdef USE_SSS - vec4 sss_data; -# ifdef USE_SSS_ALBEDO + vec3 sss_irradiance; vec3 sss_albedo; -# endif + float sss_radius; # endif vec4 ssr_data; vec2 ssr_normal; @@ -796,13 +793,8 @@ Closure nodetree_exec(void); /* Prototype */ # define CLOSURE_HOLDOUT_FLAG 4 # ifdef USE_SSS -# ifdef USE_SSS_ALBEDO -# define CLOSURE_DEFAULT \ - Closure(vec3(0.0), vec3(0.0), 0.0, vec4(0.0), vec3(0.0), vec4(0.0), vec2(0.0), 0) -# else -# define CLOSURE_DEFAULT \ - Closure(vec3(0.0), vec3(0.0), 0.0, vec4(0.0), vec4(0.0), vec2(0.0), 0) -# endif +# define CLOSURE_DEFAULT \ + Closure(vec3(0.0), vec3(0.0), 0.0, vec3(0.0), vec3(0.0), 0.0, vec4(0.0), vec2(0.0), 0) # else # define CLOSURE_DEFAULT Closure(vec3(0.0), vec3(0.0), 0.0, vec4(0.0), vec2(0.0), 0) # endif @@ -823,30 +815,22 @@ void closure_load_ssr_data( } } -# ifdef USE_SSS -void closure_load_sss_data(float radius, - vec3 sss_radiance, -# ifdef USE_SSS_ALBEDO - vec3 sss_albedo, -# endif - int sss_id, - inout Closure cl) +void closure_load_sss_data( + float radius, vec3 sss_irradiance, vec3 sss_albedo, int sss_id, inout Closure cl) { +# ifdef USE_SSS if (sss_id == outputSssId) { - cl.sss_data = vec4(sss_radiance, radius); -# ifdef USE_SSS_ALBEDO + cl.sss_irradiance = sss_irradiance; + cl.sss_radius = radius; cl.sss_albedo = sss_albedo; -# endif cl.flag |= CLOSURE_SSS_FLAG; } - else { - cl.radiance += sss_radiance; -# ifdef USE_SSS_ALBEDO - cl.radiance += sss_radiance * sss_albedo; -# endif + else +# endif + { + cl.radiance += sss_irradiance * sss_albedo; } } -# endif Closure closure_mix(Closure cl1, Closure cl2, float fac) { @@ -862,13 +846,11 @@ Closure closure_mix(Closure cl1, Closure cl2, float fac) cl.ssr_normal = (use_cl1_ssr) ? cl1.ssr_normal : cl2.ssr_normal; # ifdef USE_SSS - cl.sss_data = mix(cl1.sss_data, cl2.sss_data, fac); + cl.sss_albedo = mix(cl1.sss_albedo, cl2.sss_albedo, fac); bool use_cl1_sss = FLAG_TEST(cl1.flag, CLOSURE_SSS_FLAG); - /* It also does not make sense to mix SSS radius or albedo. */ - cl.sss_data.w = (use_cl1_sss) ? cl1.sss_data.w : cl2.sss_data.w; -# ifdef USE_SSS_ALBEDO - cl.sss_albedo = (use_cl1_sss) ? cl1.sss_albedo : cl2.sss_albedo; -# endif + /* It also does not make sense to mix SSS radius or irradiance. */ + cl.sss_radius = (use_cl1_sss) ? cl1.sss_radius : cl2.sss_radius; + cl.sss_irradiance = (use_cl1_sss) ? cl1.sss_irradiance : cl2.sss_irradiance; # endif return cl; } @@ -887,13 +869,11 @@ Closure closure_add(Closure cl1, Closure cl2) cl.ssr_normal = (use_cl1_ssr) ? cl1.ssr_normal : cl2.ssr_normal; # ifdef USE_SSS - cl.sss_data = cl1.sss_data + cl2.sss_data; + cl.sss_albedo = cl1.sss_albedo + cl2.sss_albedo; bool use_cl1_sss = FLAG_TEST(cl1.flag, CLOSURE_SSS_FLAG); - /* It also does not make sense to mix SSS radius or albedo. */ - cl.sss_data.w = (use_cl1_sss) ? cl1.sss_data.w : cl2.sss_data.w; -# ifdef USE_SSS_ALBEDO - cl.sss_albedo = (use_cl1_sss) ? cl1.sss_albedo : cl2.sss_albedo; -# endif + /* It also does not make sense to mix SSS radius or irradiance. */ + cl.sss_radius = (use_cl1_sss) ? cl1.sss_radius : cl2.sss_radius; + cl.sss_irradiance = (use_cl1_sss) ? cl1.sss_irradiance : cl2.sss_irradiance; # endif return cl; } @@ -914,10 +894,9 @@ layout(location = 0) out vec4 outRadiance; layout(location = 1) out vec2 ssrNormals; layout(location = 2) out vec4 ssrData; # ifdef USE_SSS -layout(location = 3) out vec4 sssData; -# ifdef USE_SSS_ALBEDO -layout(location = 4) out vec4 sssAlbedo; -# endif +layout(location = 3) out vec3 sssIrradiance; +layout(location = 4) out float sssRadius; +layout(location = 5) out vec3 sssAlbedo; # endif # else /* USE_ALPHA_BLEND */ /* Use dual source blending to be able to make a whole range of effects. */ @@ -953,10 +932,9 @@ void main() ssrNormals = cl.ssr_normal; ssrData = cl.ssr_data; # ifdef USE_SSS - sssData = cl.sss_data; -# ifdef USE_SSS_ALBEDO - sssAlbedo = cl.sss_albedo.rgbb; -# endif + sssIrradiance = cl.sss_irradiance; + sssRadius = cl.sss_radius; + sssAlbedo = cl.sss_albedo; # endif # endif @@ -964,6 +942,8 @@ void main() # ifdef USE_SSS float fac = float(!sssToggle); + /* TODO(fclem) we shouldn't need this. + * Just disable USE_SSS when USE_REFRACTION is enabled. */ # ifdef USE_REFRACTION /* SSRefraction pass is done after the SSS pass. * In order to not loose the diffuse light totally we @@ -971,11 +951,7 @@ void main() fac = 1.0; # endif -# ifdef USE_SSS_ALBEDO - outRadiance.rgb += cl.sss_data.rgb * cl.sss_albedo.rgb * fac; -# else - outRadiance.rgb += cl.sss_data.rgb * fac; -# endif + outRadiance.rgb += cl.sss_irradiance.rgb * cl.sss_albedo.rgb * fac; # endif } diff --git a/source/blender/draw/engines/eevee/shaders/default_frag.glsl b/source/blender/draw/engines/eevee/shaders/default_frag.glsl index 1f60661d234..ca06d458f6e 100644 --- a/source/blender/draw/engines/eevee/shaders/default_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/default_frag.glsl @@ -31,7 +31,7 @@ Closure nodetree_exec(void) vec3 f0 = mix(dielectric, basecol, metallic); vec3 f90 = mix(vec3(1.0), f0, (1.0 - specular) * metallic); vec3 out_diff, out_spec, ssr_spec; - eevee_closure_default(N, albedo, f0, f90, 1, roughness, 1.0, out_diff, out_spec, ssr_spec); + eevee_closure_default(N, albedo, f0, f90, 1, roughness, 1.0, true, out_diff, out_spec, ssr_spec); Closure cl = CLOSURE_DEFAULT; cl.radiance = out_spec + out_diff * albedo; diff --git a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl index 4260c601543..1241cf0e387 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl @@ -10,7 +10,8 @@ layout(std140) uniform sssProfile }; uniform sampler2D depthBuffer; -uniform sampler2D sssData; +uniform sampler2D sssIrradiance; +uniform sampler2D sssRadius; uniform sampler2D sssAlbedo; #ifndef UTIL_TEX @@ -19,9 +20,12 @@ uniform sampler2DArray utilTex; # define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0) #endif /* UTIL_TEX */ -layout(location = 0) out vec4 FragColor; #ifdef RESULT_ACCUM +/* Render Passes Accumulation */ +layout(location = 0) out vec4 sssDirect; layout(location = 1) out vec4 sssColor; +#else +layout(location = 0) out vec4 sssRadiance; #endif float get_view_z_from_depth(float depth) @@ -43,7 +47,8 @@ void main(void) { vec2 pixel_size = 1.0 / vec2(textureSize(depthBuffer, 0).xy); /* TODO precompute */ vec2 uvs = gl_FragCoord.xy * pixel_size; - vec4 sss_data = texture(sssData, uvs).rgba; + vec3 sss_irradiance = texture(sssIrradiance, uvs).rgb; + float sss_radius = texture(sssRadius, uvs).r; float depth_view = get_view_z_from_depth(texture(depthBuffer, uvs).r); float rand = texelfetch_noise_tex(gl_FragCoord.xy).r; @@ -58,44 +63,36 @@ void main(void) /* Compute kernel bounds in 2D. */ float homcoord = ProjectionMatrix[2][3] * depth_view + ProjectionMatrix[3][3]; - vec2 scale = vec2(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) * sss_data.aa / homcoord; + vec2 scale = vec2(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) * sss_radius / homcoord; vec2 finalStep = scale * radii_max_radius.w; finalStep *= 0.5; /* samples range -1..1 */ /* Center sample */ - vec3 accum = sss_data.rgb * kernel[0].rgb; + vec3 accum = sss_irradiance * kernel[0].rgb; for (int i = 1; i < sss_samples && i < MAX_SSS_SAMPLES; i++) { vec2 sample_uv = uvs + kernel[i].a * finalStep * ((abs(kernel[i].a) > sssJitterThreshold) ? dir : dir_rand); - vec3 color = texture(sssData, sample_uv).rgb; + vec3 color = texture(sssIrradiance, sample_uv).rgb; float sample_depth = texture(depthBuffer, sample_uv).r; sample_depth = get_view_z_from_depth(sample_depth); - /* Depth correction factor. */ float depth_delta = depth_view - sample_depth; - float s = clamp(1.0 - exp(-(depth_delta * depth_delta) / (2.0 * sss_data.a)), 0.0, 1.0); - + float s = clamp(1.0 - exp(-(depth_delta * depth_delta) / (2.0 * sss_radius)), 0.0, 1.0); /* Out of view samples. */ if (any(lessThan(sample_uv, vec2(0.0))) || any(greaterThan(sample_uv, vec2(1.0)))) { s = 1.0; } - - accum += kernel[i].rgb * mix(color, sss_data.rgb, s); + /* Mix with first sample in failure case and apply kernel color. */ + accum += kernel[i].rgb * mix(color, sss_irradiance, s); } -#ifdef FIRST_PASS - FragColor = vec4(accum, sss_data.a); +#ifdef RESULT_ACCUM + sssDirect = vec4(accum, 1.0); + sssColor = vec4(texture(sssAlbedo, uvs).rgb, 1.0); +#elif defined(FIRST_PASS) + sssRadiance = vec4(accum, 1.0); #else /* SECOND_PASS */ -# ifdef USE_SEP_ALBEDO -# ifdef RESULT_ACCUM - FragColor = vec4(accum, 1.0); - sssColor = texture(sssAlbedo, uvs); -# else - FragColor = vec4(accum * texture(sssAlbedo, uvs).rgb, 1.0); -# endif -# else - FragColor = vec4(accum, 1.0); -# endif + sssRadiance = vec4(accum * texture(sssAlbedo, uvs).rgb, 1.0); #endif } diff --git a/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl new file mode 100644 index 00000000000..7edb0053da7 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl @@ -0,0 +1,165 @@ + +in vec4 uvcoordsvar; + +out vec4 FragColor; + +uniform sampler1D sssTexProfile; +uniform sampler2D sssRadius; + +uniform sampler2DArray sssShadowCubes; +uniform sampler2DArray sssShadowCascades; + +#define MAX_SSS_SAMPLES 65 +#define SSS_LUT_SIZE 64.0 +#define SSS_LUT_SCALE ((SSS_LUT_SIZE - 1.0) / float(SSS_LUT_SIZE)) +#define SSS_LUT_BIAS (0.5 / float(SSS_LUT_SIZE)) + +layout(std140) uniform sssProfile +{ + vec4 kernel[MAX_SSS_SAMPLES]; + vec4 radii_max_radius; + int sss_samples; +}; + +vec3 sss_profile(float s) +{ + s /= radii_max_radius.w; + return texture(sssTexProfile, saturate(s) * SSS_LUT_SCALE + SSS_LUT_BIAS).rgb; +} + +#ifndef UTIL_TEX +# define UTIL_TEX +uniform sampler2DArray utilTex; +# define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0) +#endif /* UTIL_TEX */ + +float light_translucent_power_with_falloff(LightData ld, vec3 N, vec4 l_vector) +{ + float power, falloff; + /* XXX : Removing Area Power. */ + /* TODO : put this out of the shader. */ + if (ld.l_type >= AREA_RECT) { + power = (ld.l_sizex * ld.l_sizey * 4.0 * M_PI) * (1.0 / 80.0); + if (ld.l_type == AREA_ELLIPSE) { + power *= M_PI * 0.25; + } + power *= 0.3 * 20.0 * + max(0.0, dot(-ld.l_forward, l_vector.xyz / l_vector.w)); /* XXX ad hoc, empirical */ + power /= (l_vector.w * l_vector.w); + falloff = dot(N, l_vector.xyz / l_vector.w); + } + else if (ld.l_type == SUN) { + power = 1.0 / (1.0 + (ld.l_radius * ld.l_radius * 0.5)); + power *= ld.l_radius * ld.l_radius * M_PI; /* Removing area light power*/ + power *= M_2PI * 0.78; /* Matching cycles with point light. */ + power *= 0.082; /* XXX ad hoc, empirical */ + falloff = dot(N, -ld.l_forward); + } + else { + power = (4.0 * ld.l_radius * ld.l_radius) * (1.0 / 10.0); + power *= 1.5; /* XXX ad hoc, empirical */ + power /= (l_vector.w * l_vector.w); + falloff = dot(N, l_vector.xyz / l_vector.w); + } + /* No transmittance at grazing angle (hide artifacts) */ + return power * saturate(falloff * 2.0); +} + +/* Some driver poorly optimize this code. Use direct reference to matrices. */ +#define sd(x) shadows_data[x] +#define scube(x) shadows_cube_data[x] +#define scascade(x) shadows_cascade_data[x] + +vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, vec2 rand, float sss_scale) +{ + int shadow_id = int(ld.l_shadowid); + + vec4 L = (ld.l_type != SUN) ? l_vector : vec4(-ld.l_forward, 1.0); + + /* We use the full l_vector.xyz so that the spread is minimize + * if the shading point is further away from the light source */ + /* TODO(fclem) do something better than this. */ + // vec3 T, B; + // make_orthonormal_basis(L.xyz / L.w, T, B); + // rand.xy *= data.sh_blur; + // W = W + T * rand.x + B * rand.y; + + float s, dist; + int data_id = int(sd(shadow_id).sh_data_index); + if (ld.l_type == SUN) { + vec4 view_z = vec4(dot(W - cameraPos, cameraForward)); + + vec4 weights = step(scascade(data_id).split_end_distances, view_z); + float id = abs(4.0 - dot(weights, weights)); + if (id > 3.0) { + return vec3(0.0); + } + + /* Same factor as in get_cascade_world_distance(). */ + float range = abs(sd(shadow_id).sh_far - sd(shadow_id).sh_near); + + vec4 shpos = scascade(data_id).shadowmat[int(id)] * vec4(W, 1.0); + dist = shpos.z * range; + + if (shpos.z > 1.0 || shpos.z < 0.0) { + return vec3(0.0); + } + + float tex_id = scascade(data_id).sh_tex_index; + s = sample_cascade(sssShadowCascades, shpos.xy, tex_id + id).r; + s *= range; + } + else { + vec3 cubevec = transform_point(scube(data_id).shadowmat, W); + dist = length(cubevec); + cubevec /= dist; + /* tex_id == data_id for cube shadowmap */ + float tex_id = float(data_id); + s = sample_cube(sssShadowCubes, cubevec, tex_id).r; + s = length(cubevec / max_v3(abs(cubevec))) * + linear_depth(true, s, sd(shadow_id).sh_far, sd(shadow_id).sh_near); + } + float delta = dist - s; + + float power = light_translucent_power_with_falloff(ld, N, l_vector); + + return power * sss_profile(abs(delta) / sss_scale); +} + +#undef sd +#undef scube +#undef scsmd + +void main(void) +{ + vec2 uvs = uvcoordsvar.xy; + float sss_scale = texture(sssRadius, uvs).r; + vec3 W = get_world_space_from_depth(uvs, texture(depthBuffer, uvs).r); + vec3 N = normalize(cross(dFdx(W), dFdy(W))); + + vec3 rand = texelfetch_noise_tex(gl_FragCoord.xy).zwy; + rand.xy *= fast_sqrt(rand.z); + + vec3 accum = vec3(0.0); + for (int i = 0; i < MAX_LIGHT && i < laNumLight; ++i) { + LightData ld = lights_data[i]; + + /* Only shadowed light can produce translucency */ + if (ld.l_shadowid < 0.0) { + continue; + } + + vec4 l_vector; /* Non-Normalized Light Vector with length in last component. */ + l_vector.xyz = ld.l_position - W; + l_vector.w = length(l_vector.xyz); + + float att = light_attenuation(ld, l_vector); + if (att < 1e-8) { + continue; + } + + accum += att * ld.l_color * light_translucent(ld, W, -N, l_vector, rand.xy, sss_scale); + } + + FragColor = vec4(accum, 1.0); +} diff --git a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl index c3643cccbfc..72017e971fc 100644 --- a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl @@ -1,6 +1,6 @@ -uniform sampler2DArray shadowCubeTexture; -uniform sampler2DArray shadowCascadeTexture; +uniform sampler2DArrayShadow shadowCubeTexture; +uniform sampler2DArrayShadow shadowCascadeTexture; #define LAMPS_LIB @@ -24,129 +24,115 @@ layout(std140) uniform light_block /* Used to define the area light shape, doesn't directly correspond to a Blender light type. */ #define AREA_ELLIPSE 100.0 -#if defined(SHADOW_VSM) -# define ShadowSample vec2 -# define sample_cube(vec, id) texture_octahedron(shadowCubeTexture, vec4(vec, id)).rg -# define sample_cascade(vec, id) texture(shadowCascadeTexture, vec3(vec, id)).rg -#elif defined(SHADOW_ESM) -# define ShadowSample float -# define sample_cube(vec, id) texture_octahedron(shadowCubeTexture, vec4(vec, id)).r -# define sample_cascade(vec, id) texture(shadowCascadeTexture, vec3(vec, id)).r -#else -# define ShadowSample float -# define sample_cube(vec, id) texture_octahedron(shadowCubeTexture, vec4(vec, id)).r -# define sample_cascade(vec, id) texture(shadowCascadeTexture, vec3(vec, id)).r -#endif - -#if defined(SHADOW_VSM) -# define get_depth_delta(dist, s) (dist - s.x) -#else -# define get_depth_delta(dist, s) (dist - s) -#endif - - /* ----------------------------------------------------------- */ - /* ----------------------- Shadow tests ---------------------- */ - /* ----------------------------------------------------------- */ - -#if defined(SHADOW_VSM) - -float shadow_test(ShadowSample moments, float dist, ShadowData sd) +float cubeFaceIndexEEVEE(vec3 P) { - float p = 0.0; - - if (dist <= moments.x) { - p = 1.0; + vec3 aP = abs(P); + if (all(greaterThan(aP.xx, aP.yz))) { + return (P.x > 0.0) ? 0.0 : 1.0; + } + else if (all(greaterThan(aP.yy, aP.xz))) { + return (P.y > 0.0) ? 2.0 : 3.0; + } + else { + return (P.z > 0.0) ? 4.0 : 5.0; } - - float variance = moments.y - (moments.x * moments.x); - variance = max(variance, sd.sh_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 - sd.sh_bleed) / (1.0 - sd.sh_bleed), 0.0, 1.0); - - return max(p, p_max); } -#elif defined(SHADOW_ESM) - -float shadow_test(ShadowSample z, float dist, ShadowData sd) +vec2 cubeFaceCoordEEVEE(vec3 P, float face, float scale) { - return saturate(exp(sd.sh_exp * (z - dist + sd.sh_bias))); + if (face < 2.0) { + return (P.zy / P.x) * scale * vec2(-0.5, -sign(P.x) * 0.5) + 0.5; + } + else if (face < 4.0) { + return (P.xz / P.y) * scale * vec2(sign(P.y) * 0.5, 0.5) + 0.5; + } + else { + return (P.xy / P.z) * scale * vec2(0.5, -sign(P.z) * 0.5) + 0.5; + } } -#else - -float shadow_test(ShadowSample z, float dist, ShadowData sd) +vec2 cubeFaceCoordEEVEE(vec3 P, float face, sampler2DArray tex) { - return step(0, z - dist + sd.sh_bias); + /* Scaling to compensate the 1px border around the face. */ + float cube_res = float(textureSize(tex, 0).x); + float scale = (cube_res) / (cube_res + 1.0); + return cubeFaceCoordEEVEE(P, face, scale); } -#endif - -/* ----------------------------------------------------------- */ -/* ----------------------- Shadow types ---------------------- */ -/* ----------------------------------------------------------- */ - -float shadow_cubemap(ShadowData sd, ShadowCubeData scd, float texid, vec3 W) +vec2 cubeFaceCoordEEVEE(vec3 P, float face, sampler2DArrayShadow tex) { - vec3 cubevec = W - scd.position.xyz; - float dist = length(cubevec); + /* Scaling to compensate the 1px border around the face. */ + float cube_res = float(textureSize(tex, 0).x); + float scale = (cube_res) / (cube_res + 1.0); + return cubeFaceCoordEEVEE(P, face, scale); +} - cubevec /= dist; +vec4 sample_cube(sampler2DArray tex, vec3 cubevec, float cube) +{ + /* Manual Shadow Cube Layer indexing. */ + /* TODO Shadow Cube Array. */ + float face = cubeFaceIndexEEVEE(cubevec); + vec2 uv = cubeFaceCoordEEVEE(cubevec, face, tex); - ShadowSample s = sample_cube(cubevec, texid); - return shadow_test(s, dist, sd); + vec3 coord = vec3(uv, cube * 6.0 + face); + return texture(tex, coord); } -float evaluate_cascade(ShadowData sd, mat4 shadowmat, vec3 W, float range, float texid) +vec4 sample_cascade(sampler2DArray tex, vec2 co, float cascade_id) { - vec4 shpos = shadowmat * vec4(W, 1.0); - float dist = shpos.z * range; + return texture(tex, vec3(co, cascade_id)); +} - ShadowSample s = sample_cascade(shpos.xy, texid); - float vis = shadow_test(s, dist, sd); +/* Some driver poorly optimize this code. Use direct reference to matrices. */ +#define sd(x) shadows_data[x] +#define scube(x) shadows_cube_data[x] +#define scascade(x) shadows_cascade_data[x] - /* If fragment is out of shadowmap range, do not occlude */ - if (shpos.z < 1.0 && shpos.z > 0.0) { - return vis; - } - else { - return 1.0; - } +float sample_cube_shadow(int shadow_id, vec3 W) +{ + int data_id = int(sd(shadow_id).sh_data_index); + vec3 cubevec = transform_point(scube(data_id).shadowmat, W); + float dist = max_v3(abs(cubevec)) - sd(shadow_id).sh_bias; + dist = buffer_depth(true, dist, sd(shadow_id).sh_far, sd(shadow_id).sh_near); + /* Manual Shadow Cube Layer indexing. */ + /* TODO Shadow Cube Array. */ + float face = cubeFaceIndexEEVEE(cubevec); + vec2 coord = cubeFaceCoordEEVEE(cubevec, face, shadowCubeTexture); + /* tex_id == data_id for cube shadowmap */ + float tex_id = float(data_id); + return texture(shadowCubeTexture, vec4(coord, tex_id * 6.0 + face, dist)); } -float shadow_cascade(ShadowData sd, int scd_id, float texid, vec3 W) +float sample_cascade_shadow(int shadow_id, vec3 W) { + int data_id = int(sd(shadow_id).sh_data_index); + float tex_id = scascade(data_id).sh_tex_index; vec4 view_z = vec4(dot(W - cameraPos, cameraForward)); - vec4 weights = smoothstep(shadows_cascade_data[scd_id].split_end_distances, - shadows_cascade_data[scd_id].split_start_distances.yzwx, - view_z); - - weights.yzw -= weights.xyz; - - vec4 vis = vec4(1.0); - float range = abs(sd.sh_far - sd.sh_near); /* Same factor as in get_cascade_world_distance(). */ - - /* Branching using (weights > 0.0) is reaally slooow on intel so avoid it for now. */ - /* TODO OPTI: Only do 2 samples and blend. */ - vis.x = evaluate_cascade(sd, shadows_cascade_data[scd_id].shadowmat[0], W, range, texid + 0); - vis.y = evaluate_cascade(sd, shadows_cascade_data[scd_id].shadowmat[1], W, range, texid + 1); - vis.z = evaluate_cascade(sd, shadows_cascade_data[scd_id].shadowmat[2], W, range, texid + 2); - vis.w = evaluate_cascade(sd, shadows_cascade_data[scd_id].shadowmat[3], W, range, texid + 3); - - float weight_sum = dot(vec4(1.0), weights); - if (weight_sum > 0.9999) { - float vis_sum = dot(vec4(1.0), vis * weights); - return vis_sum / weight_sum; - } - else { - float vis_sum = dot(vec4(1.0), vis * step(0.001, weights)); - return mix(1.0, vis_sum, weight_sum); - } + vec4 weights = 1.0 - smoothstep(scascade(data_id).split_end_distances, + scascade(data_id).split_start_distances.yzwx, + view_z); + float tot_weight = dot(weights.xyz, vec3(1.0)); + + int cascade = int(clamp(tot_weight, 0.0, 3.0)); + float blend = fract(tot_weight); + float vis = weights.w; + vec4 coord, shpos; + /* Main cascade. */ + shpos = scascade(data_id).shadowmat[cascade] * vec4(W, 1.0); + coord = vec4(shpos.xy, tex_id + float(cascade), shpos.z - sd(shadow_id).sh_bias); + vis += texture(shadowCascadeTexture, coord) * (1.0 - blend); + + cascade = min(3, cascade + 1); + /* Second cascade. */ + shpos = scascade(data_id).shadowmat[cascade] * vec4(W, 1.0); + coord = vec4(shpos.xy, tex_id + float(cascade), shpos.z - sd(shadow_id).sh_bias); + vis += texture(shadowCascadeTexture, coord) * blend; + + return saturate(vis); } +#undef sd +#undef scube +#undef scsmd /* ----------------------------------------------------------- */ /* --------------------- Light Functions --------------------- */ @@ -173,16 +159,9 @@ float spot_attenuation(LightData ld, vec3 l_vector) return spotmask; } -float light_visibility(LightData ld, - vec3 W, -#ifndef VOLUMETRICS - vec3 viewPosition, - vec3 vN, -#endif - vec4 l_vector) +float light_attenuation(LightData ld, vec4 l_vector) { float vis = 1.0; - if (ld.l_type == SPOT) { vis *= spot_attenuation(ld, l_vector.xyz); } @@ -192,69 +171,66 @@ float light_visibility(LightData ld, if (ld.l_type != SUN) { vis *= distance_attenuation(l_vector.w * l_vector.w, ld.l_influence); } + return vis; +} + +float light_visibility(LightData ld, + vec3 W, +#ifndef VOLUMETRICS + vec3 viewPosition, + float tracing_depth, + vec3 true_normal, + float rand_x, + const bool use_contact_shadows, +#endif + vec4 l_vector) +{ + float vis = light_attenuation(ld, l_vector); #if !defined(VOLUMETRICS) || defined(VOLUME_SHADOW) /* shadowing */ if (ld.l_shadowid >= 0.0 && vis > 0.001) { - ShadowData data = shadows_data[int(ld.l_shadowid)]; if (ld.l_type == SUN) { - vis *= shadow_cascade(data, int(data.sh_data_start), data.sh_tex_start, W); + vis *= sample_cascade_shadow(int(ld.l_shadowid), W); } else { - vis *= shadow_cubemap( - data, shadows_cube_data[int(data.sh_data_start)], data.sh_tex_start, W); + vis *= sample_cube_shadow(int(ld.l_shadowid), W); } # ifndef VOLUMETRICS + ShadowData sd = shadows_data[int(ld.l_shadowid)]; /* Only compute if not already in shadow. */ - if (data.sh_contact_dist > 0.0) { - vec4 L = (ld.l_type != SUN) ? l_vector : vec4(-ld.l_forward, 1.0); - float trace_distance = (ld.l_type != SUN) ? min(data.sh_contact_dist, l_vector.w) : - data.sh_contact_dist; - - vec3 T, B; - make_orthonormal_basis(L.xyz / L.w, T, B); - - vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy); - rand.zw *= fast_sqrt(rand.y) * data.sh_contact_spread; - - /* We use the full l_vector.xyz so that the spread is minimize - * if the shading point is further away from the light source */ - vec3 ray_dir = L.xyz + T * rand.z + B * rand.w; - ray_dir = transform_direction(ViewMatrix, ray_dir); - ray_dir = normalize(ray_dir); - - vec3 ray_ori = viewPosition; - - /* Fix translucency shadowed by contact shadows. */ - vN = (gl_FrontFacing) ? vN : -vN; - - if (dot(vN, ray_dir) <= 0.0) { - return vis; + if (use_contact_shadows && sd.sh_contact_dist > 0.0 && vis > 1e-8) { + /* Contact Shadows. */ + vec3 ray_ori, ray_dir; + float trace_distance; + + if (ld.l_type == SUN) { + trace_distance = sd.sh_contact_dist; + ray_dir = shadows_cascade_data[int(sd.sh_data_index)].sh_shadow_vec * trace_distance; + } + else { + ray_dir = shadows_cube_data[int(sd.sh_data_index)].position.xyz - W; + float len = length(ray_dir); + trace_distance = min(sd.sh_contact_dist, len); + ray_dir *= trace_distance / len; } - float bias = 0.5; /* Constant Bias */ - bias += 1.0 - abs(dot(vN, ray_dir)); /* Angle dependent bias */ - bias *= gl_FrontFacing ? data.sh_contact_offset : -data.sh_contact_offset; - - vec3 nor_bias = vN * bias; - ray_ori += nor_bias; - - ray_dir *= trace_distance; - ray_dir -= nor_bias; + ray_dir = transform_direction(ViewMatrix, ray_dir); + ray_ori = vec3(viewPosition.xy, tracing_depth) + true_normal * sd.sh_contact_offset; vec3 hit_pos = raycast( - -1, ray_ori, ray_dir, data.sh_contact_thickness, rand.x, 0.1, 0.001, false); + -1, ray_ori, ray_dir, sd.sh_contact_thickness, rand_x, 0.1, 0.001, false); if (hit_pos.z > 0.0) { hit_pos = get_view_space_from_depth(hit_pos.xy, hit_pos.z); float hit_dist = distance(viewPosition, hit_pos); float dist_ratio = hit_dist / trace_distance; - return vis * saturate(dist_ratio * dist_ratio * dist_ratio); + return vis * saturate(dist_ratio * 3.0 - 2.0); } } -# endif +# endif /* VOLUMETRICS */ } #endif @@ -325,134 +301,3 @@ float light_specular(LightData ld, vec4 ltc_mat, vec3 N, vec3 V, vec4 l_vector) } } #endif - -#define MAX_SSS_SAMPLES 65 -#define SSS_LUT_SIZE 64.0 -#define SSS_LUT_SCALE ((SSS_LUT_SIZE - 1.0) / float(SSS_LUT_SIZE)) -#define SSS_LUT_BIAS (0.5 / float(SSS_LUT_SIZE)) - -#ifdef USE_TRANSLUCENCY -layout(std140) uniform sssProfile -{ - vec4 kernel[MAX_SSS_SAMPLES]; - vec4 radii_max_radius; - int sss_samples; -}; - -uniform sampler1D sssTexProfile; - -vec3 sss_profile(float s) -{ - s /= radii_max_radius.w; - return texture(sssTexProfile, saturate(s) * SSS_LUT_SCALE + SSS_LUT_BIAS).rgb; -} -#endif - -vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, float scale) -{ -#if !defined(USE_TRANSLUCENCY) || defined(VOLUMETRICS) - return vec3(0.0); -#else - vec3 vis = vec3(1.0); - - if (ld.l_type == SPOT) { - vis *= spot_attenuation(ld, l_vector.xyz); - } - if (ld.l_type >= SPOT) { - vis *= step(0.0, -dot(l_vector.xyz, ld.l_forward)); - } - if (ld.l_type != SUN) { - vis *= distance_attenuation(l_vector.w * l_vector.w, ld.l_influence); - } - - /* Only shadowed light can produce translucency */ - if (ld.l_shadowid >= 0.0 && vis.x > 0.001) { - ShadowData data = shadows_data[int(ld.l_shadowid)]; - float delta; - - vec4 L = (ld.l_type != SUN) ? l_vector : vec4(-ld.l_forward, 1.0); - - vec3 T, B; - make_orthonormal_basis(L.xyz / L.w, T, B); - - vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy); - rand.zw *= fast_sqrt(rand.y) * data.sh_blur; - - /* We use the full l_vector.xyz so that the spread is minimize - * if the shading point is further away from the light source */ - W = W + T * rand.z + B * rand.w; - - if (ld.l_type == SUN) { - int scd_id = int(data.sh_data_start); - vec4 view_z = vec4(dot(W - cameraPos, cameraForward)); - - vec4 weights = step(shadows_cascade_data[scd_id].split_end_distances, view_z); - float id = abs(4.0 - dot(weights, weights)); - - if (id > 3.0) { - return vec3(0.0); - } - - /* Same factor as in get_cascade_world_distance(). */ - float range = abs(data.sh_far - data.sh_near); - - vec4 shpos = shadows_cascade_data[scd_id].shadowmat[int(id)] * vec4(W, 1.0); - float dist = shpos.z * range; - - if (shpos.z > 1.0 || shpos.z < 0.0) { - return vec3(0.0); - } - - ShadowSample s = sample_cascade(shpos.xy, data.sh_tex_start + id); - delta = get_depth_delta(dist, s); - } - else { - vec3 cubevec = W - shadows_cube_data[int(data.sh_data_start)].position.xyz; - float dist = length(cubevec); - cubevec /= dist; - - ShadowSample s = sample_cube(cubevec, data.sh_tex_start); - delta = get_depth_delta(dist, s); - } - - /* XXX : Removing Area Power. */ - /* TODO : put this out of the shader. */ - float falloff; - if (ld.l_type == AREA_RECT || ld.l_type == AREA_ELLIPSE) { - vis *= (ld.l_sizex * ld.l_sizey * 4.0 * M_PI) * (1.0 / 80.0); - if (ld.l_type == AREA_ELLIPSE) { - vis *= M_PI * 0.25; - } - vis *= 0.3 * 20.0 * - max(0.0, dot(-ld.l_forward, l_vector.xyz / l_vector.w)); /* XXX ad hoc, empirical */ - vis /= (l_vector.w * l_vector.w); - falloff = dot(N, l_vector.xyz / l_vector.w); - } - else if (ld.l_type == SUN) { - vis /= 1.0f + (ld.l_radius * ld.l_radius * 0.5f); - vis *= ld.l_radius * ld.l_radius * M_PI; /* Removing area light power*/ - vis *= M_2PI * 0.78; /* Matching cycles with point light. */ - vis *= 0.082; /* XXX ad hoc, empirical */ - falloff = dot(N, -ld.l_forward); - } - else { - vis *= (4.0 * ld.l_radius * ld.l_radius) * (1.0 / 10.0); - vis *= 1.5; /* XXX ad hoc, empirical */ - vis /= (l_vector.w * l_vector.w); - falloff = dot(N, l_vector.xyz / l_vector.w); - } - // vis *= M_1_PI; /* Normalize */ - - /* Applying profile */ - vis *= sss_profile(abs(delta) / scale); - - /* No transmittance at grazing angle (hide artifacts) */ - vis *= saturate(falloff * 2.0); - } - else { - vis = vec3(0.0); - } - - return vis; -#endif -} diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl index 53f1517505c..e9bdfec008f 100644 --- a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl @@ -144,14 +144,12 @@ void CLOSURE_NAME(vec3 N , float ior #endif + , + const bool use_contact_shadows #ifdef CLOSURE_DIFFUSE , out vec3 out_diff #endif -#ifdef CLOSURE_SUBSURFACE - , - out vec3 out_trans -#endif #ifdef CLOSURE_GLOSSY , out vec3 out_spec @@ -170,10 +168,6 @@ void CLOSURE_NAME(vec3 N out_diff = vec3(0.0); #endif -#ifdef CLOSURE_SUBSURFACE - out_trans = vec3(0.0); -#endif - #ifdef CLOSURE_GLOSSY out_spec = vec3(0.0); #endif @@ -230,6 +224,16 @@ void CLOSURE_NAME(vec3 N vec3 out_spec_clear = vec3(0.0); # endif + float tracing_depth = gl_FragCoord.z; + /* Constant bias (due to depth buffer precision) */ + /* Magic numbers for 24bits of precision. + * From http://terathon.com/gdc07_lengyel.pdf (slide 26) */ + tracing_depth -= mix(2.4e-7, 4.8e-7, gl_FragCoord.z); + /* Convert to view Z. */ + tracing_depth = get_view_z_from_depth(tracing_depth); + + vec3 true_normal = normalize(cross(dFdx(viewPosition), dFdy(viewPosition))); + for (int i = 0; i < MAX_LIGHT && i < laNumLight; ++i) { LightData ld = lights_data[i]; @@ -237,7 +241,14 @@ void CLOSURE_NAME(vec3 N l_vector.xyz = ld.l_position - worldPosition; l_vector.w = length(l_vector.xyz); - float l_vis = light_visibility(ld, worldPosition, viewPosition, viewNormal, l_vector); + float l_vis = light_visibility(ld, + worldPosition, + viewPosition, + tracing_depth, + true_normal, + rand.x, + use_contact_shadows, + l_vector); if (l_vis < 1e-8) { continue; @@ -249,10 +260,6 @@ void CLOSURE_NAME(vec3 N out_diff += l_color_vis * light_diffuse(ld, N, V, l_vector); # endif -# ifdef CLOSURE_SUBSURFACE - out_trans += ld.l_color * light_translucent(ld, worldPosition, -N, l_vector, sss_scale); -# endif - # ifdef CLOSURE_GLOSSY out_spec += l_color_vis * light_specular(ld, ltc_mat, N, V, l_vector) * ld.l_spec; # endif @@ -441,10 +448,17 @@ void CLOSURE_NAME(vec3 N /* Ambient Occlusion */ /* ---------------------------- */ # if defined(CLOSURE_GLOSSY) || defined(CLOSURE_DIFFUSE) - /* HACK: Fix for translucent BSDF. (see T65631) */ - bool same_side = dot((gl_FrontFacing) ? worldNormal : -worldNormal, N) > 0.0; + if (!use_contact_shadows) { + /* HACK: Fix for translucent BSDF. (see T65631) */ + N = -N; + } vec3 bent_normal; - float final_ao = occlusion_compute(same_side ? N : -N, viewPosition, ao, rand, bent_normal); + float final_ao = occlusion_compute(gl_FrontFacing ? N : -N, viewPosition, ao, rand, bent_normal); + if (!use_contact_shadows) { + N = -N; + /* Bypass bent normal. */ + bent_normal = N; + } # endif /* ---------------------------- */ diff --git a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl index 14e0c947b47..f88cfdf3787 100644 --- a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl @@ -120,7 +120,8 @@ void prepare_raycast(vec3 ray_origin, ss_ray = ss_start * m.xyyy + 0.5; ss_step *= m.xyyy; - ss_ray.xy += m * ssrPixelSize * 2.0; /* take the center of the texel. * 2 because halfres. */ + /* take the center of the texel. */ + // ss_ray.xy += sign(ss_ray.xy) * m * ssrPixelSize * (1.0 + hizMipOffset); } /* See times_and_deltas. */ diff --git a/source/blender/draw/engines/eevee/shaders/shadow_copy_frag.glsl b/source/blender/draw/engines/eevee/shaders/shadow_copy_frag.glsl deleted file mode 100644 index 5646c257562..00000000000 --- a/source/blender/draw/engines/eevee/shaders/shadow_copy_frag.glsl +++ /dev/null @@ -1,199 +0,0 @@ -/* 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 -{ - /* Use vectors to avoid alignment padding. */ - ivec4 shadowSampleCount; - vec4 shadowInvSampleCount; - vec4 filterSize; - int viewCount; - int baseId; - float cubeTexelSize; - float storedTexelSize; - float nearClip; - float farClip; - float exponent; -}; - -#ifdef CSM -uniform sampler2DArray shadowTexture; -#else -uniform samplerCube shadowTexture; -#endif - -flat in int layerID; - -#ifdef CSM -# define cascadeID layerID -#else -# define cascadeID 0 -#endif - -out vec4 FragColor; - -#define linear_depth(z) \ - ((nearClip * farClip) / (clamp(z, 0.0, 0.999999) * (nearClip - farClip) + farClip)) - -/* add bias so background filtering does not bleed into shadow map */ -#define BACKGROUND_BIAS 0.05 - -#ifdef CSM -vec4 get_world_distance(vec4 depths, vec3 cos[4]) -{ - depths += step(vec4(0.9999), depths) * BACKGROUND_BIAS; - return clamp( - depths * abs(farClip - nearClip), 0.0, 1e10); /* Same factor as in shadow_cascade(). */ -} - -float get_world_distance(float depth, vec3 cos) -{ - depth += step(0.9999, depth) * BACKGROUND_BIAS; - return clamp( - depth * abs(farClip - nearClip), 0.0, 1e10); /* Same factor as in shadow_cascade(). */ -} - -#else /* CUBEMAP */ -vec4 get_world_distance(vec4 depths, vec3 cos[4]) -{ - depths = linear_depth(depths); - 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) -{ - depth = linear_depth(depth); - 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 */ -#define ln_space_prefilter_step(ref, sample) exp(sample - ref) -#define ln_space_prefilter_finalize(ref, sum) (ref + log(SAMPLE_WEIGHT * sum)) - -#define SAMPLE_WEIGHT 0.11111 - -#ifdef ESM -void prefilter(vec4 depths, float ref, inout float accum) -{ - accum += dot(ln_space_prefilter_step(ref, depths), vec4(1.0)); -} -#else /* VSM */ -void prefilter(vec4 depths, float ref, 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[layerID] + uvs.x * minorAxisX[layerID] + uvs.y * minorAxisY[layerID]; -} -#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 * 2.0 - 1.0; -#endif - - /* Center texel */ - vec3 co = get_texco(uvs, vec2(0.0)); - float depth = texture(shadowTexture, co).r; - depth = get_world_distance(depth, co); - - if (filterSize[cascadeID] == 0.0) { -#ifdef ESM - FragColor = vec4(depth); -#else /* VSM */ - FragColor = vec2(depth, depth * depth).xyxy; -#endif - return; - } - -#ifdef ESM - float ref = depth; - float accum = 1.0; -#else /* VSM */ - float ref = 0.0; /* UNUSED */ - vec2 accum = vec2(depth, depth * depth) * SAMPLE_WEIGHT; -#endif - - vec3 ofs = vec3(1.0, 0.0, -1.0) * filterSize[cascadeID]; - - 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); - prefilter(depths, ref, 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); - prefilter(depths, ref, accum); - -#ifdef ESM - accum = ln_space_prefilter_finalize(ref, accum); -#endif - /* Clamp infinite sum. */ - FragColor = vec2(clamp(accum, 0.0, 1e16)).xyxy; -} diff --git a/source/blender/draw/engines/eevee/shaders/shadow_process_geom.glsl b/source/blender/draw/engines/eevee/shaders/shadow_process_geom.glsl deleted file mode 100644 index 591666560c4..00000000000 --- a/source/blender/draw/engines/eevee/shaders/shadow_process_geom.glsl +++ /dev/null @@ -1,36 +0,0 @@ - -layout(triangles) in; -layout(triangle_strip, max_vertices = 3) out; - -layout(std140) uniform shadow_render_block -{ - /* Use vectors to avoid alignment padding. */ - ivec4 shadowSampleCount; - vec4 shadowInvSampleCount; - vec4 filterSize; - int viewCount; - int baseId; - float cubeTexelSize; - float storedTexelSize; - float nearClip; - float farClip; - float exponent; -}; - -in int layerID_g[]; - -flat out int layerID; - -void main() -{ - gl_Layer = layerID_g[0]; - layerID = gl_Layer - baseId; - - gl_Position = gl_in[0].gl_Position; - EmitVertex(); - gl_Position = gl_in[1].gl_Position; - EmitVertex(); - gl_Position = gl_in[2].gl_Position; - EmitVertex(); - EndPrimitive(); -} diff --git a/source/blender/draw/engines/eevee/shaders/shadow_process_vert.glsl b/source/blender/draw/engines/eevee/shaders/shadow_process_vert.glsl deleted file mode 100644 index 95e6a48b81f..00000000000 --- a/source/blender/draw/engines/eevee/shaders/shadow_process_vert.glsl +++ /dev/null @@ -1,32 +0,0 @@ - -layout(std140) uniform shadow_render_block -{ - /* Use vectors to avoid alignment padding. */ - ivec4 shadowSampleCount; - vec4 shadowInvSampleCount; - vec4 filterSize; - int viewCount; - int baseId; - float cubeTexelSize; - float storedTexelSize; - float nearClip; - float farClip; - float exponent; -}; - -out int layerID_g; - -void main() -{ - int v = gl_VertexID % 3; - layerID_g = gl_VertexID / 3; - float x = -1.0 + float((v & 1) << 2); - float y = -1.0 + float((v & 2) << 1); - gl_Position = vec4(x, y, 1.0, 1.0); - - /* HACK avoid changing drawcall parameters. */ - if (layerID_g >= viewCount) { - gl_Position = vec4(0.0); - } - layerID_g += baseId; -} diff --git a/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl b/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl deleted file mode 100644 index 5c19ccd5ce1..00000000000 --- a/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl +++ /dev/null @@ -1,322 +0,0 @@ - -layout(std140) uniform shadow_render_block -{ - /* Use vectors to avoid alignment padding. */ - ivec4 shadowSampleCount; - vec4 shadowInvSampleCount; - vec4 filterSize; - int viewCount; - int baseId; - float cubeTexelSize; - float storedTexelSize; - float nearClip; - float farClip; - float exponent; -}; - -#ifdef CSM -uniform sampler2DArray shadowTexture; -#else -uniform samplerCube shadowTexture; -#endif - -flat in int layerID; - -#ifdef CSM -# define cascadeID layerID -#else -# define cascadeID 0 -#endif - -out vec4 FragColor; - -vec3 octahedral_to_cubemap_proj(vec2 co) -{ - co = co * 2.0 - 1.0; - - vec2 abs_co = abs(co); - vec3 v = vec3(co, 1.0 - (abs_co.x + abs_co.y)); - - if (abs_co.x + abs_co.y > 1.0) { - v.xy = (abs(co.yx) - 1.0) * -sign(co.xy); - } - - return v; -} - -/* Marco Salvi's GDC 2008 presentation about shadow maps pre-filtering techniques slide 24 */ -/* http://advances.realtimerendering.com/s2009/SIGGRAPH%202009%20-%20Lighting%20Research%20at%20Bungie.pdf - * Slide 55. */ -#define ln_space_prefilter_step(ref, sample) exp(sample - ref) -#define ln_space_prefilter_finalize(ref, sum) (ref + log(shadowInvSampleCount[cascadeID] * sum)) - -#ifdef CSM -vec3 get_texco(vec3 cos, const vec2 ofs) -{ - cos.xy += ofs * filterSize[cascadeID]; - return cos; -} -#else /* CUBEMAP */ -/* global vars */ -vec3 T = vec3(0.0); -vec3 B = vec3(0.0); - -void make_orthonormal_basis(vec3 N) -{ - vec3 UpVector = (abs(N.z) < 0.999) ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); - T = normalize(cross(UpVector, N)); - B = cross(N, T); -} - -vec3 get_texco(vec3 cos, const vec2 ofs) -{ - return cos + ofs.x * T + ofs.y * B; -} - -#endif - -#ifdef ESM -void grouped_samples_accum(vec3 cos, - const vec2 co1, - const vec2 co2, - const vec2 co3, - const vec2 co4, - float ref, - inout vec4 accum) -{ - vec4 depths; - depths.x = texture(shadowTexture, get_texco(cos, co1)).r; - depths.y = texture(shadowTexture, get_texco(cos, co2)).r; - depths.z = texture(shadowTexture, get_texco(cos, co3)).r; - depths.w = texture(shadowTexture, get_texco(cos, co4)).r; - - accum += ln_space_prefilter_step(ref, depths); -} -#else /* VSM */ -void grouped_samples_accum(vec3 cos, - const vec2 co1, - const vec2 co2, - const vec2 co3, - const vec2 co4, - float ref, - inout vec2 accum) -{ - vec4 depths1, depths2; - depths1.xy = texture(shadowTexture, get_texco(cos, co1)).rg; - depths1.zw = texture(shadowTexture, get_texco(cos, co2)).rg; - depths2.xy = texture(shadowTexture, get_texco(cos, co3)).rg; - depths2.zw = texture(shadowTexture, get_texco(cos, co4)).rg; - - accum += depths1.xy + depths1.zw + depths2.xy + depths2.zw; -} -#endif - -void main() -{ - 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 */ - 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(cos.xy - 0.5) + 0.5; - vec2 f = floor(m); - if (f.x - f.y != 0.0) { - cos.xy = 1.0 - cos.xy; - } - - /* clamp to [0-1] */ - cos.xy = fract(cos.xy); - - /* get cubemap vector */ - cos = normalize(octahedral_to_cubemap_proj(cos.xy)); - make_orthonormal_basis(cos); - - T *= filterSize[cascadeID]; - B *= filterSize[cascadeID]; -#endif - -#ifdef ESM - /* 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; - float ref = depths.x; - vec4 accum = ln_space_prefilter_step(ref, depths); - -#else /* VSM */ - float ref = 0.0; /* UNUSED */ - vec2 accum = vec2(0.0); - grouped_samples_accum( - cos, concentric[0], concentric[1], concentric[2], concentric[3], ref, accum); -#endif - - /** - * Making the `grouped_samples_accum` be called within a loop would be - * the most conventional solution, however in some older gpus, transverse the huge - * `const vec2 concentric[]` array with variable indices is extremely slow. - * The solution is to use constant indices to access the array. - */ - if (shadowSampleCount[cascadeID] > 4) { - grouped_samples_accum( - cos, concentric[4], concentric[5], concentric[6], concentric[7], ref, accum); - grouped_samples_accum( - cos, concentric[8], concentric[9], concentric[10], concentric[11], ref, accum); - grouped_samples_accum( - cos, concentric[12], concentric[13], concentric[14], concentric[15], ref, accum); - } - if (shadowSampleCount[cascadeID] > 16) { - grouped_samples_accum( - cos, concentric[16], concentric[17], concentric[18], concentric[19], ref, accum); - grouped_samples_accum( - cos, concentric[20], concentric[21], concentric[22], concentric[23], ref, accum); - grouped_samples_accum( - cos, concentric[24], concentric[25], concentric[26], concentric[27], ref, accum); - grouped_samples_accum( - cos, concentric[28], concentric[29], concentric[30], concentric[31], ref, accum); - grouped_samples_accum( - cos, concentric[32], concentric[33], concentric[34], concentric[35], ref, accum); - } -#ifdef HIGH_BLUR - if (shadowSampleCount[cascadeID] > 36) { - grouped_samples_accum( - cos, concentric[36], concentric[37], concentric[38], concentric[39], ref, accum); - grouped_samples_accum( - cos, concentric[40], concentric[41], concentric[42], concentric[43], ref, accum); - grouped_samples_accum( - cos, concentric[44], concentric[45], concentric[46], concentric[47], ref, accum); - grouped_samples_accum( - cos, concentric[48], concentric[49], concentric[50], concentric[51], ref, accum); - grouped_samples_accum( - cos, concentric[52], concentric[53], concentric[54], concentric[55], ref, accum); - grouped_samples_accum( - cos, concentric[56], concentric[57], concentric[58], concentric[59], ref, accum); - grouped_samples_accum( - cos, concentric[60], concentric[61], concentric[62], concentric[63], ref, accum); - } - if (shadowSampleCount[cascadeID] > 64) { - grouped_samples_accum( - cos, concentric[64], concentric[65], concentric[66], concentric[67], ref, accum); - grouped_samples_accum( - cos, concentric[68], concentric[69], concentric[70], concentric[71], ref, accum); - grouped_samples_accum( - cos, concentric[72], concentric[73], concentric[74], concentric[75], ref, accum); - grouped_samples_accum( - cos, concentric[76], concentric[77], concentric[78], concentric[79], ref, accum); - grouped_samples_accum( - cos, concentric[80], concentric[81], concentric[82], concentric[83], ref, accum); - grouped_samples_accum( - cos, concentric[84], concentric[85], concentric[86], concentric[87], ref, accum); - grouped_samples_accum( - cos, concentric[88], concentric[89], concentric[90], concentric[91], ref, accum); - grouped_samples_accum( - cos, concentric[92], concentric[93], concentric[94], concentric[95], ref, accum); - grouped_samples_accum( - cos, concentric[96], concentric[97], concentric[98], concentric[99], ref, accum); - } - if (shadowSampleCount[cascadeID] > 100) { - grouped_samples_accum( - cos, concentric[100], concentric[101], concentric[102], concentric[103], ref, accum); - grouped_samples_accum( - cos, concentric[104], concentric[105], concentric[106], concentric[107], ref, accum); - grouped_samples_accum( - cos, concentric[108], concentric[109], concentric[110], concentric[111], ref, accum); - grouped_samples_accum( - cos, concentric[112], concentric[113], concentric[114], concentric[115], ref, accum); - grouped_samples_accum( - cos, concentric[116], concentric[117], concentric[118], concentric[119], ref, accum); - grouped_samples_accum( - cos, concentric[120], concentric[121], concentric[122], concentric[123], ref, accum); - grouped_samples_accum( - cos, concentric[124], concentric[125], concentric[126], concentric[127], ref, accum); - grouped_samples_accum( - cos, concentric[128], concentric[129], concentric[130], concentric[131], ref, accum); - grouped_samples_accum( - cos, concentric[132], concentric[133], concentric[134], concentric[135], ref, accum); - grouped_samples_accum( - cos, concentric[136], concentric[137], concentric[138], concentric[139], ref, accum); - grouped_samples_accum( - cos, concentric[140], concentric[141], concentric[142], concentric[143], ref, accum); - } - if (shadowSampleCount[cascadeID] > 144) { - grouped_samples_accum( - cos, concentric[144], concentric[145], concentric[146], concentric[147], ref, accum); - grouped_samples_accum( - cos, concentric[148], concentric[149], concentric[150], concentric[151], ref, accum); - grouped_samples_accum( - cos, concentric[152], concentric[153], concentric[154], concentric[155], ref, accum); - grouped_samples_accum( - cos, concentric[156], concentric[157], concentric[158], concentric[159], ref, accum); - grouped_samples_accum( - cos, concentric[160], concentric[161], concentric[162], concentric[163], ref, accum); - grouped_samples_accum( - cos, concentric[164], concentric[165], concentric[166], concentric[167], ref, accum); - grouped_samples_accum( - cos, concentric[168], concentric[169], concentric[170], concentric[171], ref, accum); - grouped_samples_accum( - cos, concentric[172], concentric[173], concentric[174], concentric[175], ref, accum); - grouped_samples_accum( - cos, concentric[176], concentric[177], concentric[178], concentric[179], ref, accum); - grouped_samples_accum( - cos, concentric[180], concentric[181], concentric[182], concentric[183], ref, accum); - grouped_samples_accum( - cos, concentric[184], concentric[185], concentric[186], concentric[187], ref, accum); - grouped_samples_accum( - cos, concentric[188], concentric[189], concentric[190], concentric[191], ref, accum); - grouped_samples_accum( - cos, concentric[192], concentric[193], concentric[194], concentric[195], ref, accum); - } - if (shadowSampleCount[cascadeID] > 196) { - grouped_samples_accum( - cos, concentric[196], concentric[197], concentric[198], concentric[199], ref, accum); - grouped_samples_accum( - cos, concentric[200], concentric[201], concentric[202], concentric[203], ref, accum); - grouped_samples_accum( - cos, concentric[204], concentric[205], concentric[206], concentric[207], ref, accum); - grouped_samples_accum( - cos, concentric[208], concentric[209], concentric[210], concentric[211], ref, accum); - grouped_samples_accum( - cos, concentric[212], concentric[213], concentric[114], concentric[215], ref, accum); - grouped_samples_accum( - cos, concentric[216], concentric[217], concentric[218], concentric[219], ref, accum); - grouped_samples_accum( - cos, concentric[220], concentric[221], concentric[222], concentric[223], ref, accum); - grouped_samples_accum( - cos, concentric[224], concentric[225], concentric[226], concentric[227], ref, accum); - grouped_samples_accum( - cos, concentric[228], concentric[229], concentric[230], concentric[231], ref, accum); - grouped_samples_accum( - cos, concentric[232], concentric[233], concentric[234], concentric[235], ref, accum); - grouped_samples_accum( - cos, concentric[236], concentric[237], concentric[238], concentric[239], ref, accum); - grouped_samples_accum( - cos, concentric[240], concentric[241], concentric[242], concentric[243], ref, accum); - grouped_samples_accum( - cos, concentric[244], concentric[245], concentric[246], concentric[247], ref, accum); - grouped_samples_accum( - cos, concentric[248], concentric[249], concentric[250], concentric[251], ref, accum); - grouped_samples_accum( - cos, concentric[252], concentric[253], concentric[254], concentric[255], ref, accum); - } -#endif - -#ifdef ESM - accum.x = dot(vec4(1.0), accum); - accum.x = ln_space_prefilter_finalize(ref, accum.x); - FragColor = accum.xxxx; - -#else /* VSM */ - FragColor = accum.xyxy * shadowInvSampleCount[cascadeID]; -#endif -} diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 10ab7c13631..e3713fdee8f 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -346,6 +346,7 @@ typedef enum { /** Use dual source blending. WARNING: Only one color buffer allowed. */ DRW_STATE_BLEND_CUSTOM = (1 << 23), + DRW_STATE_SHADOW_OFFSET = (1 << 27), DRW_STATE_CLIP_PLANES = (1 << 28), DRW_STATE_WIRE_SMOOTH = (1 << 29), DRW_STATE_FIRST_VERTEX_CONVENTION = (1 << 30), diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c index 50408015fbc..0d19a257cfa 100644 --- a/source/blender/draw/intern/draw_manager_exec.c +++ b/source/blender/draw/intern/draw_manager_exec.c @@ -279,6 +279,23 @@ void drw_state_set(DRWState state) } } + /* Shadow Bias */ + { + int test; + if ((test = CHANGED_TO(DRW_STATE_SHADOW_OFFSET))) { + if (test == 1) { + glEnable(GL_POLYGON_OFFSET_FILL); + glEnable(GL_POLYGON_OFFSET_LINE); + /* 2.0 Seems to be the lowest possible slope bias that works in every case. */ + glPolygonOffset(2.0f, 1.0f); + } + else { + glDisable(GL_POLYGON_OFFSET_FILL); + glDisable(GL_POLYGON_OFFSET_LINE); + } + } + } + /* Clip Planes */ { int test; |