bevy_pbr/light/
spot_light.rs

1use bevy_render::view::{self, Visibility};
2
3use super::*;
4
5/// A light that emits light in a given direction from a central point.
6///
7/// Behaves like a point light in a perfectly absorbent housing that
8/// shines light only in a given direction. The direction is taken from
9/// the transform, and can be specified with [`Transform::looking_at`](Transform::looking_at).
10#[derive(Component, Debug, Clone, Copy, Reflect)]
11#[reflect(Component, Default, Debug, Clone)]
12#[require(Frustum, VisibleMeshEntities, Transform, Visibility, VisibilityClass)]
13#[component(on_add = view::add_visibility_class::<LightVisibilityClass>)]
14pub struct SpotLight {
15    /// The color of the light.
16    ///
17    /// By default, this is white.
18    pub color: Color,
19
20    /// Luminous power in lumens, representing the amount of light emitted by this source in all directions.
21    pub intensity: f32,
22
23    /// Range in meters that this light illuminates.
24    ///
25    /// Note that this value affects resolution of the shadow maps; generally, the
26    /// higher you set it, the lower-resolution your shadow maps will be.
27    /// Consequently, you should set this value to be only the size that you need.
28    pub range: f32,
29
30    /// Simulates a light source coming from a spherical volume with the given
31    /// radius.
32    ///
33    /// This affects the size of specular highlights created by this light, as
34    /// well as the soft shadow penumbra size. Because of this, large values may
35    /// not produce the intended result -- for example, light radius does not
36    /// affect shadow softness or diffuse lighting.
37    pub radius: f32,
38
39    /// Whether this light casts shadows.
40    ///
41    /// Note that shadows are rather expensive and become more so with every
42    /// light that casts them. In general, it's best to aggressively limit the
43    /// number of lights with shadows enabled to one or two at most.
44    pub shadows_enabled: bool,
45
46    /// Whether soft shadows are enabled.
47    ///
48    /// Soft shadows, also known as *percentage-closer soft shadows* or PCSS,
49    /// cause shadows to become blurrier (i.e. their penumbra increases in
50    /// radius) as they extend away from objects. The blurriness of the shadow
51    /// depends on the [`SpotLight::radius`] of the light; larger lights result in larger
52    /// penumbras and therefore blurrier shadows.
53    ///
54    /// Currently, soft shadows are rather noisy if not using the temporal mode.
55    /// If you enable soft shadows, consider choosing
56    /// [`ShadowFilteringMethod::Temporal`] and enabling temporal antialiasing
57    /// (TAA) to smooth the noise out over time.
58    ///
59    /// Note that soft shadows are significantly more expensive to render than
60    /// hard shadows.
61    #[cfg(feature = "experimental_pbr_pcss")]
62    pub soft_shadows_enabled: bool,
63
64    /// Whether this spot light contributes diffuse lighting to meshes with
65    /// lightmaps.
66    ///
67    /// Set this to false if your lightmap baking tool bakes the direct diffuse
68    /// light from this directional light into the lightmaps in order to avoid
69    /// counting the radiance from this light twice. Note that the specular
70    /// portion of the light is always considered, because Bevy currently has no
71    /// means to bake specular light.
72    ///
73    /// By default, this is set to true.
74    pub affects_lightmapped_mesh_diffuse: bool,
75
76    /// A value that adjusts the tradeoff between self-shadowing artifacts and
77    /// proximity of shadows to their casters.
78    ///
79    /// This value frequently must be tuned to the specific scene; this is
80    /// normal and a well-known part of the shadow mapping workflow. If set too
81    /// low, unsightly shadow patterns appear on objects not in shadow as
82    /// objects incorrectly cast shadows on themselves, known as *shadow acne*.
83    /// If set too high, shadows detach from the objects casting them and seem
84    /// to "fly" off the objects, known as *Peter Panning*.
85    pub shadow_depth_bias: f32,
86
87    /// A bias applied along the direction of the fragment's surface normal. It is scaled to the
88    /// shadow map's texel size so that it can be small close to the camera and gets larger further
89    /// away.
90    pub shadow_normal_bias: f32,
91
92    /// The distance from the light to the near Z plane in the shadow map.
93    ///
94    /// Objects closer than this distance to the light won't cast shadows.
95    /// Setting this higher increases the shadow map's precision.
96    ///
97    /// This only has an effect if shadows are enabled.
98    pub shadow_map_near_z: f32,
99
100    /// Angle defining the distance from the spot light direction to the outer limit
101    /// of the light's cone of effect.
102    /// `outer_angle` should be < `PI / 2.0`.
103    /// `PI / 2.0` defines a hemispherical spot light, but shadows become very blocky as the angle
104    /// approaches this limit.
105    pub outer_angle: f32,
106
107    /// Angle defining the distance from the spot light direction to the inner limit
108    /// of the light's cone of effect.
109    /// Light is attenuated from `inner_angle` to `outer_angle` to give a smooth falloff.
110    /// `inner_angle` should be <= `outer_angle`
111    pub inner_angle: f32,
112}
113
114impl SpotLight {
115    pub const DEFAULT_SHADOW_DEPTH_BIAS: f32 = 0.02;
116    pub const DEFAULT_SHADOW_NORMAL_BIAS: f32 = 1.8;
117    pub const DEFAULT_SHADOW_MAP_NEAR_Z: f32 = 0.1;
118}
119
120impl Default for SpotLight {
121    fn default() -> Self {
122        // a quarter arc attenuating from the center
123        Self {
124            color: Color::WHITE,
125            // 1,000,000 lumens is a very large "cinema light" capable of registering brightly at Bevy's
126            // default "very overcast day" exposure level. For "indoor lighting" with a lower exposure,
127            // this would be way too bright.
128            intensity: 1_000_000.0,
129            range: 20.0,
130            radius: 0.0,
131            shadows_enabled: false,
132            affects_lightmapped_mesh_diffuse: true,
133            shadow_depth_bias: Self::DEFAULT_SHADOW_DEPTH_BIAS,
134            shadow_normal_bias: Self::DEFAULT_SHADOW_NORMAL_BIAS,
135            shadow_map_near_z: Self::DEFAULT_SHADOW_MAP_NEAR_Z,
136            inner_angle: 0.0,
137            outer_angle: core::f32::consts::FRAC_PI_4,
138            #[cfg(feature = "experimental_pbr_pcss")]
139            soft_shadows_enabled: false,
140        }
141    }
142}