Fix: EEVEE-Next: Shadow acnee during viewport transform

The issue would happened in any situation where the light
moves (update, animation, jitter) or have a lot of LOD
tagged by moving casters. In these cases, the actual
effective LOD min is bigger than the one from the UI which
results in shadow acnee artifacts (because the computed bias
is too small).

This patch saves the effective min LOD per tilemaps and
amend the `light.lod_min` to replace it by the min of
all tilemaps in used by one light.
This commit is contained in:
Clément Foucault
2024-06-04 12:47:00 +02:00
parent 6a61cdbb5a
commit 6ce4e94eb9
5 changed files with 40 additions and 4 deletions

View File

@@ -1317,8 +1317,8 @@ struct ShadowTileMapData {
eLightType light_type;
/** Entire tilemap (all tiles) needs to be tagged as dirty. */
bool32_t is_dirty;
float _pad1;
/** Effective minimum resolution after update throttle. */
int effective_lod_min;
float _pad2;
/** Near and far clip distances for punctual. */
float clip_near;

View File

@@ -1043,6 +1043,7 @@ void ShadowModule::end_sync()
PassSimple::Sub &sub = pass.sub("Amend");
sub.shader_set(inst_.shaders.static_shader_get(SHADOW_TILEMAP_AMEND));
sub.bind_image("tilemaps_img", tilemap_pool.tilemap_tx);
sub.bind_ssbo("tilemaps_buf", tilemap_pool.tilemaps_data);
sub.bind_resources(inst_.lights);
sub.dispatch(int3(1));
sub.barrier(GPU_BARRIER_TEXTURE_FETCH);

View File

@@ -155,6 +155,8 @@ void main()
for (int i = 1; i < max_view_per_tilemap; i++) {
max_lod = findMSB(levels_rendered & ~(~0u << max_lod));
}
/* Note: Concurent writting of the same value to the same data. */
tilemaps_buf[tilemap_index].effective_lod_min = max_lod;
/* Collapse all bits to highest level. */
for (int lod = 0; lod < max_lod; lod++) {
if (thread_mask(tile_co, lod)) {
@@ -174,6 +176,13 @@ void main()
}
}
}
else {
/* Note: Concurent writting of the same value to the same data. */
tilemaps_buf[tilemap_index].effective_lod_min = 0;
}
#else
/* Note: Concurent writting of the same value to the same data. */
tilemaps_buf[tilemap_index].effective_lod_min = 0;
#endif
barrier();

View File

@@ -94,4 +94,26 @@ void main()
}
}
LIGHT_FOREACH_END
LIGHT_FOREACH_BEGIN_LOCAL_NO_CULL(light_cull_buf, l_idx)
{
LightData light = light_buf[l_idx];
if (light.tilemap_index == LIGHT_NO_SHADOW) {
continue;
}
int lod_min = 0;
int tilemap_count = light_local_tilemap_count(light);
for (int i = 0; i < tilemap_count; i++) {
ShadowTileMapData tilemap = tilemaps_buf[light.tilemap_index + i];
lod_min = max(lod_min, tilemap.effective_lod_min);
}
if (lod_min > 0) {
/* Override the effective lod min distance in absolute mode (negative).
* Note that this only changes the sampling for this AA sample. */
const float projection_diagonal = 2.0 * M_SQRT2;
light_buf[l_idx].lod_min = -(projection_diagonal / float(SHADOW_MAP_MAX_RES >> lod_min));
}
}
LIGHT_FOREACH_END
}

View File

@@ -128,7 +128,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_page_mask)
.do_static_compilation(true)
.local_group_size(SHADOW_TILEMAP_RES, SHADOW_TILEMAP_RES)
.push_constant(Type::INT, "max_view_per_tilemap")
.storage_buf(0, Qualifier::READ, "ShadowTileMapData", "tilemaps_buf[]")
.storage_buf(0, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
.additional_info("eevee_shared")
.compute_source("eevee_shadow_page_mask_comp.glsl");
@@ -196,7 +196,11 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tilemap_amend)
.do_static_compilation(true)
.local_group_size(SHADOW_TILEMAP_RES, SHADOW_TILEMAP_RES)
.image(0, GPU_R32UI, Qualifier::READ_WRITE, ImageType::UINT_2D, "tilemaps_img")
.additional_info("eevee_shared", "eevee_light_data", "draw_view")
.storage_buf(LIGHT_CULL_BUF_SLOT, Qualifier::READ, "LightCullingData", "light_cull_buf")
.storage_buf(LIGHT_BUF_SLOT, Qualifier::READ_WRITE, "LightData", "light_buf[]")
/* The call bind_resources(lights) also uses LIGHT_ZBIN_BUF_SLOT and LIGHT_TILE_BUF_SLOT. */
.storage_buf(4, Qualifier::READ, "ShadowTileMapData", "tilemaps_buf[]")
.additional_info("eevee_shared", "draw_view")
.compute_source("eevee_shadow_tilemap_amend_comp.glsl");
/* AtomicMin clear implementation. */