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}