Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2019-08-22 17:04:25 +0300
committerClément Foucault <foucault.clem@gmail.com>2019-09-05 18:37:50 +0300
commitd8aaf25c23fa10ee121dc4fdd1cafe544bcca355 (patch)
treeb5a16157beac22e4b474c699c1ce25f3d8c5be51 /source/blender/draw/engines/eevee/eevee_shadows.c
parentca58936f2ff2b14a649722be20d98f8fa35831ff (diff)
Eevee: Shadow map refactor
Reviewed By: brecht Differential Revision: http://developer.blender.org/D5659
Diffstat (limited to 'source/blender/draw/engines/eevee/eevee_shadows.c')
-rw-r--r--source/blender/draw/engines/eevee/eevee_shadows.c412
1 files changed, 412 insertions, 0 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_shadows.c b/source/blender/draw/engines/eevee/eevee_shadows.c
new file mode 100644
index 00000000000..a709e668f34
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_shadows.c
@@ -0,0 +1,412 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup EEVEE
+ */
+
+#include "BLI_sys_types.h" /* bool */
+
+// #include "BLI_dynstr.h"
+// #include "BLI_rand.h"
+
+#include "BKE_object.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "eevee_private.h"
+
+#define SH_CASTER_ALLOC_CHUNK 32
+
+static struct {
+ struct GPUShader *shadow_sh;
+} e_data = {NULL}; /* Engine data */
+
+extern char datatoc_shadow_vert_glsl[];
+extern char datatoc_shadow_frag_glsl[];
+extern char datatoc_common_view_lib_glsl[];
+
+void eevee_contact_shadow_setup(const Light *la, EEVEE_Shadow *evsh)
+{
+ evsh->contact_dist = (la->mode & LA_SHAD_CONTACT) ? la->contact_dist : 0.0f;
+ evsh->contact_bias = 0.05f * la->contact_bias;
+ evsh->contact_thickness = la->contact_thickness;
+}
+
+void EEVEE_shadows_init(EEVEE_ViewLayerData *sldata)
+{
+ const uint shadow_ubo_size = sizeof(EEVEE_Shadow) * MAX_SHADOW +
+ sizeof(EEVEE_ShadowCube) * MAX_SHADOW_CUBE +
+ sizeof(EEVEE_ShadowCascade) * MAX_SHADOW_CASCADE;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+
+ if (!e_data.shadow_sh) {
+ e_data.shadow_sh = DRW_shader_create_with_lib(datatoc_shadow_vert_glsl,
+ NULL,
+ datatoc_shadow_frag_glsl,
+ datatoc_common_view_lib_glsl,
+ NULL);
+ }
+
+ if (!sldata->lights) {
+ sldata->lights = MEM_callocN(sizeof(EEVEE_LightsInfo), "EEVEE_LightsInfo");
+ sldata->light_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_Light) * MAX_LIGHT, NULL);
+ sldata->shadow_ubo = DRW_uniformbuffer_create(shadow_ubo_size, NULL);
+
+ for (int i = 0; i < 2; ++i) {
+ sldata->shcasters_buffers[i].bbox = MEM_callocN(
+ sizeof(EEVEE_BoundBox) * SH_CASTER_ALLOC_CHUNK, __func__);
+ sldata->shcasters_buffers[i].update = BLI_BITMAP_NEW(SH_CASTER_ALLOC_CHUNK, __func__);
+ sldata->shcasters_buffers[i].alloc_count = SH_CASTER_ALLOC_CHUNK;
+ sldata->shcasters_buffers[i].count = 0;
+ }
+ sldata->lights->shcaster_frontbuffer = &sldata->shcasters_buffers[0];
+ sldata->lights->shcaster_backbuffer = &sldata->shcasters_buffers[1];
+ }
+
+ /* Flip buffers */
+ SWAP(EEVEE_ShadowCasterBuffer *,
+ sldata->lights->shcaster_frontbuffer,
+ sldata->lights->shcaster_backbuffer);
+
+ int sh_cube_size = scene_eval->eevee.shadow_cube_size;
+ int sh_cascade_size = scene_eval->eevee.shadow_cascade_size;
+ const bool sh_high_bitdepth = (scene_eval->eevee.flag & SCE_EEVEE_SHADOW_HIGH_BITDEPTH) != 0;
+ sldata->lights->soft_shadows = (scene_eval->eevee.flag & SCE_EEVEE_SHADOW_SOFT) != 0;
+
+ EEVEE_LightsInfo *linfo = sldata->lights;
+ if ((linfo->shadow_cube_size != sh_cube_size) ||
+ (linfo->shadow_high_bitdepth != sh_high_bitdepth)) {
+ BLI_assert((sh_cube_size > 0) && (sh_cube_size <= 4096));
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_pool);
+ CLAMP(sh_cube_size, 1, 4096);
+ }
+
+ if ((linfo->shadow_cascade_size != sh_cascade_size) ||
+ (linfo->shadow_high_bitdepth != sh_high_bitdepth)) {
+ BLI_assert((sh_cascade_size > 0) && (sh_cascade_size <= 4096));
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_pool);
+ CLAMP(sh_cascade_size, 1, 4096);
+ }
+
+ linfo->shadow_high_bitdepth = sh_high_bitdepth;
+ linfo->shadow_cube_size = sh_cube_size;
+ linfo->shadow_cascade_size = sh_cascade_size;
+}
+
+void EEVEE_shadows_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_LightsInfo *linfo = sldata->lights;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_PassList *psl = vedata->psl;
+
+ EEVEE_ShadowCasterBuffer *backbuffer = linfo->shcaster_backbuffer;
+ EEVEE_ShadowCasterBuffer *frontbuffer = linfo->shcaster_frontbuffer;
+
+ frontbuffer->count = 0;
+ linfo->num_cube_layer = 0;
+ linfo->num_cascade_layer = 0;
+ linfo->cube_len = linfo->cascade_len = linfo->shadow_len = 0;
+
+ /* Shadow Casters: Reset flags. */
+ BLI_bitmap_set_all(backbuffer->update, true, backbuffer->alloc_count);
+ /* Is this one needed? */
+ BLI_bitmap_set_all(frontbuffer->update, false, frontbuffer->alloc_count);
+
+ INIT_MINMAX(linfo->shcaster_aabb.min, linfo->shcaster_aabb.max);
+
+ {
+ DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_SHADOW_OFFSET;
+ DRW_PASS_CREATE(psl->shadow_pass, state);
+
+ stl->g_data->shadow_shgrp = DRW_shgroup_create(e_data.shadow_sh, psl->shadow_pass);
+ }
+}
+
+/* Add a shadow caster to the shadowpasses */
+void EEVEE_shadows_caster_add(EEVEE_ViewLayerData *UNUSED(sldata),
+ EEVEE_StorageList *stl,
+ struct GPUBatch *geom,
+ Object *ob)
+{
+ DRW_shgroup_call(stl->g_data->shadow_shgrp, geom, ob);
+}
+
+void EEVEE_shadows_caster_material_add(EEVEE_ViewLayerData *sldata,
+ EEVEE_PassList *psl,
+ struct GPUMaterial *gpumat,
+ struct GPUBatch *geom,
+ struct Object *ob,
+ const float *alpha_threshold)
+{
+ /* TODO / PERF : reuse the same shading group for objects with the same material */
+ DRWShadingGroup *grp = DRW_shgroup_material_create(gpumat, psl->shadow_pass);
+
+ if (grp == NULL) {
+ return;
+ }
+
+ /* Grrr needed for correctness but not 99% of the time not needed.
+ * TODO detect when needed? */
+ DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
+ DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
+ DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
+ DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
+ DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+
+ if (alpha_threshold != NULL) {
+ DRW_shgroup_uniform_float(grp, "alphaThreshold", alpha_threshold, 1);
+ }
+
+ DRW_shgroup_call(grp, geom, ob);
+}
+
+/* Make that object update shadow casting lights inside its influence bounding box. */
+void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, Object *ob)
+{
+ EEVEE_LightsInfo *linfo = sldata->lights;
+ EEVEE_ShadowCasterBuffer *backbuffer = linfo->shcaster_backbuffer;
+ EEVEE_ShadowCasterBuffer *frontbuffer = linfo->shcaster_frontbuffer;
+ bool update = true;
+ int id = frontbuffer->count;
+
+ /* Make sure shadow_casters is big enough. */
+ if (id + 1 >= frontbuffer->alloc_count) {
+ frontbuffer->alloc_count += SH_CASTER_ALLOC_CHUNK;
+ frontbuffer->bbox = MEM_reallocN(frontbuffer->bbox,
+ sizeof(EEVEE_BoundBox) * frontbuffer->alloc_count);
+ BLI_BITMAP_RESIZE(frontbuffer->update, frontbuffer->alloc_count);
+ }
+
+ if (ob->base_flag & BASE_FROM_DUPLI) {
+ /* Duplis will always refresh the shadowmaps as if they were deleted each frame. */
+ /* TODO(fclem) fix this. */
+ update = true;
+ }
+ else {
+ EEVEE_ObjectEngineData *oedata = EEVEE_object_data_ensure(ob);
+ int past_id = oedata->shadow_caster_id;
+ oedata->shadow_caster_id = id;
+ /* Update flags in backbuffer. */
+ if (past_id > -1 && past_id < backbuffer->count) {
+ BLI_BITMAP_SET(backbuffer->update, past_id, oedata->need_update);
+ }
+ update = oedata->need_update;
+ oedata->need_update = false;
+ }
+
+ if (update) {
+ BLI_BITMAP_ENABLE(frontbuffer->update, id);
+ }
+
+ /* Update World AABB in frontbuffer. */
+ BoundBox *bb = BKE_object_boundbox_get(ob);
+ float min[3], max[3];
+ INIT_MINMAX(min, max);
+ for (int i = 0; i < 8; ++i) {
+ float vec[3];
+ copy_v3_v3(vec, bb->vec[i]);
+ mul_m4_v3(ob->obmat, vec);
+ minmax_v3v3_v3(min, max, vec);
+ }
+
+ EEVEE_BoundBox *aabb = &frontbuffer->bbox[id];
+ add_v3_v3v3(aabb->center, min, max);
+ mul_v3_fl(aabb->center, 0.5f);
+ sub_v3_v3v3(aabb->halfdim, aabb->center, max);
+
+ aabb->halfdim[0] = fabsf(aabb->halfdim[0]);
+ aabb->halfdim[1] = fabsf(aabb->halfdim[1]);
+ aabb->halfdim[2] = fabsf(aabb->halfdim[2]);
+
+ minmax_v3v3_v3(linfo->shcaster_aabb.min, linfo->shcaster_aabb.max, min);
+ minmax_v3v3_v3(linfo->shcaster_aabb.min, linfo->shcaster_aabb.max, max);
+
+ frontbuffer->count++;
+}
+
+/* Used for checking if object is inside the shadow volume. */
+static bool sphere_bbox_intersect(const BoundSphere *bs, const EEVEE_BoundBox *bb)
+{
+ /* We are testing using a rougher AABB vs AABB test instead of full AABB vs Sphere. */
+ /* TODO test speed with AABB vs Sphere. */
+ bool x = fabsf(bb->center[0] - bs->center[0]) <= (bb->halfdim[0] + bs->radius);
+ bool y = fabsf(bb->center[1] - bs->center[1]) <= (bb->halfdim[1] + bs->radius);
+ bool z = fabsf(bb->center[2] - bs->center[2]) <= (bb->halfdim[2] + bs->radius);
+
+ return x && y && z;
+}
+
+void EEVEE_shadows_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+ EEVEE_LightsInfo *linfo = sldata->lights;
+ EEVEE_ShadowCasterBuffer *backbuffer = linfo->shcaster_backbuffer;
+ EEVEE_ShadowCasterBuffer *frontbuffer = linfo->shcaster_frontbuffer;
+
+ eGPUTextureFormat shadow_pool_format = (linfo->shadow_high_bitdepth) ? GPU_DEPTH_COMPONENT24 :
+ GPU_DEPTH_COMPONENT16;
+ /* Setup enough layers. */
+ /* Free textures if number mismatch. */
+ if (linfo->num_cube_layer != linfo->cache_num_cube_layer) {
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_pool);
+ linfo->cache_num_cube_layer = linfo->num_cube_layer;
+ /* Update all lights. */
+ BLI_bitmap_set_all(&linfo->sh_cube_update[0], true, MAX_LIGHT);
+ }
+
+ if (linfo->num_cascade_layer != linfo->cache_num_cascade_layer) {
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_pool);
+ linfo->cache_num_cascade_layer = linfo->num_cascade_layer;
+ }
+
+ if (!sldata->shadow_cube_pool) {
+ /* TODO shadowcube array. */
+ int cube_size = linfo->shadow_cube_size + ((true) ? 2 : 0);
+ sldata->shadow_cube_pool = DRW_texture_create_2d_array(cube_size,
+ cube_size,
+ max_ii(1, linfo->num_cube_layer * 6),
+ shadow_pool_format,
+ DRW_TEX_FILTER | DRW_TEX_COMPARE,
+ NULL);
+ }
+
+ if (!sldata->shadow_cascade_pool) {
+ sldata->shadow_cascade_pool = DRW_texture_create_2d_array(linfo->shadow_cascade_size,
+ linfo->shadow_cascade_size,
+ max_ii(1, linfo->num_cascade_layer),
+ shadow_pool_format,
+ DRW_TEX_FILTER | DRW_TEX_COMPARE,
+ NULL);
+ }
+
+ if (sldata->shadow_fb == NULL) {
+ sldata->shadow_fb = GPU_framebuffer_create();
+ }
+
+ /* Gather all light own update bits. to avoid costly intersection check. */
+ for (int j = 0; j < linfo->cube_len; j++) {
+ const EEVEE_Light *evli = linfo->light_data + linfo->shadow_cube_light_indices[j];
+ /* Setup shadow cube in UBO and tag for update if necessary. */
+ if (EEVEE_shadows_cube_setup(linfo, evli, effects->taa_current_sample - 1)) {
+ BLI_BITMAP_ENABLE(&linfo->sh_cube_update[0], j);
+ }
+ }
+
+ /* TODO(fclem) This part can be slow, optimize it. */
+ EEVEE_BoundBox *bbox = backbuffer->bbox;
+ BoundSphere *bsphere = linfo->shadow_bounds;
+ /* Search for deleted shadow casters or if shcaster WAS in shadow radius. */
+ for (int i = 0; i < backbuffer->count; ++i) {
+ /* If the shadowcaster has been deleted or updated. */
+ if (BLI_BITMAP_TEST(backbuffer->update, i)) {
+ for (int j = 0; j < linfo->cube_len; j++) {
+ if (!BLI_BITMAP_TEST(&linfo->sh_cube_update[0], j)) {
+ if (sphere_bbox_intersect(&bsphere[j], &bbox[i])) {
+ BLI_BITMAP_ENABLE(&linfo->sh_cube_update[0], j);
+ }
+ }
+ }
+ }
+ }
+ /* Search for updates in current shadow casters. */
+ bbox = frontbuffer->bbox;
+ for (int i = 0; i < frontbuffer->count; i++) {
+ /* If the shadowcaster has been updated. */
+ if (BLI_BITMAP_TEST(frontbuffer->update, i)) {
+ for (int j = 0; j < linfo->cube_len; j++) {
+ if (!BLI_BITMAP_TEST(&linfo->sh_cube_update[0], j)) {
+ if (sphere_bbox_intersect(&bsphere[j], &bbox[i])) {
+ BLI_BITMAP_ENABLE(&linfo->sh_cube_update[0], j);
+ }
+ }
+ }
+ }
+ }
+
+ /* Resize shcasters buffers if too big. */
+ if (frontbuffer->alloc_count - frontbuffer->count > SH_CASTER_ALLOC_CHUNK) {
+ frontbuffer->alloc_count = (frontbuffer->count / SH_CASTER_ALLOC_CHUNK) *
+ SH_CASTER_ALLOC_CHUNK;
+ frontbuffer->alloc_count += (frontbuffer->count % SH_CASTER_ALLOC_CHUNK != 0) ?
+ SH_CASTER_ALLOC_CHUNK :
+ 0;
+ frontbuffer->bbox = MEM_reallocN(frontbuffer->bbox,
+ sizeof(EEVEE_BoundBox) * frontbuffer->alloc_count);
+ BLI_BITMAP_RESIZE(frontbuffer->update, frontbuffer->alloc_count);
+ }
+}
+
+/* this refresh lights shadow buffers */
+void EEVEE_shadows_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, DRWView *view)
+{
+ EEVEE_LightsInfo *linfo = sldata->lights;
+
+ int saved_ray_type = sldata->common_data.ray_type;
+
+ /* Precompute all shadow/view test before rendering and trashing the culling cache. */
+ BLI_bitmap *cube_visible = BLI_BITMAP_NEW_ALLOCA(MAX_SHADOW_CUBE);
+ bool any_visible = false;
+ for (int cube = 0; cube < linfo->cube_len; cube++) {
+ if (DRW_culling_sphere_test(view, linfo->shadow_bounds + cube)) {
+ BLI_BITMAP_ENABLE(cube_visible, cube);
+ any_visible = true;
+ }
+ }
+
+ if (!any_visible && linfo->cascade_len == 0) {
+ sldata->common_data.ray_type = EEVEE_RAY_SHADOW;
+ DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
+ }
+
+ DRW_stats_group_start("Cube Shadow Maps");
+ {
+ for (int cube = 0; cube < linfo->cube_len; cube++) {
+ if (BLI_BITMAP_TEST(cube_visible, cube) && BLI_BITMAP_TEST(linfo->sh_cube_update, cube)) {
+ EEVEE_shadows_draw_cubemap(sldata, vedata, cube);
+ }
+ }
+ }
+ DRW_stats_group_end();
+
+ DRW_stats_group_start("Cascaded Shadow Maps");
+ {
+ for (int cascade = 0; cascade < linfo->cascade_len; cascade++) {
+ EEVEE_shadows_draw_cascades(sldata, vedata, view, cascade);
+ }
+ }
+ DRW_stats_group_end();
+
+ DRW_view_set_active(view);
+
+ DRW_uniformbuffer_update(sldata->shadow_ubo, &linfo->shadow_data); /* Update all data at once */
+
+ if (!any_visible && linfo->cascade_len == 0) {
+ sldata->common_data.ray_type = saved_ray_type;
+ DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
+ }
+}
+
+void EEVEE_shadows_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.shadow_sh);
+} \ No newline at end of file