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