diff --git a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh index 41bd003c443..f78928751d5 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh +++ b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh @@ -1479,8 +1479,8 @@ struct ShadowSceneData { int ray_count; /* Number of shadow samples to take for each shadow ray. */ int step_count; - /* Ratio between tile-map pixel world "radius" and film pixel world "radius". */ - float tilemap_projection_ratio; + /* Bounding radius for a film pixel at 1 unit from the camera. */ + float film_pixel_radius; float _pad0; }; diff --git a/source/blender/draw/engines/eevee_next/eevee_shadow.cc b/source/blender/draw/engines/eevee_next/eevee_shadow.cc index 37377580691..67c667145ae 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shadow.cc +++ b/source/blender/draw/engines/eevee_next/eevee_shadow.cc @@ -876,8 +876,6 @@ void ShadowModule::begin_sync() /* Directional shadows. */ float texel_size = ShadowDirectional::tile_size_get(0) / float(SHADOW_PAGE_RES); int directional_level = std::max(0, int(std::ceil(log2(surfel_coverage_area / texel_size)))); - /* Punctual shadows. */ - float projection_ratio = tilemap_pixel_radius() / (surfel_coverage_area / 2.0); PassMain::Sub &sub = pass.sub("Surfels"); sub.shader_set(inst_.shaders.static_shader_get(SHADOW_TILEMAP_TAG_USAGE_SURFELS)); @@ -886,7 +884,7 @@ void ShadowModule::begin_sync() sub.bind_ssbo("surfel_buf", &surfels_buf); sub.bind_ssbo("capture_info_buf", &capture_info_buf); sub.push_constant("directional_level", directional_level); - sub.push_constant("tilemap_proj_ratio", projection_ratio); + sub.bind_resources(inst_.uniform_data); sub.bind_resources(inst_.lights); sub.dispatch(&inst_.volume_probes.bake.dispatch_per_surfel_); @@ -901,7 +899,6 @@ void ShadowModule::begin_sync() sub.bind_ssbo("tilemaps_buf", &tilemap_pool.tilemaps_data); sub.bind_ssbo("tiles_buf", &tilemap_pool.tiles_data); sub.bind_texture("depth_tx", &src_depth_tx_); - sub.push_constant("tilemap_proj_ratio", &data_.tilemap_projection_ratio); sub.push_constant("input_depth_extent", &input_depth_extent_); sub.bind_resources(inst_.lights); sub.bind_resources(inst_.uniform_data); @@ -920,8 +917,6 @@ void ShadowModule::begin_sync() sub.bind_ssbo("tilemaps_buf", &tilemap_pool.tilemaps_data); sub.bind_ssbo("tiles_buf", &tilemap_pool.tiles_data); sub.bind_ssbo("bounds_buf", &manager.bounds_buf.current()); - sub.push_constant("tilemap_proj_ratio", &data_.tilemap_projection_ratio); - sub.push_constant("pixel_world_radius", &pixel_world_radius_); sub.push_constant("fb_resolution", &usage_tag_fb_resolution_); sub.push_constant("fb_lod", &usage_tag_fb_lod_); sub.bind_resources(inst_.uniform_data); @@ -1153,7 +1148,6 @@ void ShadowModule::end_sync() sub.shader_set(inst_.shaders.static_shader_get(SHADOW_TILEMAP_TAG_USAGE_VOLUME)); sub.bind_ssbo("tilemaps_buf", &tilemap_pool.tilemaps_data); sub.bind_ssbo("tiles_buf", &tilemap_pool.tiles_data); - sub.push_constant("tilemap_proj_ratio", &data_.tilemap_projection_ratio); sub.bind_resources(inst_.uniform_data); sub.bind_resources(inst_.hiz_buffer.front); sub.bind_resources(inst_.sampling); @@ -1334,17 +1328,6 @@ float ShadowModule::screen_pixel_radius(const View &view, const int2 &extent) return math::distance(p0, p1) / min_dim; } -/* Compute approximate screen pixel world space radius at 1 unit away of the light. */ -float ShadowModule::tilemap_pixel_radius() -{ - /* This is a really rough approximation. Ideally, the cube-map distortion should be taken into - * account per pixel. But this would make this pre-computation impossible. - * So for now compute for the center of the cube-map. */ - const float cubeface_diagonal = M_SQRT2 * 2.0f; - const float pixel_count = SHADOW_TILEMAP_RES * shadow_page_size_; - return cubeface_diagonal / pixel_count; -} - bool ShadowModule::shadow_update_finished() { if (!inst_.is_image_render()) { @@ -1414,8 +1397,7 @@ void ShadowModule::set_view(View &view, int2 extent) 1); max_view_per_tilemap_ = max_view_per_tilemap(); - pixel_world_radius_ = screen_pixel_radius(view, extent); - data_.tilemap_projection_ratio = tilemap_pixel_radius() / pixel_world_radius_; + data_.film_pixel_radius = screen_pixel_radius(view, extent); inst_.uniform_data.push_update(); usage_tag_fb_resolution_ = math::divide_ceil(extent, int2(std::exp2(usage_tag_fb_lod_))); diff --git a/source/blender/draw/engines/eevee_next/eevee_shadow.hh b/source/blender/draw/engines/eevee_next/eevee_shadow.hh index 4a7fd165b2c..b8d2bfd0986 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shadow.hh +++ b/source/blender/draw/engines/eevee_next/eevee_shadow.hh @@ -259,7 +259,6 @@ class ShadowModule { ShadowRenderViewBuf render_view_buf_ = {"render_view_buf"}; int3 dispatch_depth_scan_size_; - float pixel_world_radius_; int2 usage_tag_fb_resolution_; int usage_tag_fb_lod_ = 5; int max_view_per_tilemap_ = 1; diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_frag.glsl index cfbcca3fb9e..09a30ba2369 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_frag.glsl @@ -41,7 +41,7 @@ float ray_aabb(vec3 ray_origin, vec3 ray_direction, vec3 aabb_min, vec3 aabb_max float pixel_size_at(float linear_depth) { - float pixel_size = pixel_world_radius; + float pixel_size = uniform_buf.shadow.film_pixel_radius; bool is_persp = (ProjectionMatrix[3][3] == 0.0); if (is_persp) { pixel_size *= max(0.01, linear_depth); @@ -119,6 +119,6 @@ void main() vec3 vP = drw_point_world_to_view(P); shadow_tag_usage( - vP, P, ws_view_direction, step_radius, t, gl_FragCoord.xy * exp2(float(fb_lod)), 0); + vP, P, ws_view_direction, step_radius, gl_FragCoord.xy * exp2(float(fb_lod)), 0); } } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_lib.glsl index 64d7a2c343d..dc5072ede29 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_lib.glsl @@ -80,8 +80,7 @@ void shadow_tag_usage_tilemap_directional(uint l_idx, vec3 P, vec3 V, float radi } } -void shadow_tag_usage_tilemap_punctual( - uint l_idx, vec3 P, float dist_to_cam, float radius, int lod_bias) +void shadow_tag_usage_tilemap_punctual(uint l_idx, vec3 P, float radius, int lod_bias) { LightData light = light_buf[l_idx]; @@ -111,18 +110,17 @@ void shadow_tag_usage_tilemap_punctual( /* TODO(fclem): 3D shift for jittered soft shadows. */ lP += vec3(0.0, 0.0, -light_local_data_get(light).shadow_projection_shift); - float footprint_ratio = shadow_punctual_footprint_ratio( - light, lP, drw_view_is_perspective(), dist_to_cam, tilemap_proj_ratio); + int lod = shadow_punctual_level(light, + lP, + drw_view_is_perspective(), + drw_view_z_distance(P), + uniform_buf.shadow.film_pixel_radius); + lod = clamp(lod + lod_bias, 0, SHADOW_TILEMAP_LOD); if (radius == 0) { int face_id = shadow_punctual_face_index_get(lP); lP = shadow_punctual_local_position_to_face_local(face_id, lP); ShadowCoordinates coord = shadow_punctual_coordinates(light, lP, face_id); - - int lod = int(floor(-log2(footprint_ratio) + tilemaps_buf[coord.tilemap_index].lod_bias)); - lod += lod_bias; - lod = clamp(lod, 0, SHADOW_TILEMAP_LOD); - shadow_tag_usage_tile(light, coord.tile_coord, lod, coord.tilemap_index); } else { @@ -142,10 +140,6 @@ void shadow_tag_usage_tilemap_punctual( } int tilemap_index = light.tilemap_index + face_id; - int lod = int(ceil(-log2(footprint_ratio) + tilemaps_buf[tilemap_index].lod_bias)); - lod += lod_bias; - lod = clamp(lod, 0, SHADOW_TILEMAP_LOD); - vec3 _lP = shadow_punctual_local_position_to_face_local(face_id, lP); vec3 offset = vec3(radius, radius, 0); @@ -166,8 +160,7 @@ void shadow_tag_usage_tilemap_punctual( * Used for downsampled/ray-marched tagging, so all the shadow-map texels covered get correctly * tagged. */ -void shadow_tag_usage( - vec3 vP, vec3 P, vec3 V, float radius, float dist_to_cam, vec2 pixel, int lod_bias) +void shadow_tag_usage(vec3 vP, vec3 P, vec3 V, float radius, vec2 pixel, int lod_bias) { LIGHT_FOREACH_BEGIN_DIRECTIONAL (light_cull_buf, l_idx) { shadow_tag_usage_tilemap_directional(l_idx, P, V, radius, lod_bias); @@ -175,16 +168,14 @@ void shadow_tag_usage( LIGHT_FOREACH_END LIGHT_FOREACH_BEGIN_LOCAL (light_cull_buf, light_zbin_buf, light_tile_buf, pixel, vP.z, l_idx) { - shadow_tag_usage_tilemap_punctual(l_idx, P, dist_to_cam, radius, lod_bias); + shadow_tag_usage_tilemap_punctual(l_idx, P, radius, lod_bias); } LIGHT_FOREACH_END } void shadow_tag_usage(vec3 vP, vec3 P, vec2 pixel) { - float dist_to_cam = length(vP); - - shadow_tag_usage(vP, P, vec3(0), 0, dist_to_cam, pixel, 0); + shadow_tag_usage(vP, P, vec3(0), 0, pixel, 0); } void shadow_tag_usage_surfel(Surfel surfel, int directional_lvl) @@ -198,9 +189,7 @@ void shadow_tag_usage_surfel(Surfel surfel, int directional_lvl) LIGHT_FOREACH_BEGIN_LOCAL_NO_CULL(light_cull_buf, l_idx) { - /* Set distance to camera to 1 to avoid changing footprint_ratio. */ - float dist_to_cam = 1.0; - shadow_tag_usage_tilemap_punctual(l_idx, P, dist_to_cam, 0, 0); + shadow_tag_usage_tilemap_punctual(l_idx, P, 0, 0); } LIGHT_FOREACH_END } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_vert.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_vert.glsl index c6d9fa8a16f..e844a4835b1 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_vert.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_vert.glsl @@ -20,7 +20,7 @@ void inflate_bounds(vec3 ls_center, inout vec3 P, inout vec3 lP) { vec3 vP = drw_point_world_to_view(P); - float inflate_scale = pixel_world_radius * exp2(float(fb_lod)); + float inflate_scale = uniform_buf.shadow.film_pixel_radius * exp2(float(fb_lod)); if (drw_view_is_perspective()) { inflate_scale *= -vP.z; } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_volume_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_volume_comp.glsl index 90397756a7e..a9aae756b3a 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_volume_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_volume_comp.glsl @@ -45,5 +45,5 @@ void main() uniform_buf.volumes.main_view_extent; int bias = uniform_buf.volumes.tile_size_lod; - shadow_tag_usage(vP, P, drw_world_incident_vector(P), 0.01, length(vP), pixel, bias); + shadow_tag_usage(vP, P, drw_world_incident_vector(P), 0.01, pixel, bias); } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tilemap_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tilemap_lib.glsl index f863a932117..123a236ee14 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tilemap_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tilemap_lib.glsl @@ -108,7 +108,6 @@ ShadowSamplingTile shadow_tile_load(usampler2D tilemaps_tx, ivec2 tile_co, int t * \a lP shading point position in light space, relative to the to camera position snapped to * the smallest clip-map level (`shadow_world_to_local(light, P) - light_position_get(light)`). */ - float shadow_directional_level_fractional(LightData light, vec3 lP) { float lod; @@ -138,30 +137,66 @@ int shadow_directional_level(LightData light, vec3 lP) return int(ceil(shadow_directional_level_fractional(light, lP))); } -/* How much a tilemap pixel covers a final image pixel. */ -float shadow_punctual_footprint_ratio(LightData light, - vec3 lP, - bool is_perspective, - float dist_to_cam, - float tilemap_projection_ratio) +float shadow_punctual_frustum_padding_get(LightData light) +{ + return light_local_data_get(light).clip_side / orderedIntBitsToFloat(light.clip_near); +} + +/** + * Returns the ratio of radius between shadow map pixels and screen pixels. + * `distance_to_camera` is Z distance to the camera origin. + */ +float shadow_punctual_pixel_ratio(LightData light, + vec3 lP, + bool is_perspective, + float distance_to_camera, + float film_pixel_radius) { /* We project a shadow map pixel (as a sphere for simplicity) to the receiver plane. * We then reproject this sphere onto the camera screen and compare it to the film pixel size. * This gives a good approximation of what LOD to select to get a somewhat uniform shadow map * resolution in screen space. */ - - float dist_to_light = length(lP); - /* Apply resolution ratio. */ - float footprint_ratio = dist_to_light * tilemap_projection_ratio; - /* Project the radius to the screen. 1 unit away from the camera the same way - * pixel_world_radius_inv was computed. Not needed in orthographic mode. */ - if (is_perspective) { - footprint_ratio /= dist_to_cam; - } + float film_footprint = (is_perspective) ? film_pixel_radius * distance_to_camera : + film_pixel_radius; + /* Compute approximate screen pixel world space radius at 1 unit away of the light. */ + float shadow_pixel_footprint = 2.0 * M_SQRT2 / SHADOW_MAP_MAX_RES; /* Take the frustum padding into account. */ - footprint_ratio *= light_local_data_get(light).clip_side / - orderedIntBitsToFloat(light.clip_near); - return footprint_ratio; + shadow_pixel_footprint *= shadow_punctual_frustum_padding_get(light); + + float distance_to_light = reduce_max(abs(lP)); + float shadow_footprint = shadow_pixel_footprint * distance_to_light; + /* TODO(fclem): Ideally, this should be modulated by N.L. */ + float ratio = shadow_footprint / film_footprint; + return ratio; +} + +/** + * Returns the LOD for a given shadow space position. + * `distance_to_camera` is Z distance to the camera origin. + */ +float shadow_punctual_level_fractional(LightData light, + vec3 lP, + bool is_perspective, + float distance_to_camera, + float film_pixel_radius) +{ + float ratio = shadow_punctual_pixel_ratio( + light, lP, is_perspective, distance_to_camera, film_pixel_radius); + /* Note: Bias by one to counteract the ceil in the `int` variant. This is done because this + * function should return an upper bound. */ + float lod = -log2(ratio) - 1.0 + light.lod_bias; + lod = clamp(lod, 0.0, float(SHADOW_TILEMAP_LOD)); + return lod; +} + +int shadow_punctual_level(LightData light, + vec3 lP, + bool is_perspective, + float distance_to_camera, + float film_pixel_radius) +{ + return int(ceil(shadow_punctual_level_fractional( + light, lP, is_perspective, distance_to_camera, film_pixel_radius))); } struct ShadowCoordinates { diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tracing_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tracing_lib.glsl index 475815954c7..26a30a96ef1 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tracing_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tracing_lib.glsl @@ -454,18 +454,18 @@ float shadow_texel_radius_at_position(LightData light, const bool is_directional } } else { - /* FIXME: The returned value seems quite broken as it increases drastically near the view - * position. */ - scale = shadow_punctual_footprint_ratio(light, - lP, - drw_view_is_perspective(), - distance(P, drw_view_position()), - uniform_buf.shadow.tilemap_projection_ratio); + /* Simplification of `coverage_get(shadow_punctual_level_fractional)`. */ + scale = shadow_punctual_pixel_ratio(light, + lP, + drw_view_is_perspective(), + drw_view_z_distance(P), + uniform_buf.shadow.film_pixel_radius); /* This gives the size of pixels at Z = 1. */ - scale *= exp2(light.lod_bias); + scale = 1.0 / scale; + scale *= exp2(-1.0 + light.lod_bias); scale = clamp(scale, float(1 << 0), float(1 << SHADOW_TILEMAP_LOD)); /* Now scale by distance to the light. */ - scale *= length(lP); + scale *= reduce_max(abs(lP)); } /* Footprint of a tilemap at unit distance from the camera. */ const float texel_footprint = 2.0 * M_SQRT2 / SHADOW_MAP_MAX_RES; diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_shadow_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_shadow_info.hh index 217e9a43f76..e772469d551 100644 --- a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_shadow_info.hh +++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_shadow_info.hh @@ -64,7 +64,6 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tag_usage_opaque) .storage_buf(5, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]") .storage_buf(6, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]") .push_constant(Type::IVEC2, "input_depth_extent") - .push_constant(Type::FLOAT, "tilemap_proj_ratio") .additional_info( "eevee_shared", "draw_view", "draw_view_culling", "eevee_hiz_data", "eevee_light_data") .compute_source("eevee_shadow_tag_usage_comp.glsl"); @@ -76,11 +75,11 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tag_usage_surfels) /* ShadowTileDataPacked is uint. But MSL translation need the real type. */ .storage_buf(7, Qualifier::READ_WRITE, "uint", "tiles_buf[]") .push_constant(Type::INT, "directional_level") - .push_constant(Type::FLOAT, "tilemap_proj_ratio") .additional_info("eevee_shared", "draw_view", "draw_view_culling", "eevee_light_data", + "eevee_global_ubo", "eevee_surfel_common") .compute_source("eevee_shadow_tag_usage_surfels_comp.glsl"); @@ -97,8 +96,6 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tag_usage_transparent) .storage_buf(4, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .storage_buf(5, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]") .storage_buf(6, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]") - .push_constant(Type::FLOAT, "tilemap_proj_ratio") - .push_constant(Type::FLOAT, "pixel_world_radius") .push_constant(Type::IVEC2, "fb_resolution") .push_constant(Type::INT, "fb_lod") .vertex_out(eevee_shadow_tag_transparent_iface) @@ -118,7 +115,6 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tag_usage_volume) .local_group_size(VOLUME_GROUP_SIZE, VOLUME_GROUP_SIZE, VOLUME_GROUP_SIZE) .storage_buf(4, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]") .storage_buf(5, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]") - .push_constant(Type::FLOAT, "tilemap_proj_ratio") .additional_info("eevee_volume_properties_data", "eevee_shared", "draw_view", diff --git a/source/blender/draw/intern/shaders/draw_view_lib.glsl b/source/blender/draw/intern/shaders/draw_view_lib.glsl index 83e719414bb..47ba405dc70 100644 --- a/source/blender/draw/intern/shaders/draw_view_lib.glsl +++ b/source/blender/draw/intern/shaders/draw_view_lib.glsl @@ -24,6 +24,12 @@ vec3 drw_view_position() return drw_view.viewinv[3].xyz; } +/* Positive Z distance from the view origin. Faster than using `drw_point_world_to_view`. */ +float drw_view_z_distance(vec3 P) +{ + return dot(P - drw_view_position(), -drw_view_forward()); +} + /* Returns the projection matrix far clip distance. */ float drw_view_far() {