Skip to main content

bevy_post_process/effect_stack/
chromatic_aberration.rs

1use bevy_asset::Handle;
2use bevy_camera::Camera;
3use bevy_ecs::{
4    component::Component,
5    query::{QueryItem, With},
6    reflect::ReflectComponent,
7    resource::Resource,
8    system::lifetimeless::Read,
9};
10use bevy_image::Image;
11use bevy_reflect::{std_traits::ReflectDefault, Reflect};
12use bevy_render::{
13    extract_component::ExtractComponent, render_resource::ShaderType,
14    sync_component::SyncComponent, RenderApp,
15};
16
17/// The raw RGBA data for the default chromatic aberration gradient.
18///
19/// This consists of one red pixel, one green pixel, and one blue pixel, in that
20/// order.
21pub(super) static DEFAULT_CHROMATIC_ABERRATION_LUT_DATA: [u8; 12] =
22    [255, 0, 0, 255, 0, 255, 0, 255, 0, 0, 255, 255];
23
24#[derive(Resource)]
25pub(crate) struct DefaultChromaticAberrationLut(pub(crate) Handle<Image>);
26
27/// Adds colored fringes to the edges of objects in the scene.
28///
29/// [Chromatic aberration] simulates the effect when lenses fail to focus all
30/// colors of light toward a single point. It causes rainbow-colored streaks to
31/// appear, which are especially apparent on the edges of objects. Chromatic
32/// aberration is commonly used for collision effects, especially in horror
33/// games.
34///
35/// Bevy's implementation is based on that of *Inside* ([Gjøl & Svendsen 2016]).
36/// It's based on a customizable lookup texture, which allows for changing the
37/// color pattern. By default, the color pattern is simply a 3×1 pixel texture
38/// consisting of red, green, and blue, in that order, but you can change it to
39/// any image in order to achieve different effects.
40///
41/// [Chromatic aberration]: https://en.wikipedia.org/wiki/Chromatic_aberration
42///
43/// [Gjøl & Svendsen 2016]: https://github.com/playdeadgames/publications/blob/master/INSIDE/rendering_inside_gdc2016.pdf
44#[derive(Reflect, Component, Clone)]
45#[reflect(Component, Default, Clone)]
46pub struct ChromaticAberration {
47    /// The lookup texture that determines the color gradient.
48    ///
49    /// By default (if None), this is a 3×1 texel texture consisting of one red
50    /// pixel, one green pixel, and one blue texel, in that order. This
51    /// recreates the most typical chromatic aberration pattern. However, you
52    /// can change it to achieve different artistic effects.
53    ///
54    /// The texture is always sampled in its vertical center, so it should
55    /// ordinarily have a height of 1 texel.
56    pub color_lut: Option<Handle<Image>>,
57
58    /// The size of the streaks around the edges of objects, as a fraction of
59    /// the window size.
60    ///
61    /// The default value is 0.02.
62    pub intensity: f32,
63
64    /// A cap on the number of texture samples that will be performed.
65    ///
66    /// Higher values result in smoother-looking streaks but are slower.
67    ///
68    /// The default value is 8.
69    pub max_samples: u32,
70}
71
72impl Default for ChromaticAberration {
73    fn default() -> Self {
74        Self {
75            color_lut: None,
76            intensity: 0.02,
77            max_samples: 8,
78        }
79    }
80}
81
82impl SyncComponent<RenderApp> for ChromaticAberration {
83    type Target = Self;
84}
85
86impl ExtractComponent<RenderApp> for ChromaticAberration {
87    type QueryData = Read<ChromaticAberration>;
88    type QueryFilter = With<Camera>;
89    type Out = Self;
90
91    fn extract_component(
92        chromatic_aberration: QueryItem<'_, '_, Self::QueryData>,
93    ) -> Option<Self::Out> {
94        // Skip the postprocessing phase entirely if the intensity is negligible.
95        if chromatic_aberration.intensity > 1e-4 {
96            Some(chromatic_aberration.clone())
97        } else {
98            None
99        }
100    }
101}
102
103/// The on-GPU version of the [`ChromaticAberration`] settings.
104///
105/// See the documentation for [`ChromaticAberration`] for more information on
106/// each of these fields.
107#[derive(ShaderType, Default)]
108pub struct ChromaticAberrationUniform {
109    pub(super) intensity: f32,
110    pub(super) max_samples: u32,
111    pub(super) unused_1: u32,
112    pub(super) unused_2: u32,
113}