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:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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. */
|
||||
|
||||
Reference in New Issue
Block a user