bevy/crates/bevy_pbr/src/light/directional_light.rs
Patrick Walton 40df1ea4b6
Remove the type parameter from check_visibility, and only invoke it once. (#16812)
Currently, `check_visibility` is parameterized over a query filter that
specifies the type of potentially-visible object. This has the
unfortunate side effect that we need a separate system,
`mark_view_visibility_as_changed_if_necessary`, to trigger view
visibility change detection. That system is quite slow because it must
iterate sequentially over all entities in the scene.

This PR moves the query filter from `check_visibility` to a new
component, `VisibilityClass`. `VisibilityClass` stores a list of type
IDs, each corresponding to one of the query filters we used to use.
Because `check_visibility` is no longer specialized to the query filter
at the type level, Bevy now only needs to invoke it once, leading to
better performance as `check_visibility` can do change detection on the
fly rather than delegating it to a separate system.

This commit also has ergonomic improvements, as there's no need for
applications that want to add their own custom renderable components to
add specializations of the `check_visibility` system to the schedule.
Instead, they only need to ensure that the `ViewVisibility` component is
properly kept up to date. The recommended way to do this, and the way
that's demonstrated in the `custom_phase_item` and
`specialized_mesh_pipeline` examples, is to make `ViewVisibility` a
required component and to add the type ID to it in a component add hook.
This patch does this for `Mesh3d`, `Mesh2d`, `Sprite`, `Light`, and
`Node`, which means that most app code doesn't need to change at all.

Note that, although this patch has a large impact on the performance of
visibility determination, it doesn't actually improve the end-to-end
frame time of `many_cubes`. That's because the render world was already
effectively hiding the latency from
`mark_view_visibility_as_changed_if_necessary`. This patch is, however,
necessary for *further* improvements to `many_cubes` performance.

`many_cubes` trace before:
![Screenshot 2024-12-13
015318](https://github.com/user-attachments/assets/d0b1881b-fb75-4a39-b05d-1a16eabfa2c5)

`many_cubes` trace after:
![Screenshot 2024-12-13
145735](https://github.com/user-attachments/assets/0a364289-e942-41bb-9cc2-b05d07e3722d)

## Migration Guide

* `check_visibility` no longer takes a `QueryFilter`, and there's no
need to add it manually to your app schedule anymore for custom
rendering items. Instead, entities with custom renderable components
should add the appropriate type IDs to `VisibilityClass`. See
`custom_phase_item` for an example.
2024-12-17 04:43:45 +00:00

151 lines
6.4 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use bevy_render::view::{self, Visibility};
use super::*;
/// A Directional light.
///
/// Directional lights don't exist in reality but they are a good
/// approximation for light sources VERY far away, like the sun or
/// the moon.
///
/// The light shines along the forward direction of the entity's transform. With a default transform
/// this would be along the negative-Z axis.
///
/// Valid values for `illuminance` are:
///
/// | Illuminance (lux) | Surfaces illuminated by |
/// |-------------------|------------------------------------------------|
/// | 0.0001 | Moonless, overcast night sky (starlight) |
/// | 0.002 | Moonless clear night sky with airglow |
/// | 0.050.3 | Full moon on a clear night |
/// | 3.4 | Dark limit of civil twilight under a clear sky |
/// | 2050 | Public areas with dark surroundings |
/// | 50 | Family living room lights |
/// | 80 | Office building hallway/toilet lighting |
/// | 100 | Very dark overcast day |
/// | 150 | Train station platforms |
/// | 320500 | Office lighting |
/// | 400 | Sunrise or sunset on a clear day. |
/// | 1000 | Overcast day; typical TV studio lighting |
/// | 10,00025,000 | Full daylight (not direct sun) |
/// | 32,000100,000 | Direct sunlight |
///
/// Source: [Wikipedia](https://en.wikipedia.org/wiki/Lux)
///
/// ## Shadows
///
/// To enable shadows, set the `shadows_enabled` property to `true`.
///
/// Shadows are produced via [cascaded shadow maps](https://developer.download.nvidia.com/SDK/10.5/opengl/src/cascaded_shadow_maps/doc/cascaded_shadow_maps.pdf).
///
/// To modify the cascade setup, such as the number of cascades or the maximum shadow distance,
/// change the [`CascadeShadowConfig`] component of the entity with the [`DirectionalLight`].
///
/// To control the resolution of the shadow maps, use the [`DirectionalLightShadowMap`] resource:
///
/// ```
/// # use bevy_app::prelude::*;
/// # use bevy_pbr::DirectionalLightShadowMap;
/// App::new()
/// .insert_resource(DirectionalLightShadowMap { size: 2048 });
/// ```
#[derive(Component, Debug, Clone, Reflect)]
#[reflect(Component, Default, Debug)]
#[require(
Cascades,
CascadesFrusta,
CascadeShadowConfig,
CascadesVisibleEntities,
Transform,
Visibility,
VisibilityClass
)]
#[component(on_add = view::add_visibility_class::<LightVisibilityClass>)]
pub struct DirectionalLight {
/// The color of the light.
///
/// By default, this is white.
pub color: Color,
/// Illuminance in lux (lumens per square meter), representing the amount of
/// light projected onto surfaces by this light source. Lux is used here
/// instead of lumens because a directional light illuminates all surfaces
/// more-or-less the same way (depending on the angle of incidence). Lumens
/// can only be specified for light sources which emit light from a specific
/// area.
pub illuminance: f32,
/// Whether this light casts shadows.
///
/// Note that shadows are rather expensive and become more so with every
/// light that casts them. In general, it's best to aggressively limit the
/// number of lights with shadows enabled to one or two at most.
pub shadows_enabled: bool,
/// Whether soft shadows are enabled, and if so, the size of the light.
///
/// Soft shadows, also known as *percentage-closer soft shadows* or PCSS,
/// cause shadows to become blurrier (i.e. their penumbra increases in
/// radius) as they extend away from objects. The blurriness of the shadow
/// depends on the size of the light; larger lights result in larger
/// penumbras and therefore blurrier shadows.
///
/// Currently, soft shadows are rather noisy if not using the temporal mode.
/// If you enable soft shadows, consider choosing
/// [`ShadowFilteringMethod::Temporal`] and enabling temporal antialiasing
/// (TAA) to smooth the noise out over time.
///
/// Note that soft shadows are significantly more expensive to render than
/// hard shadows.
#[cfg(feature = "experimental_pbr_pcss")]
pub soft_shadow_size: Option<f32>,
/// Whether this directional light contributes diffuse lighting to meshes
/// with lightmaps.
///
/// Set this to false if your lightmap baking tool bakes the direct diffuse
/// light from this directional light into the lightmaps in order to avoid
/// counting the radiance from this light twice. Note that the specular
/// portion of the light is always considered, because Bevy currently has no
/// means to bake specular light.
///
/// By default, this is set to true.
pub affects_lightmapped_mesh_diffuse: bool,
/// A value that adjusts the tradeoff between self-shadowing artifacts and
/// proximity of shadows to their casters.
///
/// This value frequently must be tuned to the specific scene; this is
/// normal and a well-known part of the shadow mapping workflow. If set too
/// low, unsightly shadow patterns appear on objects not in shadow as
/// objects incorrectly cast shadows on themselves, known as *shadow acne*.
/// If set too high, shadows detach from the objects casting them and seem
/// to "fly" off the objects, known as *Peter Panning*.
pub shadow_depth_bias: f32,
/// A bias applied along the direction of the fragment's surface normal. It
/// is scaled to the shadow map's texel size so that it is automatically
/// adjusted to the orthographic projection.
pub shadow_normal_bias: f32,
}
impl Default for DirectionalLight {
fn default() -> Self {
DirectionalLight {
color: Color::WHITE,
illuminance: light_consts::lux::AMBIENT_DAYLIGHT,
shadows_enabled: false,
shadow_depth_bias: Self::DEFAULT_SHADOW_DEPTH_BIAS,
shadow_normal_bias: Self::DEFAULT_SHADOW_NORMAL_BIAS,
affects_lightmapped_mesh_diffuse: true,
#[cfg(feature = "experimental_pbr_pcss")]
soft_shadow_size: None,
}
}
}
impl DirectionalLight {
pub const DEFAULT_SHADOW_DEPTH_BIAS: f32 = 0.02;
pub const DEFAULT_SHADOW_NORMAL_BIAS: f32 = 1.8;
}