diff options
author | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:17:24 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:21:24 +0300 |
commit | e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch) | |
tree | 8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/draw/engines/eevee/eevee_lights.c | |
parent | b3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff) |
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211.
For details on usage and instructions for migrating branches
without conflicts, see:
https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/draw/engines/eevee/eevee_lights.c')
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_lights.c | 2587 |
1 files changed, 1326 insertions, 1261 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c index b66563de80a..b118d7be3d0 100644 --- a/source/blender/draw/engines/eevee/eevee_lights.c +++ b/source/blender/draw/engines/eevee/eevee_lights.c @@ -38,13 +38,13 @@ // #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]; + 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[]; @@ -60,671 +60,701 @@ 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)); - } + 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)); + 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]; - } + 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)); + 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) +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)); - } - } - } + 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( - datatoc_shadow_vert_glsl, NULL, datatoc_shadow_frag_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_fullscreen( - datatoc_shadow_copy_frag_glsl, - "#define ESM\n" - "#define COPY\n"); - e_data.shadow_copy_cascade_sh[SHADOW_ESM] = DRW_shader_create_fullscreen( - datatoc_shadow_copy_frag_glsl, - "#define ESM\n" - "#define COPY\n" - "#define CSM\n"); - } - 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_fullscreen( - datatoc_shadow_copy_frag_glsl, - "#define VSM\n" - "#define COPY\n"); - e_data.shadow_copy_cascade_sh[SHADOW_VSM] = DRW_shader_create_fullscreen( - datatoc_shadow_copy_frag_glsl, - "#define VSM\n" - "#define COPY\n" - "#define CSM\n"); - } + 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( + datatoc_shadow_vert_glsl, NULL, datatoc_shadow_frag_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_fullscreen( + datatoc_shadow_copy_frag_glsl, + "#define ESM\n" + "#define COPY\n"); + e_data.shadow_copy_cascade_sh[SHADOW_ESM] = DRW_shader_create_fullscreen( + datatoc_shadow_copy_frag_glsl, + "#define ESM\n" + "#define COPY\n" + "#define CSM\n"); + } + 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_fullscreen( + datatoc_shadow_copy_frag_glsl, + "#define VSM\n" + "#define COPY\n"); + e_data.shadow_copy_cascade_sh[SHADOW_VSM] = DRW_shader_create_fullscreen( + datatoc_shadow_copy_frag_glsl, + "#define VSM\n" + "#define COPY\n" + "#define CSM\n"); + } } 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_fullscreen( - store_shadow_shader_str, define_str); - - MEM_freeN(store_shadow_shader_str); - MEM_freeN(define_str); - } - - return *shader; + 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_fullscreen(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) +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) { - EEVEE_LightsInfo *linfo = sldata->lights; - *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_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1); - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); - } - return *pass; + 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) { + EEVEE_LightsInfo *linfo = sldata->lights; + *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_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1); + DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + } + return *pass; } -static DRWPass *eevee_lights_cascade_store_pass_get(EEVEE_PassList *psl, EEVEE_ViewLayerData *sldata, int shadow_method, int shadow_samples_len) +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) { - EEVEE_LightsInfo *linfo = sldata->lights; - *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_uniform_int(grp, "cascadeId", &linfo->current_shadow_cascade, 1); - DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1); - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); - } - return *pass; + 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) { + EEVEE_LightsInfo *linfo = sldata->lights; + *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_uniform_int(grp, "cascadeId", &linfo->current_shadow_cascade, 1); + DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1); + DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + } + 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; - - { - psl->shadow_cube_copy_pass = DRW_pass_create("Shadow Copy Pass", DRW_STATE_WRITE_COLOR); - - DRWShadingGroup *grp = DRW_shgroup_create( - e_data.shadow_copy_cube_sh[linfo->shadow_method], psl->shadow_cube_copy_pass); - DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cube_target); - DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo); - DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1); - DRW_shgroup_uniform_int(grp, "faceId", &linfo->current_shadow_face, 1); - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); - } - - { - psl->shadow_cascade_copy_pass = DRW_pass_create("Shadow Cascade Copy Pass", DRW_STATE_WRITE_COLOR); - - DRWShadingGroup *grp = DRW_shgroup_create( - e_data.shadow_copy_cascade_sh[linfo->shadow_method], psl->shadow_cascade_copy_pass); - DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cascade_target); - DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo); - DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1); - DRW_shgroup_uniform_int(grp, "cascadeId", &linfo->current_shadow_cascade, 1); - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); - } - - { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; - psl->shadow_pass = DRW_pass_create("Shadow Pass", state); - - stl->g_data->shadow_shgrp = DRW_shgroup_create(e_data.shadow_sh, psl->shadow_pass); - } + 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; + + { + psl->shadow_cube_copy_pass = DRW_pass_create("Shadow Copy Pass", DRW_STATE_WRITE_COLOR); + + DRWShadingGroup *grp = DRW_shgroup_create(e_data.shadow_copy_cube_sh[linfo->shadow_method], + psl->shadow_cube_copy_pass); + DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cube_target); + DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo); + DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1); + DRW_shgroup_uniform_int(grp, "faceId", &linfo->current_shadow_face, 1); + DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + } + + { + psl->shadow_cascade_copy_pass = DRW_pass_create("Shadow Cascade Copy Pass", + DRW_STATE_WRITE_COLOR); + + DRWShadingGroup *grp = DRW_shgroup_create(e_data.shadow_copy_cascade_sh[linfo->shadow_method], + psl->shadow_cascade_copy_pass); + DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cascade_target); + DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo); + DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1); + DRW_shgroup_uniform_int(grp, "cascadeId", &linfo->current_shadow_cascade, 1); + DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + } + + { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; + psl->shadow_pass = DRW_pass_create("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) { - 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++; - } + 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) +void EEVEE_lights_cache_shcaster_add(EEVEE_ViewLayerData *UNUSED(sldata), + EEVEE_StorageList *stl, + struct GPUBatch *geom, + Object *ob) { - DRW_shgroup_call_object_add( - stl->g_data->shadow_shgrp, - geom, ob); + DRW_shgroup_call_object_add(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, float *alpha_threshold) +void EEVEE_lights_cache_shcaster_material_add(EEVEE_ViewLayerData *sldata, + EEVEE_PassList *psl, + struct GPUMaterial *gpumat, + struct GPUBatch *geom, + struct Object *ob, + 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_object_add(grp, geom, ob); + /* 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_object_add(grp, geom, ob); } /* 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; + 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); - } - 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); - } - 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); + 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); + } + 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); + } + 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) { - if (la->mode & LA_CUSTOM_ATTENUATION) { - return la->att_dist; - } - - /* Compute max light power. */ - float power = max_fff(la->r, la->g, la->b); - power *= fabsf(la->energy); - power *= max_ff(1.0f, la->spec_fac); - /* Compute the distance (using the inverse square law) - * at which the light power reaches the light_threshold. */ - float distance = sqrtf(max_ff(1e-16, power / max_ff(1e-16, light_threshold))); - return distance; + if (la->mode & LA_CUSTOM_ATTENUATION) { + return la->att_dist; + } + + /* Compute max light power. */ + float power = max_fff(la->r, la->g, la->b); + power *= fabsf(la->energy); + power *= max_ff(1.0f, la->spec_fac); + /* Compute the distance (using the inverse square law) + * at which the light power reaches the light_threshold. */ + float distance = sqrtf(max_ff(1e-16, power / max_ff(1e-16, light_threshold))); + return distance; } static void light_shape_parameters_set(EEVEE_Light *evli, const Light *la, float scale[3]) { - if (la->type == LA_SPOT) { - /* Spot size & blend */ - evli->sizex = scale[0] / scale[2]; - evli->sizey = scale[1] / scale[2]; - evli->spotsize = cosf(la->spotsize * 0.5f); - evli->spotblend = (1.0f - evli->spotsize) * la->spotblend; - evli->radius = max_ff(0.001f, la->area_size); - } - else if (la->type == LA_AREA) { - evli->sizex = max_ff(0.003f, la->area_size * scale[0] * 0.5f); - if (ELEM(la->area_shape, LA_AREA_RECT, LA_AREA_ELLIPSE)) { - evli->sizey = max_ff(0.003f, la->area_sizey * scale[1] * 0.5f); - } - else { - evli->sizey = max_ff(0.003f, la->area_size * scale[1] * 0.5f); - } - } - else { - evli->radius = max_ff(0.001f, la->area_size); - } + if (la->type == LA_SPOT) { + /* Spot size & blend */ + evli->sizex = scale[0] / scale[2]; + evli->sizey = scale[1] / scale[2]; + evli->spotsize = cosf(la->spotsize * 0.5f); + evli->spotblend = (1.0f - evli->spotsize) * la->spotblend; + evli->radius = max_ff(0.001f, la->area_size); + } + else if (la->type == LA_AREA) { + evli->sizex = max_ff(0.003f, la->area_size * scale[0] * 0.5f); + if (ELEM(la->area_shape, LA_AREA_RECT, LA_AREA_ELLIPSE)) { + evli->sizey = max_ff(0.003f, la->area_sizey * scale[1] * 0.5f); + } + else { + evli->sizey = max_ff(0.003f, la->area_size * scale[1] * 0.5f); + } + } + else { + evli->radius = max_ff(0.001f, la->area_size); + } } static float light_shape_power_get(const Light *la, const EEVEE_Light *evli) { - float power; - /* Make illumination power constant */ - if (la->type == LA_AREA) { - power = 1.0f / (evli->sizex * evli->sizey * 4.0f * M_PI) * /* 1/(w*h*Pi) */ - 80.0f; /* XXX : Empirical, Fit cycles power */ - if (ELEM(la->area_shape, LA_AREA_DISK, LA_AREA_ELLIPSE)) { - /* Scale power to account for the lower area of the ellipse compared to the surrounding rectangle. */ - power *= 4.0f / M_PI; - } - } - else if (la->type == LA_SPOT || la->type == LA_LOCAL) { - power = 1.0f / (4.0f * evli->radius * evli->radius * M_PI * M_PI) * /* 1/(4*r²*Pi²) */ - M_PI * M_PI * 10.0; /* XXX : Empirical, Fit cycles power */ - - /* for point lights (a.k.a radius == 0.0) */ - // power = M_PI * M_PI * 0.78; /* XXX : Empirical, Fit cycles power */ - } - else { - power = 1.0f / (evli->radius * evli->radius * M_PI); /* 1/(r²*Pi) */ - /* Make illumation power closer to cycles for bigger radii. Cycles uses a cos^3 term that we cannot reproduce - * so we account for that by scaling the light power. This function is the result of a rough manual fitting. */ - power += 1.0f / (2.0f * M_PI); /* power *= 1 + r²/2 */ - } - return power; + float power; + /* Make illumination power constant */ + if (la->type == LA_AREA) { + power = 1.0f / (evli->sizex * evli->sizey * 4.0f * M_PI) * /* 1/(w*h*Pi) */ + 80.0f; /* XXX : Empirical, Fit cycles power */ + if (ELEM(la->area_shape, LA_AREA_DISK, LA_AREA_ELLIPSE)) { + /* Scale power to account for the lower area of the ellipse compared to the surrounding rectangle. */ + power *= 4.0f / M_PI; + } + } + else if (la->type == LA_SPOT || la->type == LA_LOCAL) { + power = 1.0f / (4.0f * evli->radius * evli->radius * M_PI * M_PI) * /* 1/(4*r²*Pi²) */ + M_PI * M_PI * 10.0; /* XXX : Empirical, Fit cycles power */ + + /* for point lights (a.k.a radius == 0.0) */ + // power = M_PI * M_PI * 0.78; /* XXX : Empirical, Fit cycles power */ + } + else { + power = 1.0f / (evli->radius * evli->radius * M_PI); /* 1/(r²*Pi) */ + /* Make illumation power closer to cycles for bigger radii. Cycles uses a cos^3 term that we cannot reproduce + * so we account for that by scaling the light power. This function is the result of a rough manual fitting. */ + power += 1.0f / (2.0f * M_PI); /* power *= 1 + r²/2 */ + } + return power; } /* Update buffer with light data */ static void eevee_light_setup(Object *ob, EEVEE_Light *evli) { - Light *la = (Light *)ob->data; - float mat[4][4], scale[3], power, att_radius; + Light *la = (Light *)ob->data; + float mat[4][4], scale[3], power, att_radius; - const DRWContextState *draw_ctx = DRW_context_state_get(); - const float light_threshold = draw_ctx->scene->eevee.light_threshold; + const DRWContextState *draw_ctx = DRW_context_state_get(); + const float light_threshold = draw_ctx->scene->eevee.light_threshold; - /* Position */ - copy_v3_v3(evli->position, ob->obmat[3]); + /* Position */ + copy_v3_v3(evli->position, ob->obmat[3]); - /* Color */ - copy_v3_v3(evli->color, &la->r); + /* Color */ + copy_v3_v3(evli->color, &la->r); - evli->spec = la->spec_fac; + evli->spec = la->spec_fac; - /* Influence Radius */ - att_radius = light_attenuation_radius_get(la, light_threshold); - /* Take the inverse square of this distance. */ - evli->invsqrdist = 1.0 / max_ff(1e-4f, att_radius * att_radius); + /* Influence Radius */ + att_radius = light_attenuation_radius_get(la, light_threshold); + /* Take the inverse square of this distance. */ + evli->invsqrdist = 1.0 / max_ff(1e-4f, att_radius * att_radius); - /* Vectors */ - normalize_m4_m4_ex(mat, ob->obmat, scale); - copy_v3_v3(evli->forwardvec, mat[2]); - normalize_v3(evli->forwardvec); - negate_v3(evli->forwardvec); + /* Vectors */ + normalize_m4_m4_ex(mat, ob->obmat, scale); + copy_v3_v3(evli->forwardvec, mat[2]); + normalize_v3(evli->forwardvec); + negate_v3(evli->forwardvec); - copy_v3_v3(evli->rightvec, mat[0]); - normalize_v3(evli->rightvec); + copy_v3_v3(evli->rightvec, mat[0]); + normalize_v3(evli->rightvec); - copy_v3_v3(evli->upvec, mat[1]); - normalize_v3(evli->upvec); + copy_v3_v3(evli->upvec, mat[1]); + normalize_v3(evli->upvec); - /* Make sure we have a consistent Right Hand coord frame. - * (in case of negatively scaled Z axis) */ - float cross[3]; - cross_v3_v3v3(cross, evli->rightvec, evli->forwardvec); - if (dot_v3v3(cross, evli->upvec) < 0.0) { - negate_v3(evli->upvec); - } + /* Make sure we have a consistent Right Hand coord frame. + * (in case of negatively scaled Z axis) */ + float cross[3]; + cross_v3_v3v3(cross, evli->rightvec, evli->forwardvec); + if (dot_v3v3(cross, evli->upvec) < 0.0) { + negate_v3(evli->upvec); + } - light_shape_parameters_set(evli, la, scale); + light_shape_parameters_set(evli, la, scale); - /* Light Type */ - evli->light_type = (float)la->type; - if ((la->type == LA_AREA) && ELEM(la->area_shape, LA_AREA_DISK, LA_AREA_ELLIPSE)) { - evli->light_type = LAMPTYPE_AREA_ELLIPSE; - } + /* Light Type */ + evli->light_type = (float)la->type; + if ((la->type == LA_AREA) && ELEM(la->area_shape, LA_AREA_DISK, LA_AREA_ELLIPSE)) { + evli->light_type = LAMPTYPE_AREA_ELLIPSE; + } - power = light_shape_power_get(la, evli); - mul_v3_fl(evli->color, power * la->energy); + power = light_shape_power_get(la, evli); + mul_v3_fl(evli->color, power * la->energy); - /* No shadow by default */ - evli->shadowid = -1.0f; + /* No shadow by default */ + evli->shadowid = -1.0f; } /** @@ -735,769 +765,804 @@ static void eevee_light_setup(Object *ob, EEVEE_Light *evli) */ 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}; + 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); + BLI_halton_3d(ht_primes, ht_offset, sample_ofs, ht_point); - float omega = ht_point[1] * 2.0f * M_PI; + float omega = ht_point[1] * 2.0f * M_PI; - rsample[2] = ht_point[0] * 2.0f - 1.0f; /* cos theta */ + 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 */ + float r = sqrtf(fmaxf(0.0f, 1.0f - rsample[2] * rsample[2])); /* sin theta */ - rsample[0] = r * cosf(omega); - rsample[1] = r * sinf(omega); + rsample[0] = r * cosf(omega); + rsample[1] = r * sinf(omega); - radius *= sqrt(sqrt(ht_point[2])); - mul_v3_fl(rsample, radius); + 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]) + 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}; + 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); + 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]; + /* 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); + 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]) + 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}; + 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); + 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; + /* 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]); + 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]) +static void shadow_cube_random_position_set(EEVEE_Light *evli, + Light *la, + int sample_ofs, + float ws_sample_pos[3]) { - float jitter[3]; + float jitter[3]; #ifndef DEBUG_SHADOW_DISTRIBUTION - int i = sample_ofs; + int i = sample_ofs; #else - for (int i = 0; i <= sample_ofs; ++i) { + 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); - } + 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}); - } + 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); +add_v3_v3(ws_sample_pos, jitter); } -static void eevee_shadow_cube_setup(Object *ob, EEVEE_LightsInfo *linfo, EEVEE_LightEngineData *led, int sample_ofs) +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; + 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]; + float jitter[3]; #ifndef DEBUG_SHADOW_DISTRIBUTION - int i = sample_ofs; + int i = sample_ofs; #else - for (int i = 0; i <= sample_ofs; ++i) { + for (int i = 0; i <= sample_ofs; ++i) { #endif - sample_ellipse(i, mat[0], mat[1], radius, radius, jitter); + 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}); - } + 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); +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; + 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) +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); + 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); + /* 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, - DRWMatrixState *saved_mats, float view_near, float view_far, int sample_ofs) +static void eevee_shadow_cascade_setup(Object *ob, + EEVEE_LightsInfo *linfo, + EEVEE_LightEngineData *led, + DRWMatrixState *saved_mats, + float view_near, + float view_far, + int sample_ofs) { - Light *la = (Light *)ob->data; + Light *la = (Light *)ob->data; - /* Camera Matrices */ - float (*persinv)[4] = saved_mats->mat[DRW_MAT_PERSINV]; - float (*vp_projmat)[4] = saved_mats->mat[DRW_MAT_WIN]; - bool is_persp = DRW_viewport_is_persp_get(); + /* Camera Matrices */ + float(*persinv)[4] = saved_mats->mat[DRW_MAT_PERSINV]; + float(*vp_projmat)[4] = saved_mats->mat[DRW_MAT_WIN]; + bool is_persp = DRW_viewport_is_persp_get(); - /* Lights Matrices */ - int cascade_nbr = la->cascade_count; + /* 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; + 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; + /* 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); + 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])); + 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); + 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); - mul_v2_fl(shadow_texco, (2.0f * sh_data->radius[c]) / linfo->shadow_cascade_size); /* Texture to light space. */ - - /* 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]); + /* 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); + mul_v2_fl(shadow_texco, + (2.0f * sh_data->radius[c]) / + linfo->shadow_cascade_size); /* Texture to light space. */ + + /* 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); + 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; + } + + 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; } /* Used for checking if object is inside the shadow volume. */ static bool sphere_bbox_intersect(const EEVEE_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); + /* 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; + return x && y && z; } void EEVEE_lights_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { - 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); - } - } - - /* 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; - } - } - - /* 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); - } + 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); + } + } + + /* 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; + } + } + + /* 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); + } } /* this refresh lights shadow buffers */ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { - EEVEE_PassList *psl = vedata->psl; - EEVEE_StorageList *stl = vedata->stl; - EEVEE_EffectsInfo *effects = stl->effects; - 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; - - DRWMatrixState saved_mats; - int saved_ray_type = sldata->common_data.ray_type; - - /* TODO: make it optionnal 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(&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(plane); - } - - /* We need to save the Matrices before overidding them */ - DRW_viewport_matrix_get_all(&saved_mats); - - /* 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; - } - - DRWMatrixState render_mats; - float (*winmat)[4] = render_mats.mat[DRW_MAT_WIN]; - float (*viewmat)[4] = render_mats.mat[DRW_MAT_VIEW]; - float (*persmat)[4] = render_mats.mat[DRW_MAT_PERS]; - - 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; - copy_v3_v3(srd->position, cube_data->position); - - perspective_m4(winmat, -srd->clip_near, srd->clip_near, -srd->clip_near, srd->clip_near, srd->clip_near, srd->clip_far); - - DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd); - - /* 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++) { - /* TODO optimize */ - float tmp[4][4]; - unit_m4(tmp); - negate_v3_v3(tmp[3], srd->position); - mul_m4_m4m4(viewmat, cubefacemat[j], tmp); - mul_m4_m4m4(persmat, winmat, viewmat); - invert_m4_m4(render_mats.mat[DRW_MAT_WININV], winmat); - invert_m4_m4(render_mats.mat[DRW_MAT_VIEWINV], viewmat); - invert_m4_m4(render_mats.mat[DRW_MAT_PERSINV], persmat); - - DRW_viewport_matrix_override_set_all(&render_mats); - - 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); - linfo->filter_size = srd->cube_texel_size * ((filter_pixel_size > 1.0f) ? 1.5f : 0.0f); - - /* TODO: OPTI: Filter all faces in one/two draw call */ - /* TODO: OPTI: Don't do this intermediate step if no filter is needed. */ - for (linfo->current_shadow_face = 0; - linfo->current_shadow_face < 6; - linfo->current_shadow_face++) - { - /* Copy using a small 3x3 box filter */ - GPU_framebuffer_texture_cubeface_attach(sldata->shadow_cube_store_fb, sldata->shadow_cube_blur, 0, - linfo->current_shadow_face, 0); - GPU_framebuffer_bind(sldata->shadow_cube_store_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) { - linfo->filter_size = 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 = min_ii(max_sample, 4 + 8 * (int)filter_pixel_size + 4 * (int)(pix_size_sqr)); - } - else { - linfo->filter_size = 0.0f; - srd->shadow_samples_len = 4; - } - srd->shadow_samples_len_inv = 1.0f / (float)srd->shadow_samples_len; - DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd); - - GPU_framebuffer_texture_layer_attach(sldata->shadow_cube_store_fb, sldata->shadow_cube_pool, 0, evscd->layer_id, 0); - GPU_framebuffer_bind(sldata->shadow_cube_store_fb); - - DRWPass *store_pass = eevee_lights_cube_store_pass_get(psl, sldata, linfo->shadow_method, srd->shadow_samples_len); - 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(); - - DRW_viewport_matrix_override_set_all(&saved_mats); - float near = DRW_viewport_near_distance_get(); - float far = DRW_viewport_far_distance_get(); - - /* 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; - - DRWMatrixState render_mats; - float (*winmat)[4] = render_mats.mat[DRW_MAT_WIN]; - float (*viewmat)[4] = render_mats.mat[DRW_MAT_VIEW]; - float (*persmat)[4] = render_mats.mat[DRW_MAT_PERS]; - - eevee_shadow_cascade_setup(ob, linfo, led, &saved_mats, near, far, effects->taa_current_sample - 1); - - srd->clip_near = la->clipsta; - srd->clip_far = la->clipend; - srd->stored_texel_size = 1.0 / (float)linfo->shadow_cascade_size; - - DRW_uniformbuffer_update(sldata->shadow_render_ubo, &linfo->shadow_render_data); - - copy_m4_m4(viewmat, evscd->viewmat); - invert_m4_m4(render_mats.mat[DRW_MAT_VIEWINV], viewmat); - - /* 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++) { - copy_m4_m4(winmat, evscd->projmat[j]); - copy_m4_m4(persmat, evscd->viewprojmat[j]); - invert_m4_m4(render_mats.mat[DRW_MAT_WININV], winmat); - invert_m4_m4(render_mats.mat[DRW_MAT_PERSINV], persmat); - - DRW_viewport_matrix_override_set_all(&render_mats); - - 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); - } - - /* TODO: OPTI: Filter all cascade in one/two draw call */ - for (linfo->current_shadow_cascade = 0; - linfo->current_shadow_cascade < la->cascade_count; - ++linfo->current_shadow_cascade) - { - /* 0.01f factor to convert to percentage */ - float filter_texture_size = la->soft * 0.01f / evscd->radius[linfo->current_shadow_cascade]; - float filter_pixel_size = ceil(linfo->shadow_cascade_size * filter_texture_size); - - /* Copy using a small 3x3 box filter */ - /* NOTE: We always do it in the case of CSM because of artifacts in the farthest cascade. */ - linfo->filter_size = srd->stored_texel_size; - GPU_framebuffer_texture_layer_attach( - sldata->shadow_cascade_store_fb, sldata->shadow_cascade_blur, 0, linfo->current_shadow_cascade, 0); - GPU_framebuffer_bind(sldata->shadow_cascade_store_fb); - DRW_draw_pass(psl->shadow_cascade_copy_pass); - - /* Push it to shadowmap array and blur more */ - - /* 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) { - linfo->filter_size = 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 = min_ii(max_sample, 4 + 8 * (int)filter_pixel_size + 4 * (int)(pix_size_sqr)); - } - else { - linfo->filter_size = 0.0f; - srd->shadow_samples_len = 4; - } - srd->shadow_samples_len_inv = 1.0f / (float)srd->shadow_samples_len; - DRW_uniformbuffer_update(sldata->shadow_render_ubo, &linfo->shadow_render_data); - - int layer = evscd->layer_id + linfo->current_shadow_cascade; - GPU_framebuffer_texture_layer_attach(sldata->shadow_cascade_store_fb, sldata->shadow_cascade_pool, 0, layer, 0); - GPU_framebuffer_bind(sldata->shadow_cascade_store_fb); - - DRWPass *store_pass = eevee_lights_cascade_store_pass_get(psl, sldata, linfo->shadow_method, srd->shadow_samples_len); - DRW_draw_pass(store_pass); - } - } - - DRW_stats_group_end(); - - DRW_viewport_matrix_override_set_all(&saved_mats); - - 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); + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; + 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; + + DRWMatrixState saved_mats; + int saved_ray_type = sldata->common_data.ray_type; + + /* TODO: make it optionnal 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(&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(plane); + } + + /* We need to save the Matrices before overidding them */ + DRW_viewport_matrix_get_all(&saved_mats); + + /* 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; + } + + DRWMatrixState render_mats; + float(*winmat)[4] = render_mats.mat[DRW_MAT_WIN]; + float(*viewmat)[4] = render_mats.mat[DRW_MAT_VIEW]; + float(*persmat)[4] = render_mats.mat[DRW_MAT_PERS]; + + 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; + copy_v3_v3(srd->position, cube_data->position); + + perspective_m4(winmat, + -srd->clip_near, + srd->clip_near, + -srd->clip_near, + srd->clip_near, + srd->clip_near, + srd->clip_far); + + DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd); + + /* 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++) { + /* TODO optimize */ + float tmp[4][4]; + unit_m4(tmp); + negate_v3_v3(tmp[3], srd->position); + mul_m4_m4m4(viewmat, cubefacemat[j], tmp); + mul_m4_m4m4(persmat, winmat, viewmat); + invert_m4_m4(render_mats.mat[DRW_MAT_WININV], winmat); + invert_m4_m4(render_mats.mat[DRW_MAT_VIEWINV], viewmat); + invert_m4_m4(render_mats.mat[DRW_MAT_PERSINV], persmat); + + DRW_viewport_matrix_override_set_all(&render_mats); + + 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); + linfo->filter_size = srd->cube_texel_size * ((filter_pixel_size > 1.0f) ? 1.5f : 0.0f); + + /* TODO: OPTI: Filter all faces in one/two draw call */ + /* TODO: OPTI: Don't do this intermediate step if no filter is needed. */ + for (linfo->current_shadow_face = 0; linfo->current_shadow_face < 6; + linfo->current_shadow_face++) { + /* Copy using a small 3x3 box filter */ + GPU_framebuffer_texture_cubeface_attach(sldata->shadow_cube_store_fb, + sldata->shadow_cube_blur, + 0, + linfo->current_shadow_face, + 0); + GPU_framebuffer_bind(sldata->shadow_cube_store_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) { + linfo->filter_size = 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 = min_ii(max_sample, + 4 + 8 * (int)filter_pixel_size + 4 * (int)(pix_size_sqr)); + } + else { + linfo->filter_size = 0.0f; + srd->shadow_samples_len = 4; + } + srd->shadow_samples_len_inv = 1.0f / (float)srd->shadow_samples_len; + DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd); + + GPU_framebuffer_texture_layer_attach( + sldata->shadow_cube_store_fb, sldata->shadow_cube_pool, 0, evscd->layer_id, 0); + GPU_framebuffer_bind(sldata->shadow_cube_store_fb); + + DRWPass *store_pass = eevee_lights_cube_store_pass_get( + psl, sldata, linfo->shadow_method, srd->shadow_samples_len); + 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(); + + DRW_viewport_matrix_override_set_all(&saved_mats); + float near = DRW_viewport_near_distance_get(); + float far = DRW_viewport_far_distance_get(); + + /* 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; + + DRWMatrixState render_mats; + float(*winmat)[4] = render_mats.mat[DRW_MAT_WIN]; + float(*viewmat)[4] = render_mats.mat[DRW_MAT_VIEW]; + float(*persmat)[4] = render_mats.mat[DRW_MAT_PERS]; + + eevee_shadow_cascade_setup( + ob, linfo, led, &saved_mats, near, far, effects->taa_current_sample - 1); + + srd->clip_near = la->clipsta; + srd->clip_far = la->clipend; + srd->stored_texel_size = 1.0 / (float)linfo->shadow_cascade_size; + + DRW_uniformbuffer_update(sldata->shadow_render_ubo, &linfo->shadow_render_data); + + copy_m4_m4(viewmat, evscd->viewmat); + invert_m4_m4(render_mats.mat[DRW_MAT_VIEWINV], viewmat); + + /* 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++) { + copy_m4_m4(winmat, evscd->projmat[j]); + copy_m4_m4(persmat, evscd->viewprojmat[j]); + invert_m4_m4(render_mats.mat[DRW_MAT_WININV], winmat); + invert_m4_m4(render_mats.mat[DRW_MAT_PERSINV], persmat); + + DRW_viewport_matrix_override_set_all(&render_mats); + + 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); + } + + /* TODO: OPTI: Filter all cascade in one/two draw call */ + for (linfo->current_shadow_cascade = 0; linfo->current_shadow_cascade < la->cascade_count; + ++linfo->current_shadow_cascade) { + /* 0.01f factor to convert to percentage */ + float filter_texture_size = la->soft * 0.01f / evscd->radius[linfo->current_shadow_cascade]; + float filter_pixel_size = ceil(linfo->shadow_cascade_size * filter_texture_size); + + /* Copy using a small 3x3 box filter */ + /* NOTE: We always do it in the case of CSM because of artifacts in the farthest cascade. */ + linfo->filter_size = srd->stored_texel_size; + GPU_framebuffer_texture_layer_attach(sldata->shadow_cascade_store_fb, + sldata->shadow_cascade_blur, + 0, + linfo->current_shadow_cascade, + 0); + GPU_framebuffer_bind(sldata->shadow_cascade_store_fb); + DRW_draw_pass(psl->shadow_cascade_copy_pass); + + /* Push it to shadowmap array and blur more */ + + /* 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) { + linfo->filter_size = 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 = min_ii(max_sample, + 4 + 8 * (int)filter_pixel_size + 4 * (int)(pix_size_sqr)); + } + else { + linfo->filter_size = 0.0f; + srd->shadow_samples_len = 4; + } + srd->shadow_samples_len_inv = 1.0f / (float)srd->shadow_samples_len; + DRW_uniformbuffer_update(sldata->shadow_render_ubo, &linfo->shadow_render_data); + + int layer = evscd->layer_id + linfo->current_shadow_cascade; + GPU_framebuffer_texture_layer_attach( + sldata->shadow_cascade_store_fb, sldata->shadow_cascade_pool, 0, layer, 0); + GPU_framebuffer_bind(sldata->shadow_cascade_store_fb); + + DRWPass *store_pass = eevee_lights_cascade_store_pass_get( + psl, sldata, linfo->shadow_method, srd->shadow_samples_len); + DRW_draw_pass(store_pass); + } + } + + DRW_stats_group_end(); + + DRW_viewport_matrix_override_set_all(&saved_mats); + + 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]); - } + 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]); + } } |