From 4176a0f375cb9eda572ed26cf282560275ba3f84 Mon Sep 17 00:00:00 2001 From: Dylan Sechet Date: Wed, 24 Jun 2026 00:20:31 +0200 Subject: [PATCH 1/2] fix: clamp SpotLight.outer_angle to pi/2 - epsilon at extraction time --- crates/bevy_pbr/src/render/light.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index 0188614a17623..a53a136147f4b 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -27,6 +27,7 @@ use bevy_light::{ Cascades, DirectionalLight, DirectionalLightShadowMap, GlobalAmbientLight, PointLight, PointLightShadowMap, RectLight, ShadowFilteringMethod, SpotLight, VolumetricLight, }; +use bevy_log::warn_once; use bevy_material::{ key::{ErasedMaterialPipelineKey, ErasedMeshPipelineKey}, MaterialProperties, @@ -638,8 +639,22 @@ pub fn extract_lights( )); } - let texel_size = - 2.0 * ops::tan(spot_light.outer_angle) / directional_light_shadow_map.size as f32; + // `outer_angle` must be <π/2. + let (inner_angle, outer_angle) = { + let mut outer_angle = spot_light.outer_angle; + if outer_angle >= core::f32::consts::FRAC_PI_2 { + warn_once!( + "A `SpotLight` has `outer_angle` {} >= π/2 (~1.57079), clamping it to just below π/2. \ + Spot lights require `outer_angle < π/2`", + outer_angle + ); + outer_angle = core::f32::consts::FRAC_PI_2 - 1e-4; + } + // Keep inner_angle <= outer_angle after clamping. + (spot_light.inner_angle.min(outer_angle), outer_angle) + }; + + let texel_size = 2.0 * ops::tan(outer_angle) / directional_light_shadow_map.size as f32; let mut entity_commands = commands.entity(render_entity); let extracted_spot_light = ExtractedPointLight { @@ -662,7 +677,7 @@ pub fn extract_lights( * texel_size * core::f32::consts::SQRT_2, shadow_map_near_z: spot_light.shadow_map_near_z, - spot_light_angles: Some((spot_light.inner_angle, spot_light.outer_angle)), + spot_light_angles: Some((inner_angle, outer_angle)), volumetric: volumetric_light.is_some(), affects_lightmapped_mesh_diffuse: spot_light.affects_lightmapped_mesh_diffuse, #[cfg(feature = "experimental_pbr_pcss")] From 5af1b96ef4f014994e15a616cfbb46d21ea2d0d5 Mon Sep 17 00:00:00 2001 From: Dylan Sechet Date: Wed, 24 Jun 2026 00:21:18 +0200 Subject: [PATCH 2/2] doc: update SpotLight doc to explicitely forbid outer_angle=pi/2 --- crates/bevy_light/src/spot_light.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/bevy_light/src/spot_light.rs b/crates/bevy_light/src/spot_light.rs index f770e696ca788..13dbda9aa83b3 100644 --- a/crates/bevy_light/src/spot_light.rs +++ b/crates/bevy_light/src/spot_light.rs @@ -124,9 +124,7 @@ pub struct SpotLight { /// Angle defining the distance from the spot light direction to the outer limit /// of the light's cone of effect. - /// `outer_angle` should be < `PI / 2.0`. - /// `PI / 2.0` defines a hemispherical spot light, but shadows become very blocky as the angle - /// approaches this limit. + /// `outer_angle` must be < `PI / 2.0`. pub outer_angle: f32, /// Angle defining the distance from the spot light direction to the inner limit