EEVEE-Next: Avoid shadowmap padding on 0 radius punctual lights

Use the original Light radius to compute the shadowmap projection.
Avoid unnecessary padding in shadowmaps, increasing the perceived
shadow resolution when the shadow softness is not 0.

Pull Request: https://projects.blender.org/blender/blender/pulls/118860
This commit is contained in:
Miguel Pozo
2024-03-05 18:59:44 +01:00
parent 615edb3f3c
commit fe93664cef
3 changed files with 21 additions and 5 deletions
@@ -97,12 +97,23 @@ void Light::sync(ShadowModule &shadows, const Object *ob, float threshold)
/* Reuse shape radius as near clip plane. */
/* This assumes `shape_parameters_set` has already set `radius_squared`. */
float radius = math::sqrt(this->radius_squared);
float shadow_radius = la->shadow_softness_factor * radius;
if (ELEM(la->type, LA_LOCAL, LA_SPOT)) {
/* `shape_parameters_set` can increase the radius of point and spot lights to ensure a
* minimum radius/energy ratio.
* But we don't want to take that into account for computing the shadow-map projection,
* since non-zero radius introduces padding (required for soft-shadows tracing), reducing
* the effective resolution of shadow-maps.
* So we use the original light radius instead. */
shadow_radius = la->shadow_softness_factor * la->radius;
}
this->punctual->sync(this->type,
this->object_mat,
la->spotsize,
radius,
this->influence_radius_max,
la->shadow_softness_factor);
la->shadow_softness_factor,
la->shadow_softness_factor * la->radius);
}
}
else {
@@ -224,7 +224,8 @@ void ShadowPunctual::sync(eLightType light_type,
float cone_aperture,
float light_shape_radius,
float max_distance,
float softness_factor)
float softness_factor,
float shadow_radius)
{
if (is_spot_light(light_type)) {
tilemaps_needed_ = (cone_aperture > DEG2RADF(90.0f)) ? 5 : 1;
@@ -247,6 +248,7 @@ void ShadowPunctual::sync(eLightType light_type,
position_ = float3(object_mat[3]);
softness_factor_ = softness_factor;
shadow_radius_ = shadow_radius;
}
void ShadowPunctual::release_excess_tilemaps()
@@ -341,8 +343,7 @@ void ShadowPunctual::end_sync(Light &light, float lod_bias)
ShadowTileMapPool &tilemap_pool = shadows_.tilemap_pool;
float side, near, far;
compute_projection_boundaries(
light_radius_, light_radius_ * softness_factor_, max_distance_, near, far, side);
compute_projection_boundaries(light_radius_, shadow_radius_, max_distance_, near, far, side);
/* Shift shadow map origin for area light to avoid clipping nearby geometry. */
float shift = is_area_light(light.type) ? near : 0.0f;
@@ -395,6 +395,9 @@ class ShadowPunctual : public NonCopyable, NonMovable {
int tilemaps_needed_;
/** Scaling factor to the light shape for shadow ray casting. */
float softness_factor_;
/** radius * softness_factor (Bypasses LightModule radius modifications to avoid unnecesary
* padding in the shadow projection). */
float shadow_radius_;
public:
ShadowPunctual(ShadowModule &module) : shadows_(module){};
@@ -414,7 +417,8 @@ class ShadowPunctual : public NonCopyable, NonMovable {
float cone_aperture,
float light_shape_radius,
float max_distance,
float softness_factor);
float softness_factor,
float shadow_radius);
/**
* Release the tile-maps that will not be used in the current frame.