Skip to main content

bevy_post_process/effect_stack/
lens_distortion.rs

1use bevy_ecs::{
2    component::Component,
3    query::{QueryItem, With},
4    system::lifetimeless::Read,
5};
6use bevy_math::{ops::abs, Vec2};
7use bevy_reflect::Reflect;
8use bevy_render::{
9    extract_component::ExtractComponent, render_resource::ShaderType,
10    sync_component::SyncComponent, RenderApp,
11};
12
13/// Simulates the warping of the image caused by real-world camera lenses.
14///
15/// [Lens distortion] simulates the imperfections of optical systems, where
16/// straight lines in the real world appear curved in the image. This effect
17/// is commonly used to create a sense of unease or disorientation, to mimic
18/// specific camera equipment, or to enhance the scale and immersion of scenes.
19///
20/// Bevy's implementation is based on a simplified special case of the
21/// Brown-Conrady model, where p₁ = p₂ = 0 and control is retained only
22/// for k1 and k2.
23#[derive(Reflect, Component, Clone)]
24pub struct LensDistortion {
25    /// The overall strength of the distortion effect.
26    ///
27    /// Positive values typically produce **barrel distortion** (bulging outwards),
28    /// while negative values produce **pincushion distortion** (pinching inwards).
29    /// This corresponds roughly to the radial distortion coefficient `k1`
30    /// in the simplified model.
31    ///
32    /// The default value is 0.5.
33    pub intensity: f32,
34    /// A global scale factor applied to the final distorted image.
35    ///
36    /// Strong distortion pushes pixels away from the center or pulls them in,
37    /// resulting in visible **stretching artifacts** at the screen edges.
38    /// Increasing this value zooms in to **crop out** these extreme edge artifacts,
39    /// ensuring the screen remains fully covered at the cost of a tighter field of view.
40    ///
41    /// The default value is 1.0(No zoom).
42    pub scale: f32,
43    /// A multiplier that determines how the distortion scales along the X and Y axes.
44    ///
45    /// By default, this should be `Vec2::ONE` for uniform radial distortion.
46    /// Modifying these values allows for anamorphic-like effects where the distortion
47    /// is stronger on one axis than the other. When a component of multiplier is set to 0.0,
48    /// no distortion effect is applied.
49    ///
50    /// The default value is `Vec2::ONE`
51    pub multiplier: Vec2,
52    /// The center point of the distortion effect in UV space `[0.0, 1.0]`.
53    ///
54    /// Distortion radiates outward or inward from this point.
55    ///
56    /// The default value is `Vec2::splat(0.5)`
57    pub center: Vec2,
58    /// Controls the sharpness of the distortion curve near the screen edges.
59    ///
60    /// `edge_curvature` provides indirect control over the k2 parameter.
61    /// The reason for indirect control is that k1 and k2 are typically correlated.
62    /// If k2 did not vary with k1, it would easily cause visual jumping when intensity
63    /// transitions from positive to negative.
64    /// For a simple and natural look in most cases, we recommend setting `edge_curvature` to 0.0.
65    ///
66    /// The default value is 0.0.
67    pub edge_curvature: f32,
68}
69
70impl Default for LensDistortion {
71    fn default() -> Self {
72        Self {
73            intensity: 0.5,
74            scale: 1.0,
75            multiplier: Vec2::ONE,
76            center: Vec2::splat(0.5),
77            edge_curvature: 0.0,
78        }
79    }
80}
81
82impl SyncComponent<RenderApp> for LensDistortion {
83    type Target = Self;
84}
85
86impl ExtractComponent<RenderApp> for LensDistortion {
87    type QueryData = Read<LensDistortion>;
88    type QueryFilter = With<LensDistortion>;
89    type Out = Self;
90
91    fn extract_component(lens_distortion: QueryItem<'_, '_, Self::QueryData>) -> Option<Self::Out> {
92        // Skip the postprocessing phase entirely if the intensity is negligible.
93        if abs(lens_distortion.intensity) > 1e-4 {
94            Some(lens_distortion.clone())
95        } else {
96            None
97        }
98    }
99}
100
101/// The on-GPU version of the [`LensDistortion`] settings.
102///
103/// See the documentation for [`LensDistortion`] for more information on
104/// each of these fields.
105#[derive(ShaderType, Default)]
106pub struct LensDistortionUniform {
107    pub(super) intensity: f32,
108    pub(super) scale: f32,
109    pub(super) multiplier: Vec2,
110    pub(super) center: Vec2,
111    pub(super) edge_curvature: f32,
112    pub(super) unused: u32,
113}