EEVEE-Next: Split clipmap_base_offset into two int2

This avoid uneeded complexity since we have a lot of space
inside the sunlight struct.
This commit is contained in:
Clément Foucault 2024-03-28 12:38:56 +01:00
parent b59059a518
commit 28c53cccd3
6 changed files with 43 additions and 29 deletions

View File

@ -793,12 +793,12 @@ static inline bool is_local_light(eLightType type)
/** --- Shadow Data --- */ \
/** Other parts of the perspective matrix. Assumes symmetric frustum. */ \
float clip_side; \
/** Number of allocated tilemap for this local light. */ \
int tilemaps_count; \
/** Scaling factor to the light shape for shadow ray casting. */ \
float shadow_scale; \
/** Shift to apply to the light origin to get the shadow projection origin. */ \
float shadow_projection_shift; \
/** Number of allocated tilemap for this local light. */ \
int tilemaps_count;
float shadow_projection_shift;
/* Untyped local light data. Gets reinterpreted to LightSpotData and LightAreaData.
* Allow access to local light common data without casting. */
@ -861,12 +861,11 @@ struct LightSunData {
float _pad3;
float _pad4;
float _pad5;
float _pad6;
/** --- Shadow Data --- */
/** Offset of the LOD min in LOD min tile units. */
int2 clipmap_base_offset;
/** Offset of the LOD min in LOD min tile units. Split positive and negative for bit-shift. */
int2 clipmap_base_offset_neg;
int2 clipmap_base_offset_pos;
/** Angle covered by the light shape for shadow ray casting. */
float shadow_angle;
/** Trace distance around the shading point. */
@ -1073,7 +1072,8 @@ static inline LightSunData light_sun_data_get(LightData light)
{
SAFE_BEGIN(LightSunData, is_sun_light(light.type))
SAFE_ASSIGN_FLOAT(radius, radius_squared)
SAFE_ASSIGN_FLOAT_AS_INT2_COMBINE(clipmap_base_offset, _pad0_reserved, _pad1_reserved)
SAFE_ASSIGN_FLOAT_AS_INT2_COMBINE(clipmap_base_offset_neg, shadow_scale, shadow_projection_shift)
SAFE_ASSIGN_FLOAT_AS_INT2_COMBINE(clipmap_base_offset_pos, _pad0_reserved, _pad1_reserved)
SAFE_ASSIGN_FLOAT(shadow_angle, _pad1)
SAFE_ASSIGN_FLOAT(shadow_trace_distance, _pad2)
SAFE_ASSIGN_FLOAT2(clipmap_origin, _pad3)

View File

@ -490,12 +490,13 @@ void ShadowDirectional::cascade_tilemaps_distribution(Light &light, const Camera
/* Offset for smooth level transitions. */
light.object_mat.location() = near_point;
/* Offset in tiles from the origin to the center of the first tile-maps. */
/* Offset in tiles from the scene origin to the center of the first tile-maps. */
int2 origin_offset = int2(round(float2(near_point) / tile_size));
/* Offset in tiles between the first and the last tile-maps. */
int2 offset_vector = int2(round(farthest_tilemap_center / tile_size));
light.sun.clipmap_base_offset = (offset_vector * (1 << 16)) / max_ii(levels_range.size() - 1, 1);
light.sun.clipmap_base_offset_pos = (offset_vector * (1 << 16)) /
max_ii(levels_range.size() - 1, 1);
/* \note: cascade_level_range starts the range at the unique LOD to apply to all tile-maps. */
int level = levels_range.first();
@ -504,7 +505,7 @@ void ShadowDirectional::cascade_tilemaps_distribution(Light &light, const Camera
/* Equal spacing between cascades layers since we want uniform shadow density. */
int2 level_offset = origin_offset +
shadow_cascade_grid_offset(light.sun.clipmap_base_offset, i);
shadow_cascade_grid_offset(light.sun.clipmap_base_offset_pos, i);
tilemap->sync_orthographic(object_mat_, level_offset, level, 0.0f, SHADOW_PROJECTION_CASCADE);
/* Add shadow tile-maps grouped by lights to the GPU buffer. */
@ -535,8 +536,8 @@ IndexRange ShadowDirectional::clipmap_level_range(const Camera &camera)
{
using namespace blender::math;
/* Take 16 to be able to pack offset into a single int2. */
const int max_tilemap_per_shadows = 16;
/* 32 to be able to pack offset into two single int2. */
const int max_tilemap_per_shadows = 32;
int user_min_level = floorf(log2(min_resolution_));
/* Covers the farthest points of the view. */
@ -586,8 +587,7 @@ void ShadowDirectional::clipmap_tilemaps_distribution(Light &light,
* single integer where one bit contains offset between 2 levels. Then a single bit shift in
* the shader gives the number of tile to offset in the given tile-map space. However we need
* also the sign of the offset for each level offset. To this end, we split the negative
* offsets to a separate int.
* Recovering the offset with: (pos_offset >> lod) - (neg_offset >> lod). */
* offsets to a separate int. */
int2 lvl_offset_next = tilemaps_[lod + 1]->grid_offset;
int2 lvl_offset = tilemaps_[lod]->grid_offset;
int2 lvl_delta = lvl_offset - (lvl_offset_next << 1);
@ -596,9 +596,9 @@ void ShadowDirectional::clipmap_tilemaps_distribution(Light &light,
neg_offset |= math::max(-lvl_delta, int2(0)) << lod;
}
/* Compressing to a single value to save up storage in light data. Number of levels is limited to
* 16 by `clipmap_level_range()` for this reason. */
light.sun.clipmap_base_offset = pos_offset | (neg_offset << 16);
/* Number of levels is limited to 32 by `clipmap_level_range()` for this reason. */
light.sun.clipmap_base_offset_pos = pos_offset;
light.sun.clipmap_base_offset_neg = neg_offset;
float tile_size_max = ShadowDirectional::tile_size_get(levels_range.last());
int2 level_offset_max = tilemaps_[levels_range.size() - 1]->grid_offset;

View File

@ -210,7 +210,10 @@ ShadowDirectionalSampleInfo shadow_directional_sample_info_get(LightData light,
level;
info.clipmap_offset = shadow_decompress_grid_offset(
light.type, light_sun_data_get(light).clipmap_base_offset, info.level_relative);
light.type,
light_sun_data_get(light).clipmap_base_offset_neg,
light_sun_data_get(light).clipmap_base_offset_pos,
info.level_relative);
info.clipmap_origin = light_sun_data_get(light).clipmap_origin;
return info;

View File

@ -30,6 +30,8 @@ void set_clipmap_data(inout LightData light,
void set_clipmap_base_offset(inout LightData light, ivec2 clipmap_base_offset)
{
/* WATCH: Can get out of sync with light_sun_data_get(). */
light.do_not_access_directly.shadow_scale = intBitsToFloat(0);
light.do_not_access_directly.shadow_projection_shift = intBitsToFloat(0);
light.do_not_access_directly._pad0_reserved = intBitsToFloat(clipmap_base_offset.x);
light.do_not_access_directly._pad1_reserved = intBitsToFloat(clipmap_base_offset.y);
}
@ -47,7 +49,7 @@ void main()
EXPECT_EQ(light_sun_data_get(light).clipmap_lod_min, 1);
EXPECT_EQ(light_sun_data_get(light).clipmap_lod_max, 2);
EXPECT_EQ(light_sun_data_get(light).clipmap_origin, vec2(3.0, 4.0));
EXPECT_EQ(light_sun_data_get(light).clipmap_base_offset, ivec2(5, 6));
EXPECT_EQ(light_sun_data_get(light).clipmap_base_offset_pos, ivec2(5, 6));
}
TEST(eevee_shadow, DirectionalClipmapLevel)
@ -119,7 +121,7 @@ void main()
camera_lP = vec3(0.0, 0.0, 0.0);
/* Follows ShadowDirectional::end_sync(). */
set_clipmap_base_offset(light, ivec2(round(camera_lP.xy / lod_min_tile_size)));
EXPECT_EQ(light_sun_data_get(light).clipmap_base_offset, ivec2(0));
EXPECT_EQ(light_sun_data_get(light).clipmap_base_offset_pos, ivec2(0));
/* Test UVs and tile mapping. */
@ -152,7 +154,7 @@ void main()
camera_lP = vec3(2.0, 2.0, 0.0);
/* Follows ShadowDirectional::end_sync(). */
set_clipmap_base_offset(light, ivec2(round(camera_lP.xy / lod_min_tile_size)));
EXPECT_EQ(light_sun_data_get(light).clipmap_base_offset, ivec2(32));
EXPECT_EQ(light_sun_data_get(light).clipmap_base_offset_pos, ivec2(32));
lP = vec3(2.00001, 2.00001, 0.0);
coords = shadow_directional_coordinates(light, lP);
@ -278,7 +280,7 @@ void main()
// camera_lP = vec3(2.0, 2.0, 0.0);
/* Follows ShadowDirectional::end_sync(). */
// set_clipmap_base_offset(light, ivec2(round(camera_lP.xy / lod_min_tile_size)));
// EXPECT_EQ(light_sun_data_get(light).clipmap_base_offset, ivec2(32));
// EXPECT_EQ(light_sun_data_get(light).clipmap_base_offset_pos, ivec2(32));
// lP = vec3(2.00001, 2.00001, 0.0);
// coords = shadow_directional_coordinates(light, lP);

View File

@ -176,13 +176,16 @@ struct ShadowCoordinates {
};
/* Retain sign bit and avoid costly int division. */
ivec2 shadow_decompress_grid_offset(eLightType light_type, ivec2 offset, int level_relative)
ivec2 shadow_decompress_grid_offset(eLightType light_type,
ivec2 offset_neg,
ivec2 offset_pos,
int level_relative)
{
if (light_type == LIGHT_SUN_ORTHO) {
return shadow_cascade_grid_offset(offset, level_relative);
return shadow_cascade_grid_offset(offset_pos, level_relative);
}
else {
return ((offset & 0xFFFF) >> level_relative) - ((offset >> 16) >> level_relative);
return (offset_pos >> level_relative) - (offset_neg >> level_relative);
}
}
@ -203,7 +206,10 @@ ShadowCoordinates shadow_directional_coordinates_at_level(LightData light, vec3
/* Compute offset in tile. */
ivec2 clipmap_offset = shadow_decompress_grid_offset(
light.type, light_sun_data_get(light).clipmap_base_offset, level_relative);
light.type,
light_sun_data_get(light).clipmap_base_offset_neg,
light_sun_data_get(light).clipmap_base_offset_pos,
level_relative);
ret.uv = lP.xy - light_sun_data_get(light).clipmap_origin;
ret.uv /= exp2(float(ret.lod_relative));

View File

@ -252,7 +252,10 @@ ShadowTracingSample shadow_map_trace_sample(ShadowMapTracingState state,
/* Compute offset in tile. */
ivec2 clipmap_offset = shadow_decompress_grid_offset(
ray.light.type, light_sun_data_get(ray.light).clipmap_base_offset, level_relative);
ray.light.type,
light_sun_data_get(ray.light).clipmap_base_offset_neg,
light_sun_data_get(ray.light).clipmap_base_offset_pos,
level_relative);
/* Translate tilemap UVs to its origin. */
tilemap_uv -= vec2(clipmap_offset) / float(SHADOW_TILEMAP_RES);
/* Clamp to avoid out of tilemap access. */