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