416 lines
16 KiB
C
416 lines
16 KiB
C
/*
|
|
* 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_string_utils.h"
|
|
#include "BLI_sys_types.h" /* bool */
|
|
|
|
#include "BKE_object.h"
|
|
|
|
#include "DEG_depsgraph_query.h"
|
|
|
|
#include "eevee_private.h"
|
|
|
|
#define SH_CASTER_ALLOC_CHUNK 32
|
|
|
|
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 (!sldata->lights) {
|
|
sldata->lights = MEM_callocN(sizeof(EEVEE_LightsInfo), "EEVEE_LightsInfo");
|
|
sldata->light_ubo = GPU_uniformbuf_create_ex(sizeof(EEVEE_Light) * MAX_LIGHT, NULL, "evLight");
|
|
sldata->shadow_ubo = GPU_uniformbuf_create_ex(shadow_ubo_size, NULL, "evShadow");
|
|
|
|
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(EEVEE_shaders_shadow_sh_get(),
|
|
psl->shadow_pass);
|
|
}
|
|
}
|
|
|
|
/* 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 shadow-maps 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) {
|
|
sldata->shadow_cube_pool = DRW_texture_create_2d_array(linfo->shadow_cube_size,
|
|
linfo->shadow_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("shadow_fb");
|
|
}
|
|
|
|
/* 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 shadow-caster 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 shadow-caster 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 = linfo->cascade_len > 0;
|
|
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) {
|
|
sldata->common_data.ray_type = EEVEE_RAY_SHADOW;
|
|
GPU_uniformbuf_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);
|
|
|
|
GPU_uniformbuf_update(sldata->shadow_ubo, &linfo->shadow_data); /* Update all data at once */
|
|
|
|
if (any_visible) {
|
|
sldata->common_data.ray_type = saved_ray_type;
|
|
GPU_uniformbuf_update(sldata->common_ubo, &sldata->common_data);
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Render Passes
|
|
* \{ */
|
|
|
|
void EEVEE_shadow_output_init(EEVEE_ViewLayerData *sldata,
|
|
EEVEE_Data *vedata,
|
|
uint UNUSED(tot_samples))
|
|
{
|
|
EEVEE_FramebufferList *fbl = vedata->fbl;
|
|
EEVEE_TextureList *txl = vedata->txl;
|
|
EEVEE_PassList *psl = vedata->psl;
|
|
EEVEE_StorageList *stl = vedata->stl;
|
|
EEVEE_EffectsInfo *effects = stl->effects;
|
|
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
|
|
|
|
const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
|
|
|
/* Create FrameBuffer. */
|
|
const eGPUTextureFormat texture_format = GPU_R32F;
|
|
DRW_texture_ensure_fullscreen_2d(&txl->shadow_accum, texture_format, 0);
|
|
|
|
GPU_framebuffer_ensure_config(&fbl->shadow_accum_fb,
|
|
{GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->shadow_accum)});
|
|
|
|
/* Clear texture. */
|
|
if (effects->taa_current_sample == 1) {
|
|
GPU_framebuffer_bind(fbl->shadow_accum_fb);
|
|
GPU_framebuffer_clear_color(fbl->shadow_accum_fb, clear);
|
|
}
|
|
|
|
/* Create Pass and shgroup. */
|
|
DRW_PASS_CREATE(psl->shadow_accum_pass,
|
|
DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS | DRW_STATE_BLEND_ADD_FULL);
|
|
DRWShadingGroup *grp = DRW_shgroup_create(EEVEE_shaders_shadow_accum_sh_get(),
|
|
psl->shadow_accum_pass);
|
|
DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
|
|
DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
|
|
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);
|
|
DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
|
|
DRW_shgroup_uniform_texture_ref(grp, "shadowCubeTexture", &sldata->shadow_cube_pool);
|
|
DRW_shgroup_uniform_texture_ref(grp, "shadowCascadeTexture", &sldata->shadow_cascade_pool);
|
|
|
|
DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
|
|
}
|
|
|
|
void EEVEE_shadow_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
|
|
{
|
|
EEVEE_FramebufferList *fbl = vedata->fbl;
|
|
EEVEE_PassList *psl = vedata->psl;
|
|
|
|
if (fbl->shadow_accum_fb != NULL) {
|
|
GPU_framebuffer_bind(fbl->shadow_accum_fb);
|
|
DRW_draw_pass(psl->shadow_accum_pass);
|
|
|
|
/* Restore */
|
|
GPU_framebuffer_bind(fbl->main_fb);
|
|
}
|
|
}
|
|
|
|
/** \} */
|