Skip to main content

bevy_post_process/dof/
mod.rs

1//! Depth of field, a postprocessing effect that simulates camera focus.
2//!
3//! By default, Bevy renders all objects in full focus: regardless of depth, all
4//! objects are rendered perfectly sharp (up to output resolution). Real lenses,
5//! however, can only focus on objects at a specific distance. The distance
6//! between the nearest and furthest objects that are in focus is known as
7//! [depth of field], and this term is used more generally in computer graphics
8//! to refer to the effect that simulates focus of lenses.
9//!
10//! Attaching [`DepthOfField`] to a camera causes Bevy to simulate the
11//! focus of a camera lens. Generally, Bevy's implementation of depth of field
12//! is optimized for speed instead of physical accuracy. Nevertheless, the depth
13//! of field effect in Bevy is based on physical parameters.
14//!
15//! [Depth of field]: https://en.wikipedia.org/wiki/Depth_of_field
16
17use bevy_app::{App, Plugin};
18use bevy_asset::{embedded_asset, load_embedded_asset, AssetServer, Handle};
19use bevy_camera::{Camera3d, PhysicalCameraParameters, Projection};
20use bevy_derive::{Deref, DerefMut};
21use bevy_ecs::{
22    component::Component,
23    entity::Entity,
24    query::With,
25    reflect::ReflectComponent,
26    resource::Resource,
27    schedule::IntoScheduleConfigs as _,
28    system::{Commands, Query, Res, ResMut},
29};
30use bevy_math::ops;
31use bevy_reflect::{prelude::ReflectDefault, Reflect};
32use bevy_render::{
33    camera::ExtractedCamera,
34    extract_component::{ComponentUniforms, DynamicUniformIndex, UniformComponentPlugin},
35    render_resource::{
36        binding_types::{
37            sampler, texture_2d, texture_depth_2d, texture_depth_2d_multisampled, uniform_buffer,
38        },
39        BindGroup, BindGroupEntries, BindGroupLayoutDescriptor, BindGroupLayoutEntries,
40        CachedRenderPipelineId, ColorTargetState, ColorWrites, FilterMode, FragmentState, LoadOp,
41        Operations, PipelineCache, RenderPassColorAttachment, RenderPassDescriptor,
42        RenderPipelineDescriptor, Sampler, SamplerBindingType, SamplerDescriptor, ShaderStages,
43        ShaderType, SpecializedRenderPipeline, SpecializedRenderPipelines, StoreOp,
44        TextureDescriptor, TextureDimension, TextureFormat, TextureSampleType, TextureUsages,
45    },
46    renderer::{RenderContext, RenderDevice, ViewQuery},
47    sync_component::{SyncComponent, SyncComponentPlugin},
48    sync_world::RenderEntity,
49    texture::{CachedTexture, TextureCache},
50    view::{
51        prepare_view_targets, ExtractedView, Msaa, ViewDepthTexture, ViewTarget, ViewUniform,
52        ViewUniformOffset, ViewUniforms,
53    },
54    Extract, ExtractSchedule, GpuResourceAppExt, Render, RenderApp, RenderStartup, RenderSystems,
55};
56use bevy_shader::Shader;
57use bevy_utils::{default, once};
58use smallvec::SmallVec;
59use tracing::{info, warn};
60
61use crate::bloom::bloom;
62use bevy_core_pipeline::{
63    core_3d::DEPTH_PREPASS_TEXTURE_SUPPORTED, schedule::Core3d, tonemapping::tonemapping,
64    FullscreenShader,
65};
66
67/// A plugin that adds support for the depth of field effect to Bevy.
68#[derive(#[automatically_derived]
impl ::core::default::Default for DepthOfFieldPlugin {
    #[inline]
    fn default() -> DepthOfFieldPlugin { DepthOfFieldPlugin {} }
}Default)]
69pub struct DepthOfFieldPlugin;
70
71/// A component that enables a [depth of field] postprocessing effect when attached to a [`Camera3d`],
72/// simulating the focus of a camera lens.
73///
74/// [depth of field]: https://en.wikipedia.org/wiki/Depth_of_field
75#[derive(impl bevy_ecs::component::Component for DepthOfField where
    Self: ::core::marker::Send + ::core::marker::Sync + 'static {
    const STORAGE_TYPE: bevy_ecs::component::StorageType =
        bevy_ecs::component::StorageType::Table;
    type Mutability = bevy_ecs::component::Mutable;
    fn register_required_components(_requiree:
            bevy_ecs::component::ComponentId,
        required_components:
            &mut bevy_ecs::component::RequiredComponentsRegistrator) {}
    fn clone_behavior() -> bevy_ecs::component::ComponentCloneBehavior {
        use bevy_ecs::component::{
            DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone,
        };
        (&&&bevy_ecs::component::DefaultCloneBehaviorSpecialization::<Self>::default()).default_clone_behavior()
    }
    fn relationship_accessor()
        ->
            ::core::option::Option<bevy_ecs::relationship::ComponentRelationshipAccessor<Self>> {
        ::core::option::Option::None
    }
}Component, #[automatically_derived]
impl ::core::clone::Clone for DepthOfField {
    #[inline]
    fn clone(&self) -> DepthOfField {
        let _: ::core::clone::AssertParamIsClone<DepthOfFieldMode>;
        let _: ::core::clone::AssertParamIsClone<f32>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for DepthOfField { }Copy, const _: () =
    {
        impl bevy_reflect::GetTypeRegistration for DepthOfField where  {
            fn get_type_registration() -> bevy_reflect::TypeRegistration {
                let mut registration =
                    bevy_reflect::TypeRegistration::of::<Self>();
                registration.insert::<bevy_reflect::ReflectFromPtr>(bevy_reflect::FromType::<Self>::from_type());
                registration.insert::<bevy_reflect::ReflectFromReflect>(bevy_reflect::FromType::<Self>::from_type());
                registration.register_type_data::<ReflectComponent, Self>();
                registration.register_type_data::<ReflectDefault, Self>();
                registration
            }
            #[inline(never)]
            fn register_type_dependencies(registry:
                    &mut bevy_reflect::TypeRegistry) {
                <DepthOfFieldMode as
                        bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
                <f32 as
                        bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
            }
        }
        impl bevy_reflect::Typed for DepthOfField where  {
            #[inline]
            fn type_info() -> &'static bevy_reflect::TypeInfo {
                static CELL: bevy_reflect::utility::NonGenericTypeInfoCell =
                    bevy_reflect::utility::NonGenericTypeInfoCell::new();
                CELL.get_or_set(||
                        {
                            bevy_reflect::TypeInfo::Struct(bevy_reflect::structs::StructInfo::new::<Self>(&[bevy_reflect::NamedField::new::<DepthOfFieldMode>("mode"),
                                                bevy_reflect::NamedField::new::<f32>("focal_distance"),
                                                bevy_reflect::NamedField::new::<f32>("sensor_height"),
                                                bevy_reflect::NamedField::new::<f32>("aperture_f_stops"),
                                                bevy_reflect::NamedField::new::<f32>("max_circle_of_confusion_diameter"),
                                                bevy_reflect::NamedField::new::<f32>("max_depth")]))
                        })
            }
        }
        #[allow(deprecated, reason =
        "derives on a deprecated type shouldn't be considered a usage")]
        impl bevy_reflect::TypePath for DepthOfField where  {
            fn type_path() -> &'static str {
                "bevy_post_process::dof::DepthOfField"
            }
            fn short_type_path() -> &'static str { "DepthOfField" }
            fn type_ident() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("DepthOfField")
            }
            fn crate_name() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_post_process::dof".split(':').next().unwrap())
            }
            fn module_path() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_post_process::dof")
            }
        }
        impl bevy_reflect::Reflect for DepthOfField where  {
            #[inline]
            fn into_any(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn ::core::any::Any> {
                self
            }
            #[inline]
            fn as_any(&self) -> &dyn ::core::any::Any { self }
            #[inline]
            fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any { self }
            #[inline]
            fn into_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect> {
                self
            }
            #[inline]
            fn as_reflect(&self) -> &dyn bevy_reflect::Reflect { self }
            #[inline]
            fn as_reflect_mut(&mut self) -> &mut dyn bevy_reflect::Reflect {
                self
            }
            #[inline]
            fn set(&mut self,
                value:
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>)
                ->
                    ::core::result::Result<(),
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>> {
                *self = <dyn bevy_reflect::Reflect>::take(value)?;
                ::core::result::Result::Ok(())
            }
        }
        #[allow(non_upper_case_globals)]
        const _: () =
            {
                static __INVENTORY: ::inventory::Node =
                    ::inventory::Node {
                        value: &{
                                bevy_reflect::__macro_exports::auto_register::AutomaticReflectRegistrations(<DepthOfField
                                        as
                                        bevy_reflect::__macro_exports::auto_register::RegisterForReflection>::__register)
                            },
                        next: ::inventory::__private::UnsafeCell::new(::inventory::__private::Option::None),
                    };
                #[link_section = ".text.startup"]
                unsafe extern "C" fn __ctor() {
                    unsafe {
                        ::inventory::ErasedNode::submit(__INVENTORY.value,
                            &__INVENTORY)
                    }
                }
                #[used]
                #[link_section = ".init_array"]
                static __CTOR: unsafe extern "C" fn() = __ctor;
            };
        impl bevy_reflect::structs::Struct for DepthOfField where  {
            fn field(&self, name: &str)
                -> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
                match name {
                    "mode" => ::core::option::Option::Some(&self.mode),
                    "focal_distance" =>
                        ::core::option::Option::Some(&self.focal_distance),
                    "sensor_height" =>
                        ::core::option::Option::Some(&self.sensor_height),
                    "aperture_f_stops" =>
                        ::core::option::Option::Some(&self.aperture_f_stops),
                    "max_circle_of_confusion_diameter" =>
                        ::core::option::Option::Some(&self.max_circle_of_confusion_diameter),
                    "max_depth" =>
                        ::core::option::Option::Some(&self.max_depth),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_mut(&mut self, name: &str)
                ->
                    ::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
                match name {
                    "mode" => ::core::option::Option::Some(&mut self.mode),
                    "focal_distance" =>
                        ::core::option::Option::Some(&mut self.focal_distance),
                    "sensor_height" =>
                        ::core::option::Option::Some(&mut self.sensor_height),
                    "aperture_f_stops" =>
                        ::core::option::Option::Some(&mut self.aperture_f_stops),
                    "max_circle_of_confusion_diameter" =>
                        ::core::option::Option::Some(&mut self.max_circle_of_confusion_diameter),
                    "max_depth" =>
                        ::core::option::Option::Some(&mut self.max_depth),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_at(&self, index: usize)
                -> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
                match index {
                    0usize => ::core::option::Option::Some(&self.mode),
                    1usize =>
                        ::core::option::Option::Some(&self.focal_distance),
                    2usize => ::core::option::Option::Some(&self.sensor_height),
                    3usize =>
                        ::core::option::Option::Some(&self.aperture_f_stops),
                    4usize =>
                        ::core::option::Option::Some(&self.max_circle_of_confusion_diameter),
                    5usize => ::core::option::Option::Some(&self.max_depth),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_at_mut(&mut self, index: usize)
                ->
                    ::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
                match index {
                    0usize => ::core::option::Option::Some(&mut self.mode),
                    1usize =>
                        ::core::option::Option::Some(&mut self.focal_distance),
                    2usize =>
                        ::core::option::Option::Some(&mut self.sensor_height),
                    3usize =>
                        ::core::option::Option::Some(&mut self.aperture_f_stops),
                    4usize =>
                        ::core::option::Option::Some(&mut self.max_circle_of_confusion_diameter),
                    5usize => ::core::option::Option::Some(&mut self.max_depth),
                    _ => ::core::option::Option::None,
                }
            }
            fn name_at(&self, index: usize) -> ::core::option::Option<&str> {
                match index {
                    0usize => ::core::option::Option::Some("mode"),
                    1usize => ::core::option::Option::Some("focal_distance"),
                    2usize => ::core::option::Option::Some("sensor_height"),
                    3usize => ::core::option::Option::Some("aperture_f_stops"),
                    4usize =>
                        ::core::option::Option::Some("max_circle_of_confusion_diameter"),
                    5usize => ::core::option::Option::Some("max_depth"),
                    _ => ::core::option::Option::None,
                }
            }
            fn index_of_name(&self, name: &str)
                -> ::core::option::Option<usize> {
                match name {
                    "mode" => ::core::option::Option::Some(0usize),
                    "focal_distance" => ::core::option::Option::Some(1usize),
                    "sensor_height" => ::core::option::Option::Some(2usize),
                    "aperture_f_stops" => ::core::option::Option::Some(3usize),
                    "max_circle_of_confusion_diameter" =>
                        ::core::option::Option::Some(4usize),
                    "max_depth" => ::core::option::Option::Some(5usize),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_len(&self) -> usize { 6usize }
            fn iter_fields(&self) -> bevy_reflect::structs::FieldIter {
                bevy_reflect::structs::FieldIter::new(self)
            }
            fn to_dynamic_struct(&self)
                -> bevy_reflect::structs::DynamicStruct {
                let mut dynamic: bevy_reflect::structs::DynamicStruct =
                    ::core::default::Default::default();
                dynamic.set_represented_type(bevy_reflect::PartialReflect::get_represented_type_info(self));
                dynamic.insert_boxed("mode",
                    bevy_reflect::PartialReflect::to_dynamic(&self.mode));
                dynamic.insert_boxed("focal_distance",
                    bevy_reflect::PartialReflect::to_dynamic(&self.focal_distance));
                dynamic.insert_boxed("sensor_height",
                    bevy_reflect::PartialReflect::to_dynamic(&self.sensor_height));
                dynamic.insert_boxed("aperture_f_stops",
                    bevy_reflect::PartialReflect::to_dynamic(&self.aperture_f_stops));
                dynamic.insert_boxed("max_circle_of_confusion_diameter",
                    bevy_reflect::PartialReflect::to_dynamic(&self.max_circle_of_confusion_diameter));
                dynamic.insert_boxed("max_depth",
                    bevy_reflect::PartialReflect::to_dynamic(&self.max_depth));
                dynamic
            }
        }
        impl bevy_reflect::PartialReflect for DepthOfField where  {
            #[inline]
            fn get_represented_type_info(&self)
                -> ::core::option::Option<&'static bevy_reflect::TypeInfo> {
                ::core::option::Option::Some(<Self as
                            bevy_reflect::Typed>::type_info())
            }
            #[inline]
            fn try_apply(&mut self, value: &dyn bevy_reflect::PartialReflect)
                -> ::core::result::Result<(), bevy_reflect::ApplyError> {
                if let bevy_reflect::ReflectRef::Struct(struct_value) =
                        bevy_reflect::PartialReflect::reflect_ref(value) {
                    for (name, value) in
                        bevy_reflect::structs::Struct::iter_fields(struct_value) {
                        if let ::core::option::Option::Some(v) =
                                bevy_reflect::structs::Struct::field_mut(self, name) {
                            bevy_reflect::PartialReflect::try_apply(v, value)?;
                        }
                    }
                } else {
                    return ::core::result::Result::Err(bevy_reflect::ApplyError::MismatchedKinds {
                                from_kind: bevy_reflect::PartialReflect::reflect_kind(value),
                                to_kind: bevy_reflect::ReflectKind::Struct,
                            });
                }
                ::core::result::Result::Ok(())
            }
            #[inline]
            fn reflect_kind(&self) -> bevy_reflect::ReflectKind {
                bevy_reflect::ReflectKind::Struct
            }
            #[inline]
            fn reflect_ref(&self) -> bevy_reflect::ReflectRef {
                bevy_reflect::ReflectRef::Struct(self)
            }
            #[inline]
            fn reflect_mut(&mut self) -> bevy_reflect::ReflectMut {
                bevy_reflect::ReflectMut::Struct(self)
            }
            #[inline]
            fn reflect_owned(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                -> bevy_reflect::ReflectOwned {
                bevy_reflect::ReflectOwned::Struct(self)
            }
            #[inline]
            fn try_into_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    ::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect>> {
                ::core::result::Result::Ok(self)
            }
            #[inline]
            fn try_as_reflect(&self)
                -> ::core::option::Option<&dyn bevy_reflect::Reflect> {
                ::core::option::Option::Some(self)
            }
            #[inline]
            fn try_as_reflect_mut(&mut self)
                -> ::core::option::Option<&mut dyn bevy_reflect::Reflect> {
                ::core::option::Option::Some(self)
            }
            #[inline]
            fn into_partial_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect> {
                self
            }
            #[inline]
            fn as_partial_reflect(&self)
                -> &dyn bevy_reflect::PartialReflect {
                self
            }
            #[inline]
            fn as_partial_reflect_mut(&mut self)
                -> &mut dyn bevy_reflect::PartialReflect {
                self
            }
            fn reflect_partial_eq(&self,
                value: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<bool> {
                (bevy_reflect::structs::struct_partial_eq)(self, value)
            }
            fn reflect_partial_cmp(&self,
                value: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<::core::cmp::Ordering> {
                (bevy_reflect::structs::struct_partial_cmp)(self, value)
            }
            #[inline]
            fn reflect_clone(&self)
                ->
                    ::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
                    bevy_reflect::ReflectCloneError> {
                ::core::result::Result::Ok(bevy_reflect::__macro_exports::alloc_utils::Box::new(::core::clone::Clone::clone(self)))
            }
        }
        impl bevy_reflect::FromReflect for DepthOfField where  {
            fn from_reflect(reflect: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<Self> {
                if let bevy_reflect::ReflectRef::Struct(__ref_struct) =
                        bevy_reflect::PartialReflect::reflect_ref(reflect) {
                    let mut __this =
                        <Self as ::core::default::Default>::default();
                    if let ::core::option::Option::Some(__field) =
                            (||
                                        <DepthOfFieldMode as
                                                bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                                    "mode")?))() {
                        __this.mode = __field;
                    }
                    if let ::core::option::Option::Some(__field) =
                            (||
                                        <f32 as
                                                bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                                    "focal_distance")?))() {
                        __this.focal_distance = __field;
                    }
                    if let ::core::option::Option::Some(__field) =
                            (||
                                        <f32 as
                                                bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                                    "sensor_height")?))() {
                        __this.sensor_height = __field;
                    }
                    if let ::core::option::Option::Some(__field) =
                            (||
                                        <f32 as
                                                bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                                    "aperture_f_stops")?))() {
                        __this.aperture_f_stops = __field;
                    }
                    if let ::core::option::Option::Some(__field) =
                            (||
                                        <f32 as
                                                bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                                    "max_circle_of_confusion_diameter")?))() {
                        __this.max_circle_of_confusion_diameter = __field;
                    }
                    if let ::core::option::Option::Some(__field) =
                            (||
                                        <f32 as
                                                bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                                    "max_depth")?))() {
                        __this.max_depth = __field;
                    }
                    ::core::option::Option::Some(__this)
                } else { ::core::option::Option::None }
            }
        }
    };Reflect)]
76#[reflect(Component, Clone, Default)]
77pub struct DepthOfField {
78    /// The appearance of the effect.
79    pub mode: DepthOfFieldMode,
80
81    /// The distance in meters to the location in focus.
82    pub focal_distance: f32,
83
84    /// The height of the [image sensor format] in meters.
85    ///
86    /// Focal length is derived from the FOV and this value. The default is
87    /// 18.66mm, matching the [Super 35] format, which is popular in cinema.
88    ///
89    /// [image sensor format]: https://en.wikipedia.org/wiki/Image_sensor_format
90    ///
91    /// [Super 35]: https://en.wikipedia.org/wiki/Super_35
92    pub sensor_height: f32,
93
94    /// Along with the focal length, controls how much objects not in focus are
95    /// blurred.
96    pub aperture_f_stops: f32,
97
98    /// The maximum diameter, in pixels, that we allow a circle of confusion to be.
99    ///
100    /// A circle of confusion essentially describes the size of a blur.
101    ///
102    /// This value is nonphysical but is useful for avoiding pathologically-slow
103    /// behavior.
104    pub max_circle_of_confusion_diameter: f32,
105
106    /// Objects are never considered to be farther away than this distance as
107    /// far as depth of field is concerned, even if they actually are.
108    ///
109    /// This is primarily useful for skyboxes and background colors. The Bevy
110    /// renderer considers them to be infinitely far away. Without this value,
111    /// that would cause the circle of confusion to be infinitely large, capped
112    /// only by the `max_circle_of_confusion_diameter`. As that's unsightly,
113    /// this value can be used to essentially adjust how "far away" the skybox
114    /// or background are.
115    pub max_depth: f32,
116}
117
118/// Controls the appearance of the effect.
119#[derive(#[automatically_derived]
impl ::core::clone::Clone for DepthOfFieldMode {
    #[inline]
    fn clone(&self) -> DepthOfFieldMode { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for DepthOfFieldMode { }Copy, #[automatically_derived]
impl ::core::default::Default for DepthOfFieldMode {
    #[inline]
    fn default() -> DepthOfFieldMode { Self::Gaussian }
}Default, #[automatically_derived]
impl ::core::cmp::PartialEq for DepthOfFieldMode {
    #[inline]
    fn eq(&self, other: &DepthOfFieldMode) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr
    }
}PartialEq, #[automatically_derived]
impl ::core::fmt::Debug for DepthOfFieldMode {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                DepthOfFieldMode::Bokeh => "Bokeh",
                DepthOfFieldMode::Gaussian => "Gaussian",
            })
    }
}Debug, const _: () =
    {
        impl bevy_reflect::GetTypeRegistration for DepthOfFieldMode where  {
            fn get_type_registration() -> bevy_reflect::TypeRegistration {
                let mut registration =
                    bevy_reflect::TypeRegistration::of::<Self>();
                registration.insert::<bevy_reflect::ReflectFromPtr>(bevy_reflect::FromType::<Self>::from_type());
                registration.insert::<bevy_reflect::ReflectFromReflect>(bevy_reflect::FromType::<Self>::from_type());
                registration.register_type_data::<ReflectDefault, Self>();
                registration
            }
            #[inline(never)]
            fn register_type_dependencies(registry:
                    &mut bevy_reflect::TypeRegistry) {}
        }
        impl bevy_reflect::Typed for DepthOfFieldMode where  {
            #[inline]
            fn type_info() -> &'static bevy_reflect::TypeInfo {
                static CELL: bevy_reflect::utility::NonGenericTypeInfoCell =
                    bevy_reflect::utility::NonGenericTypeInfoCell::new();
                CELL.get_or_set(||
                        {
                            bevy_reflect::TypeInfo::Enum(bevy_reflect::enums::EnumInfo::new::<Self>(&[bevy_reflect::enums::VariantInfo::Unit(bevy_reflect::enums::UnitVariantInfo::new("Bokeh")),
                                                bevy_reflect::enums::VariantInfo::Unit(bevy_reflect::enums::UnitVariantInfo::new("Gaussian"))]))
                        })
            }
        }
        #[allow(deprecated, reason =
        "derives on a deprecated type shouldn't be considered a usage")]
        impl bevy_reflect::TypePath for DepthOfFieldMode where  {
            fn type_path() -> &'static str {
                "bevy_post_process::dof::DepthOfFieldMode"
            }
            fn short_type_path() -> &'static str { "DepthOfFieldMode" }
            fn type_ident() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("DepthOfFieldMode")
            }
            fn crate_name() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_post_process::dof".split(':').next().unwrap())
            }
            fn module_path() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_post_process::dof")
            }
        }
        impl bevy_reflect::Reflect for DepthOfFieldMode where  {
            #[inline]
            fn into_any(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn ::core::any::Any> {
                self
            }
            #[inline]
            fn as_any(&self) -> &dyn ::core::any::Any { self }
            #[inline]
            fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any { self }
            #[inline]
            fn into_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect> {
                self
            }
            #[inline]
            fn as_reflect(&self) -> &dyn bevy_reflect::Reflect { self }
            #[inline]
            fn as_reflect_mut(&mut self) -> &mut dyn bevy_reflect::Reflect {
                self
            }
            #[inline]
            fn set(&mut self,
                value:
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>)
                ->
                    ::core::result::Result<(),
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>> {
                *self = <dyn bevy_reflect::Reflect>::take(value)?;
                ::core::result::Result::Ok(())
            }
        }
        #[allow(non_upper_case_globals)]
        const _: () =
            {
                static __INVENTORY: ::inventory::Node =
                    ::inventory::Node {
                        value: &{
                                bevy_reflect::__macro_exports::auto_register::AutomaticReflectRegistrations(<DepthOfFieldMode
                                        as
                                        bevy_reflect::__macro_exports::auto_register::RegisterForReflection>::__register)
                            },
                        next: ::inventory::__private::UnsafeCell::new(::inventory::__private::Option::None),
                    };
                #[link_section = ".text.startup"]
                unsafe extern "C" fn __ctor() {
                    unsafe {
                        ::inventory::ErasedNode::submit(__INVENTORY.value,
                            &__INVENTORY)
                    }
                }
                #[used]
                #[link_section = ".init_array"]
                static __CTOR: unsafe extern "C" fn() = __ctor;
            };
        impl bevy_reflect::enums::Enum for DepthOfFieldMode where  {
            fn field(&self, __name_param: &str)
                -> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
                match self { _ => ::core::option::Option::None, }
            }
            fn field_at(&self, __index_param: usize)
                -> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
                match self { _ => ::core::option::Option::None, }
            }
            fn field_mut(&mut self, __name_param: &str)
                ->
                    ::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
                match self { _ => ::core::option::Option::None, }
            }
            fn field_at_mut(&mut self, __index_param: usize)
                ->
                    ::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
                match self { _ => ::core::option::Option::None, }
            }
            fn index_of(&self, __name_param: &str)
                -> ::core::option::Option<usize> {
                match self { _ => ::core::option::Option::None, }
            }
            fn name_at(&self, __index_param: usize)
                -> ::core::option::Option<&str> {
                match self { _ => ::core::option::Option::None, }
            }
            fn iter_fields(&self) -> bevy_reflect::enums::VariantFieldIter {
                bevy_reflect::enums::VariantFieldIter::new(self)
            }
            #[inline]
            fn field_len(&self) -> usize {
                match self {
                    DepthOfFieldMode::Bokeh { .. } => 0usize,
                    DepthOfFieldMode::Gaussian { .. } => 0usize,
                    _ => 0,
                }
            }
            #[inline]
            fn variant_name(&self) -> &str {
                match self {
                    DepthOfFieldMode::Bokeh { .. } => "Bokeh",
                    DepthOfFieldMode::Gaussian { .. } => "Gaussian",
                    _ =>
                        ::core::panicking::panic("internal error: entered unreachable code"),
                }
            }
            #[inline]
            fn variant_index(&self) -> usize {
                match self {
                    DepthOfFieldMode::Bokeh { .. } => 0usize,
                    DepthOfFieldMode::Gaussian { .. } => 1usize,
                    _ =>
                        ::core::panicking::panic("internal error: entered unreachable code"),
                }
            }
            #[inline]
            fn variant_type(&self) -> bevy_reflect::enums::VariantType {
                match self {
                    DepthOfFieldMode::Bokeh { .. } =>
                        bevy_reflect::enums::VariantType::Unit,
                    DepthOfFieldMode::Gaussian { .. } =>
                        bevy_reflect::enums::VariantType::Unit,
                    _ =>
                        ::core::panicking::panic("internal error: entered unreachable code"),
                }
            }
            fn to_dynamic_enum(&self) -> bevy_reflect::enums::DynamicEnum {
                bevy_reflect::enums::DynamicEnum::from_ref::<Self>(self)
            }
        }
        impl bevy_reflect::PartialReflect for DepthOfFieldMode where  {
            #[inline]
            fn get_represented_type_info(&self)
                -> ::core::option::Option<&'static bevy_reflect::TypeInfo> {
                ::core::option::Option::Some(<Self as
                            bevy_reflect::Typed>::type_info())
            }
            #[inline]
            fn try_apply(&mut self,
                __value_param: &dyn bevy_reflect::PartialReflect)
                -> ::core::result::Result<(), bevy_reflect::ApplyError> {
                if let bevy_reflect::ReflectRef::Enum(__value_param) =
                        bevy_reflect::PartialReflect::reflect_ref(__value_param) {
                    if bevy_reflect::enums::Enum::variant_name(self) ==
                            bevy_reflect::enums::Enum::variant_name(__value_param) {
                        match bevy_reflect::enums::Enum::variant_type(__value_param)
                            {
                            bevy_reflect::enums::VariantType::Struct => {
                                for field in
                                    bevy_reflect::enums::Enum::iter_fields(__value_param) {
                                    let name = field.name().unwrap();
                                    if let ::core::option::Option::Some(v) =
                                            bevy_reflect::enums::Enum::field_mut(self, name) {
                                        bevy_reflect::PartialReflect::try_apply(v, field.value())?;
                                    }
                                }
                            }
                            bevy_reflect::enums::VariantType::Tuple => {
                                for (index, field) in
                                    ::core::iter::Iterator::enumerate(bevy_reflect::enums::Enum::iter_fields(__value_param))
                                    {
                                    if let ::core::option::Option::Some(v) =
                                            bevy_reflect::enums::Enum::field_at_mut(self, index) {
                                        bevy_reflect::PartialReflect::try_apply(v, field.value())?;
                                    }
                                }
                            }
                            _ => {}
                        }
                    } else {
                        match bevy_reflect::enums::Enum::variant_name(__value_param)
                            {
                            "Bokeh" => { *self = DepthOfFieldMode::Bokeh {} }
                            "Gaussian" => { *self = DepthOfFieldMode::Gaussian {} }
                            name => {
                                return ::core::result::Result::Err(bevy_reflect::ApplyError::UnknownVariant {
                                            enum_name: ::core::convert::Into::into(bevy_reflect::DynamicTypePath::reflect_type_path(self)),
                                            variant_name: ::core::convert::Into::into(name),
                                        });
                            }
                        }
                    }
                } else {
                    return ::core::result::Result::Err(bevy_reflect::ApplyError::MismatchedKinds {
                                from_kind: bevy_reflect::PartialReflect::reflect_kind(__value_param),
                                to_kind: bevy_reflect::ReflectKind::Enum,
                            });
                }
                ::core::result::Result::Ok(())
            }
            fn reflect_kind(&self) -> bevy_reflect::ReflectKind {
                bevy_reflect::ReflectKind::Enum
            }
            fn reflect_ref(&self) -> bevy_reflect::ReflectRef {
                bevy_reflect::ReflectRef::Enum(self)
            }
            fn reflect_mut(&mut self) -> bevy_reflect::ReflectMut {
                bevy_reflect::ReflectMut::Enum(self)
            }
            fn reflect_owned(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                -> bevy_reflect::ReflectOwned {
                bevy_reflect::ReflectOwned::Enum(self)
            }
            #[inline]
            fn try_into_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    ::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect>> {
                ::core::result::Result::Ok(self)
            }
            #[inline]
            fn try_as_reflect(&self)
                -> ::core::option::Option<&dyn bevy_reflect::Reflect> {
                ::core::option::Option::Some(self)
            }
            #[inline]
            fn try_as_reflect_mut(&mut self)
                -> ::core::option::Option<&mut dyn bevy_reflect::Reflect> {
                ::core::option::Option::Some(self)
            }
            #[inline]
            fn into_partial_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect> {
                self
            }
            #[inline]
            fn as_partial_reflect(&self)
                -> &dyn bevy_reflect::PartialReflect {
                self
            }
            #[inline]
            fn as_partial_reflect_mut(&mut self)
                -> &mut dyn bevy_reflect::PartialReflect {
                self
            }
            fn reflect_hash(&self) -> ::core::option::Option<u64> {
                (bevy_reflect::enums::enum_hash)(self)
            }
            fn reflect_partial_eq(&self,
                value: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<bool> {
                let value =
                    <dyn bevy_reflect::PartialReflect>::try_downcast_ref::<Self>(value);
                if let ::core::option::Option::Some(value) = value {
                    ::core::option::Option::Some(::core::cmp::PartialEq::eq(self,
                            value))
                } else { ::core::option::Option::Some(false) }
            }
            fn reflect_partial_cmp(&self,
                value: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<::core::cmp::Ordering> {
                (bevy_reflect::enums::enum_partial_cmp)(self, value)
            }
            #[inline]
            fn reflect_clone(&self)
                ->
                    ::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
                    bevy_reflect::ReflectCloneError> {
                ::core::result::Result::Ok(bevy_reflect::__macro_exports::alloc_utils::Box::new(::core::clone::Clone::clone(self)))
            }
        }
        impl bevy_reflect::FromReflect for DepthOfFieldMode where  {
            fn from_reflect(__param0: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<Self> {
                if let bevy_reflect::ReflectRef::Enum(__param0) =
                        bevy_reflect::PartialReflect::reflect_ref(__param0) {
                    match bevy_reflect::enums::Enum::variant_name(__param0) {
                        "Bokeh" =>
                            ::core::option::Option::Some(DepthOfFieldMode::Bokeh {}),
                        "Gaussian" =>
                            ::core::option::Option::Some(DepthOfFieldMode::Gaussian {}),
                        name => ::core::option::Option::None,
                    }
                } else { ::core::option::Option::None }
            }
        }
    };Reflect)]
120#[reflect(Default, Clone, PartialEq)]
121pub enum DepthOfFieldMode {
122    /// A more accurate simulation, in which circles of confusion generate
123    /// "spots" of light.
124    ///
125    /// For more information, see [Wikipedia's article on *bokeh*].
126    ///
127    /// [Wikipedia's article on *bokeh*]: https://en.wikipedia.org/wiki/Bokeh
128    Bokeh,
129
130    /// A faster simulation, in which out-of-focus areas are simply blurred.
131    ///
132    /// This is less accurate to actual lens behavior and is generally less
133    /// aesthetically pleasing but requires less video memory bandwidth.
134    ///
135    /// This is the default.
136    #[default]
137    Gaussian,
138}
139
140/// Data about the depth of field effect that's uploaded to the GPU.
141#[derive(#[automatically_derived]
impl ::core::clone::Clone for DepthOfFieldUniform {
    #[inline]
    fn clone(&self) -> DepthOfFieldUniform {
        let _: ::core::clone::AssertParamIsClone<f32>;
        let _: ::core::clone::AssertParamIsClone<u32>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for DepthOfFieldUniform { }Copy, impl bevy_ecs::component::Component for DepthOfFieldUniform where
    Self: ::core::marker::Send + ::core::marker::Sync + 'static {
    const STORAGE_TYPE: bevy_ecs::component::StorageType =
        bevy_ecs::component::StorageType::Table;
    type Mutability = bevy_ecs::component::Mutable;
    fn register_required_components(_requiree:
            bevy_ecs::component::ComponentId,
        required_components:
            &mut bevy_ecs::component::RequiredComponentsRegistrator) {}
    fn clone_behavior() -> bevy_ecs::component::ComponentCloneBehavior {
        use bevy_ecs::component::{
            DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone,
        };
        (&&&bevy_ecs::component::DefaultCloneBehaviorSpecialization::<Self>::default()).default_clone_behavior()
    }
    fn relationship_accessor()
        ->
            ::core::option::Option<bevy_ecs::relationship::ComponentRelationshipAccessor<Self>> {
        ::core::option::Option::None
    }
}Component, impl bevy_render::render_resource::encase::private::ShaderSize for
    DepthOfFieldUniform where
    f32: bevy_render::render_resource::encase::private::ShaderSize,
    f32: bevy_render::render_resource::encase::private::ShaderSize,
    f32: bevy_render::render_resource::encase::private::ShaderSize,
    f32: bevy_render::render_resource::encase::private::ShaderSize,
    f32: bevy_render::render_resource::encase::private::ShaderSize,
    u32: bevy_render::render_resource::encase::private::ShaderSize,
    u32: bevy_render::render_resource::encase::private::ShaderSize,
    u32: bevy_render::render_resource::encase::private::ShaderSize {}ShaderType)]
142pub struct DepthOfFieldUniform {
143    /// The distance in meters to the location in focus.
144    focal_distance: f32,
145
146    /// The focal length. See the comment in `DepthOfFieldParams` in `dof.wgsl`
147    /// for more information.
148    focal_length: f32,
149
150    /// The premultiplied factor that we scale the circle of confusion by.
151    ///
152    /// This is calculated as `focal_length² / (sensor_height *
153    /// aperture_f_stops)`.
154    coc_scale_factor: f32,
155
156    /// The maximum circle of confusion diameter in pixels. See the comment in
157    /// [`DepthOfField`] for more information.
158    max_circle_of_confusion_diameter: f32,
159
160    /// The depth value that we clamp distant objects to. See the comment in
161    /// [`DepthOfField`] for more information.
162    max_depth: f32,
163
164    /// Padding.
165    pad_a: u32,
166    /// Padding.
167    pad_b: u32,
168    /// Padding.
169    pad_c: u32,
170}
171
172/// A key that uniquely identifies depth of field pipelines.
173#[derive(#[automatically_derived]
impl ::core::clone::Clone for DepthOfFieldPipelineKey {
    #[inline]
    fn clone(&self) -> DepthOfFieldPipelineKey {
        let _: ::core::clone::AssertParamIsClone<DofPass>;
        let _: ::core::clone::AssertParamIsClone<TextureFormat>;
        let _: ::core::clone::AssertParamIsClone<bool>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for DepthOfFieldPipelineKey { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for DepthOfFieldPipelineKey {
    #[inline]
    fn eq(&self, other: &DepthOfFieldPipelineKey) -> bool {
        self.multisample == other.multisample && self.pass == other.pass &&
            self.target_format == other.target_format
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for DepthOfFieldPipelineKey {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<DofPass>;
        let _: ::core::cmp::AssertParamIsEq<TextureFormat>;
        let _: ::core::cmp::AssertParamIsEq<bool>;
    }
}Eq, #[automatically_derived]
impl ::core::hash::Hash for DepthOfFieldPipelineKey {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.pass, state);
        ::core::hash::Hash::hash(&self.target_format, state);
        ::core::hash::Hash::hash(&self.multisample, state)
    }
}Hash)]
174pub struct DepthOfFieldPipelineKey {
175    /// Whether we're doing Gaussian or bokeh blur.
176    pass: DofPass,
177    target_format: TextureFormat,
178    /// Whether the render target is multisampled.
179    multisample: bool,
180}
181
182/// Identifies a specific depth of field render pass.
183#[derive(#[automatically_derived]
impl ::core::clone::Clone for DofPass {
    #[inline]
    fn clone(&self) -> DofPass { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for DofPass { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for DofPass {
    #[inline]
    fn eq(&self, other: &DofPass) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for DofPass {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {}
}Eq, #[automatically_derived]
impl ::core::hash::Hash for DofPass {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        ::core::hash::Hash::hash(&__self_discr, state)
    }
}Hash)]
184enum DofPass {
185    /// The first, horizontal, Gaussian blur pass.
186    GaussianHorizontal,
187    /// The second, vertical, Gaussian blur pass.
188    GaussianVertical,
189    /// The first bokeh pass: vertical and diagonal.
190    BokehPass0,
191    /// The second bokeh pass: two diagonals.
192    BokehPass1,
193}
194
195impl Plugin for DepthOfFieldPlugin {
196    fn build(&self, app: &mut App) {
197        {
    {
        let mut embedded =
            app.world_mut().resource_mut::<::bevy_asset::io::embedded::EmbeddedAssetRegistry>();
        let path =
            {
                let crate_name =
                    "bevy_post_process::dof".split(':').next().unwrap();
                ::bevy_asset::io::embedded::_embedded_asset_path(crate_name,
                    "src".as_ref(), "src/dof/mod.rs".as_ref(),
                    "dof.wgsl".as_ref())
            };
        let watched_path =
            ::bevy_asset::io::embedded::watched_path("src/dof/mod.rs",
                "dof.wgsl");
        embedded.insert_asset(watched_path, &path,
            b"// Performs depth of field postprocessing, with both Gaussian and bokeh kernels.\n//\n// Gaussian blur is performed as a separable convolution: first blurring in the\n// X direction, and then in the Y direction. This is asymptotically more\n// efficient than performing a 2D convolution.\n//\n// The Bokeh blur uses a similar, but more complex, separable convolution\n// technique. The algorithm is described in Colin Barr\xc3\xa9-Brisebois, \"Hexagonal\n// Bokeh Blur Revisited\" [1]. It\'s motivated by the observation that we can use\n// separable convolutions not only to produce boxes but to produce\n// parallelograms. Thus, by performing three separable convolutions in sequence,\n// we can produce a hexagonal shape. The first and second convolutions are done\n// simultaneously using multiple render targets to cut the total number of\n// passes down to two.\n//\n// [1]: https://colinbarrebrisebois.com/2017/04/18/hexagonal-bokeh-blur-revisited-part-2-improved-2-pass-version/\n\n#import bevy_core_pipeline::fullscreen_vertex_shader::FullscreenVertexOutput\n#import bevy_pbr::mesh_view_bindings::view\n#import bevy_pbr::view_transformations::depth_ndc_to_view_z\n#import bevy_post_process::gaussian_blur::gaussian_blur\n#import bevy_render::view::View\n\n// Parameters that control the depth of field effect. See\n// `bevy_core_pipeline::dof::DepthOfFieldUniforms` for information on what these\n// parameters mean.\nstruct DepthOfFieldParams {\n    /// The distance in meters to the location in focus.\n    focal_distance: f32,\n\n    /// The [focal length]. Physically speaking, this represents \"the distance\n    /// from the center of the lens to the principal foci of the lens\". The\n    /// default value, 50 mm, is considered representative of human eyesight.\n    /// Real-world lenses range from anywhere from 5 mm for \"fisheye\" lenses to\n    /// 2000 mm for \"super-telephoto\" lenses designed for very distant objects.\n    ///\n    /// The higher the value, the more blurry objects not in focus will be.\n    ///\n    /// [focal length]: https://en.wikipedia.org/wiki/Focal_length\n    focal_length: f32,\n\n    /// The premultiplied factor that we scale the circle of confusion by.\n    ///\n    /// This is calculated as `focal_length\xc2\xb2 / (sensor_height * aperture_f_stops)`.\n    coc_scale_factor: f32,\n\n    /// The maximum diameter, in pixels, that we allow a circle of confusion to be.\n    ///\n    /// A circle of confusion essentially describes the size of a blur.\n    ///\n    /// This value is nonphysical but is useful for avoiding pathologically-slow\n    /// behavior.\n    max_circle_of_confusion_diameter: f32,\n\n    /// The depth value that we clamp distant objects to. See the comment in\n    /// [`DepthOfField`] for more information.\n    max_depth: f32,\n\n    /// Padding.\n    pad_a: u32,\n    /// Padding.\n    pad_b: u32,\n    /// Padding.\n    pad_c: u32,\n}\n\n// The first bokeh pass outputs to two render targets. We declare them here.\nstruct DualOutput {\n    // The vertical output.\n    @location(0) output_0: vec4<f32>,\n    // The diagonal output.\n    @location(1) output_1: vec4<f32>,\n}\n\n// @group(0) @binding(0) is `mesh_view_bindings::view`.\n\n// The depth texture for the main view.\n#ifdef MULTISAMPLED\n@group(0) @binding(1) var depth_texture: texture_depth_multisampled_2d;\n#else   // MULTISAMPLED\n@group(0) @binding(1) var depth_texture: texture_depth_2d;\n#endif  // MULTISAMPLED\n\n// The main color texture.\n@group(0) @binding(2) var color_texture_a: texture_2d<f32>;\n\n// The auxiliary color texture that we\'re sampling from. This is only used as\n// part of the second bokeh pass.\n#ifdef DUAL_INPUT\n@group(0) @binding(3) var color_texture_b: texture_2d<f32>;\n#endif  // DUAL_INPUT\n\n// The global uniforms, representing data backed by buffers shared among all\n// views in the scene.\n\n// The parameters that control the depth of field effect.\n@group(1) @binding(0) var<uniform> dof_params: DepthOfFieldParams;\n\n// The sampler that\'s used to fetch texels from the source color buffer.\n@group(1) @binding(1) var color_texture_sampler: sampler;\n\n// used to ensure `depth * (focus - f)` is always a positive number,\nconst EPSILON: f32 = 1.19209290e-07;\n// cos(-30\xc2\xb0), used for the bokeh blur.\nconst COS_NEG_FRAC_PI_6: f32 = 0.8660254037844387;\n// sin(-30\xc2\xb0), used for the bokeh blur.\nconst SIN_NEG_FRAC_PI_6: f32 = -0.5;\n// cos(-150\xc2\xb0), used for the bokeh blur.\nconst COS_NEG_FRAC_PI_5_6: f32 = -0.8660254037844387;\n// sin(-150\xc2\xb0), used for the bokeh blur.\nconst SIN_NEG_FRAC_PI_5_6: f32 = -0.5;\n\n// Calculates and returns the diameter (not the radius) of the [circle of\n// confusion].\n//\n// [circle of confusion]: https://en.wikipedia.org/wiki/Circle_of_confusion\nfn calculate_circle_of_confusion(in_frag_coord: vec4<f32>) -> f32 {\n    // Unpack the depth of field parameters.\n    let focus = dof_params.focal_distance;\n    let f = dof_params.focal_length;\n    let scale = dof_params.coc_scale_factor;\n    let max_coc_diameter = dof_params.max_circle_of_confusion_diameter;\n\n    // Sample the depth.\n    let frag_coord = vec2<i32>(floor(in_frag_coord.xy));\n    let raw_depth = textureLoad(depth_texture, frag_coord, 0);\n    let depth = min(-depth_ndc_to_view_z(raw_depth), dof_params.max_depth);\n\n    // Calculate the circle of confusion.\n    //\n    // This is just the formula from Wikipedia [1].\n    //\n    // [1]: https://en.wikipedia.org/wiki/Circle_of_confusion#Determining_a_circle_of_confusion_diameter_from_the_object_field\n    let candidate_coc = scale * abs(depth - focus) / (depth * max(focus - f, EPSILON));\n\n    let framebuffer_size = vec2<f32>(textureDimensions(color_texture_a));\n    return clamp(candidate_coc * framebuffer_size.y, 0.0, max_coc_diameter);\n}\n\n// Performs a box blur in a single direction, sampling `color_texture_a`.\n//\n// * `frag_coord` is the screen-space pixel coordinate of the fragment (i.e. the\n//   `position` input to the fragment).\n//\n// * `coc` is the diameter (not the radius) of the circle of confusion for this\n//   fragment.\n//\n// * `frag_offset` is the vector, in screen-space units, from one sample to the\n//   next. This need not be horizontal or vertical.\nfn box_blur_a(frag_coord: vec4<f32>, coc: f32, frag_offset: vec2<f32>) -> vec4<f32> {\n    let support = i32(round(coc * 0.5));\n    let uv = frag_coord.xy / vec2<f32>(textureDimensions(color_texture_a));\n    let offset = frag_offset / vec2<f32>(textureDimensions(color_texture_a));\n\n    // Accumulate samples in a single direction.\n    var sum = vec3(0.0);\n    for (var i = 0; i <= support; i += 1) {\n        sum += textureSampleLevel(\n            color_texture_a, color_texture_sampler, uv + offset * f32(i), 0.0).rgb;\n    }\n\n    return vec4(sum / vec3(1.0 + f32(support)), 1.0);\n}\n\n// Performs a box blur in a single direction, sampling `color_texture_b`.\n//\n// * `frag_coord` is the screen-space pixel coordinate of the fragment (i.e. the\n//   `position` input to the fragment).\n//\n// * `coc` is the diameter (not the radius) of the circle of confusion for this\n//   fragment.\n//\n// * `frag_offset` is the vector, in screen-space units, from one sample to the\n//   next. This need not be horizontal or vertical.\n#ifdef DUAL_INPUT\nfn box_blur_b(frag_coord: vec4<f32>, coc: f32, frag_offset: vec2<f32>) -> vec4<f32> {\n    let support = i32(round(coc * 0.5));\n    let uv = frag_coord.xy / vec2<f32>(textureDimensions(color_texture_b));\n    let offset = frag_offset / vec2<f32>(textureDimensions(color_texture_b));\n\n    // Accumulate samples in a single direction.\n    var sum = vec3(0.0);\n    for (var i = 0; i <= support; i += 1) {\n        sum += textureSampleLevel(\n            color_texture_b, color_texture_sampler, uv + offset * f32(i), 0.0).rgb;\n    }\n\n    return vec4(sum / vec3(1.0 + f32(support)), 1.0);\n}\n#endif\n\n// Calculates the horizontal component of the separable Gaussian blur.\n@fragment\nfn gaussian_horizontal(in: FullscreenVertexOutput) -> @location(0) vec4<f32> {\n    let coc = calculate_circle_of_confusion(in.position);\n    return gaussian_blur(color_texture_a, color_texture_sampler, in.position, coc, vec2(1.0, 0.0));\n}\n\n// Calculates the vertical component of the separable Gaussian blur.\n@fragment\nfn gaussian_vertical(in: FullscreenVertexOutput) -> @location(0) vec4<f32> {\n    let coc = calculate_circle_of_confusion(in.position);\n    return gaussian_blur(color_texture_a, color_texture_sampler, in.position, coc, vec2(0.0, 1.0));\n}\n\n// Calculates the vertical and first diagonal components of the separable\n// hexagonal bokeh blur.\n//\n//         \xe2\x95\xb1\n//        \xe2\x95\xb1\n//       \xe2\x80\xa2\n//       \xe2\x94\x82\n//       \xe2\x94\x82\n@fragment\nfn bokeh_pass_a(in: FullscreenVertexOutput) -> DualOutput {\n    let coc = calculate_circle_of_confusion(in.position);\n    let vertical = box_blur_a(in.position, coc, vec2(0.0, 1.0));\n    let diagonal = box_blur_a(in.position, coc, vec2(COS_NEG_FRAC_PI_6, SIN_NEG_FRAC_PI_6));\n\n    // Note that the diagonal part is pre-mixed with the vertical component.\n    var output: DualOutput;\n    output.output_0 = vertical;\n    output.output_1 = mix(vertical, diagonal, 0.5);\n    return output;\n}\n\n// Calculates the second diagonal components of the separable hexagonal bokeh\n// blur.\n//\n//     \xe2\x95\xb2   \xe2\x95\xb1\n//      \xe2\x95\xb2 \xe2\x95\xb1\n//       \xe2\x80\xa2\n#ifdef DUAL_INPUT\n@fragment\nfn bokeh_pass_b(in: FullscreenVertexOutput) -> @location(0) vec4<f32> {\n    let coc = calculate_circle_of_confusion(in.position);\n    let output_0 = box_blur_a(in.position, coc, vec2(COS_NEG_FRAC_PI_6, SIN_NEG_FRAC_PI_6));\n    let output_1 = box_blur_b(in.position, coc, vec2(COS_NEG_FRAC_PI_5_6, SIN_NEG_FRAC_PI_5_6));\n    return mix(output_0, output_1, 0.5);\n}\n#endif\n");
    }
};embedded_asset!(app, "dof.wgsl");
198
199        app.add_plugins(UniformComponentPlugin::<DepthOfFieldUniform>::default());
200
201        app.add_plugins(SyncComponentPlugin::<DepthOfField>::default());
202
203        let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
204            return;
205        };
206
207        render_app
208            .init_gpu_resource::<SpecializedRenderPipelines<DepthOfFieldPipeline>>()
209            .init_resource::<DepthOfFieldGlobalBindGroup>()
210            .add_systems(RenderStartup, init_dof_global_bind_group_layout)
211            .add_systems(ExtractSchedule, extract_depth_of_field_settings)
212            .add_systems(
213                Render,
214                (
215                    configure_depth_of_field_view_targets
216                        .ambiguous_with(RenderSystems::PrepareViews),
217                    prepare_auxiliary_depth_of_field_textures,
218                )
219                    .after(prepare_view_targets)
220                    .in_set(RenderSystems::PrepareViews),
221            )
222            .add_systems(
223                Render,
224                (
225                    prepare_depth_of_field_view_bind_group_layouts,
226                    prepare_depth_of_field_pipelines,
227                )
228                    .chain()
229                    .in_set(RenderSystems::Prepare),
230            )
231            .add_systems(
232                Render,
233                prepare_depth_of_field_global_bind_group.in_set(RenderSystems::PrepareBindGroups),
234            )
235            .add_systems(Core3d, depth_of_field.after(bloom).before(tonemapping));
236    }
237}
238
239/// The layout for the bind group shared among all invocations of the depth of
240/// field shader.
241#[derive(impl bevy_ecs::resource::Resource for DepthOfFieldGlobalBindGroupLayout where
    Self: ::core::marker::Send + ::core::marker::Sync + 'static {}Resource, #[automatically_derived]
impl ::core::clone::Clone for DepthOfFieldGlobalBindGroupLayout {
    #[inline]
    fn clone(&self) -> DepthOfFieldGlobalBindGroupLayout {
        DepthOfFieldGlobalBindGroupLayout {
            layout: ::core::clone::Clone::clone(&self.layout),
            color_texture_sampler: ::core::clone::Clone::clone(&self.color_texture_sampler),
        }
    }
}Clone)]
242pub struct DepthOfFieldGlobalBindGroupLayout {
243    /// The layout.
244    layout: BindGroupLayoutDescriptor,
245    /// The sampler used to sample from the color buffer or buffers.
246    color_texture_sampler: Sampler,
247}
248
249/// The bind group shared among all invocations of the depth of field shader,
250/// regardless of view.
251#[derive(impl bevy_ecs::resource::Resource for DepthOfFieldGlobalBindGroup where
    Self: ::core::marker::Send + ::core::marker::Sync + 'static {}Resource, #[automatically_derived]
impl ::core::default::Default for DepthOfFieldGlobalBindGroup {
    #[inline]
    fn default() -> DepthOfFieldGlobalBindGroup {
        DepthOfFieldGlobalBindGroup(::core::default::Default::default())
    }
}Default, impl ::core::ops::Deref for DepthOfFieldGlobalBindGroup {
    type Target = Option<BindGroup>;
    fn deref(&self) -> &Self::Target { &self.0 }
}Deref, impl ::core::ops::DerefMut for DepthOfFieldGlobalBindGroup {
    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}DerefMut)]
252pub struct DepthOfFieldGlobalBindGroup(Option<BindGroup>);
253
254#[derive(impl bevy_ecs::component::Component for DepthOfFieldPipelines where
    Self: ::core::marker::Send + ::core::marker::Sync + 'static {
    const STORAGE_TYPE: bevy_ecs::component::StorageType =
        bevy_ecs::component::StorageType::Table;
    type Mutability = bevy_ecs::component::Mutable;
    fn register_required_components(_requiree:
            bevy_ecs::component::ComponentId,
        required_components:
            &mut bevy_ecs::component::RequiredComponentsRegistrator) {}
    fn clone_behavior() -> bevy_ecs::component::ComponentCloneBehavior {
        use bevy_ecs::component::{
            DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone,
        };
        (&&&bevy_ecs::component::DefaultCloneBehaviorSpecialization::<Self>::default()).default_clone_behavior()
    }
    fn map_entities<M: bevy_ecs::entity::EntityMapper>(this: &mut Self,
        mapper: &mut M) {
        use bevy_ecs::entity::MapEntities;
        match this {
            Self::Gaussian { .. } => {}
            Self::Bokeh { .. } => {}
            _ => {}
        }
    }
    fn relationship_accessor()
        ->
            ::core::option::Option<bevy_ecs::relationship::ComponentRelationshipAccessor<Self>> {
        ::core::option::Option::None
    }
}Component)]
255pub enum DepthOfFieldPipelines {
256    Gaussian {
257        horizontal: CachedRenderPipelineId,
258        vertical: CachedRenderPipelineId,
259    },
260    Bokeh {
261        pass_0: CachedRenderPipelineId,
262        pass_1: CachedRenderPipelineId,
263    },
264}
265
266struct DepthOfFieldPipelineRenderInfo {
267    pass_label: &'static str,
268    view_bind_group_label: &'static str,
269    pipeline: CachedRenderPipelineId,
270    is_dual_input: bool,
271    is_dual_output: bool,
272}
273
274/// The extra texture used as the second render target for the hexagonal bokeh
275/// blur.
276///
277/// This is the same size and format as the main view target texture. It'll only
278/// be present if bokeh is being used.
279#[derive(impl bevy_ecs::component::Component for AuxiliaryDepthOfFieldTexture where
    Self: ::core::marker::Send + ::core::marker::Sync + 'static {
    const STORAGE_TYPE: bevy_ecs::component::StorageType =
        bevy_ecs::component::StorageType::Table;
    type Mutability = bevy_ecs::component::Mutable;
    fn register_required_components(_requiree:
            bevy_ecs::component::ComponentId,
        required_components:
            &mut bevy_ecs::component::RequiredComponentsRegistrator) {}
    fn clone_behavior() -> bevy_ecs::component::ComponentCloneBehavior {
        use bevy_ecs::component::{
            DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone,
        };
        (&&&bevy_ecs::component::DefaultCloneBehaviorSpecialization::<Self>::default()).default_clone_behavior()
    }
    fn relationship_accessor()
        ->
            ::core::option::Option<bevy_ecs::relationship::ComponentRelationshipAccessor<Self>> {
        ::core::option::Option::None
    }
}Component, impl ::core::ops::Deref for AuxiliaryDepthOfFieldTexture {
    type Target = CachedTexture;
    fn deref(&self) -> &Self::Target { &self.0 }
}Deref, impl ::core::ops::DerefMut for AuxiliaryDepthOfFieldTexture {
    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}DerefMut)]
280pub struct AuxiliaryDepthOfFieldTexture(CachedTexture);
281
282/// Bind group layouts for depth of field specific to a single view.
283#[derive(impl bevy_ecs::component::Component for ViewDepthOfFieldBindGroupLayouts where
    Self: ::core::marker::Send + ::core::marker::Sync + 'static {
    const STORAGE_TYPE: bevy_ecs::component::StorageType =
        bevy_ecs::component::StorageType::Table;
    type Mutability = bevy_ecs::component::Mutable;
    fn register_required_components(_requiree:
            bevy_ecs::component::ComponentId,
        required_components:
            &mut bevy_ecs::component::RequiredComponentsRegistrator) {}
    fn clone_behavior() -> bevy_ecs::component::ComponentCloneBehavior {
        use bevy_ecs::component::{
            DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone,
        };
        (&&&bevy_ecs::component::DefaultCloneBehaviorSpecialization::<Self>::default()).default_clone_behavior()
    }
    fn relationship_accessor()
        ->
            ::core::option::Option<bevy_ecs::relationship::ComponentRelationshipAccessor<Self>> {
        ::core::option::Option::None
    }
}Component, #[automatically_derived]
impl ::core::clone::Clone for ViewDepthOfFieldBindGroupLayouts {
    #[inline]
    fn clone(&self) -> ViewDepthOfFieldBindGroupLayouts {
        ViewDepthOfFieldBindGroupLayouts {
            single_input: ::core::clone::Clone::clone(&self.single_input),
            dual_input: ::core::clone::Clone::clone(&self.dual_input),
        }
    }
}Clone)]
284pub struct ViewDepthOfFieldBindGroupLayouts {
285    /// The bind group layout for passes that take only one input.
286    single_input: BindGroupLayoutDescriptor,
287
288    /// The bind group layout for the second bokeh pass, which takes two inputs.
289    ///
290    /// This will only be present if bokeh is in use.
291    dual_input: Option<BindGroupLayoutDescriptor>,
292}
293
294/// Information needed to specialize the pipeline corresponding to a pass of the
295/// depth of field shader.
296pub struct DepthOfFieldPipeline {
297    /// The bind group layouts specific to each view.
298    view_bind_group_layouts: ViewDepthOfFieldBindGroupLayouts,
299    /// The bind group layout shared among all invocations of the depth of field
300    /// shader.
301    global_bind_group_layout: BindGroupLayoutDescriptor,
302    /// The asset handle for the fullscreen vertex shader.
303    fullscreen_shader: FullscreenShader,
304    /// The fragment shader asset handle.
305    fragment_shader: Handle<Shader>,
306}
307
308impl Default for DepthOfField {
309    fn default() -> Self {
310        let physical_camera_default = PhysicalCameraParameters::default();
311        Self {
312            focal_distance: 10.0,
313            aperture_f_stops: physical_camera_default.aperture_f_stops,
314            sensor_height: physical_camera_default.sensor_height,
315            max_circle_of_confusion_diameter: 64.0,
316            max_depth: f32::INFINITY,
317            mode: DepthOfFieldMode::default(),
318        }
319    }
320}
321
322impl DepthOfField {
323    /// Initializes [`DepthOfField`] from a set of
324    /// [`PhysicalCameraParameters`].
325    ///
326    /// By passing the same [`PhysicalCameraParameters`] object to this function
327    /// and to [`bevy_camera::Exposure::from_physical_camera`], matching
328    /// results for both the exposure and depth of field effects can be
329    /// obtained.
330    ///
331    /// All fields of the returned [`DepthOfField`] other than
332    /// `focal_length` and `aperture_f_stops` are set to their default values.
333    pub fn from_physical_camera(camera: &PhysicalCameraParameters) -> DepthOfField {
334        DepthOfField {
335            sensor_height: camera.sensor_height,
336            aperture_f_stops: camera.aperture_f_stops,
337            ..default()
338        }
339    }
340}
341
342pub fn init_dof_global_bind_group_layout(mut commands: Commands, render_device: Res<RenderDevice>) {
343    // Create the bind group layout that will be shared among all instances
344    // of the depth of field shader.
345    let layout = BindGroupLayoutDescriptor::new(
346        "depth of field global bind group layout",
347        &BindGroupLayoutEntries::sequential(
348            ShaderStages::FRAGMENT,
349            (
350                // `dof_params`
351                uniform_buffer::<DepthOfFieldUniform>(true),
352                // `color_texture_sampler`
353                sampler(SamplerBindingType::Filtering),
354            ),
355        ),
356    );
357
358    // Create the color texture sampler.
359    let sampler = render_device.create_sampler(&SamplerDescriptor {
360        label: Some("depth of field sampler"),
361        mag_filter: FilterMode::Linear,
362        min_filter: FilterMode::Linear,
363        ..default()
364    });
365
366    commands.insert_resource(DepthOfFieldGlobalBindGroupLayout {
367        color_texture_sampler: sampler,
368        layout,
369    });
370}
371
372/// Creates the bind group layouts for the depth of field effect that are
373/// specific to each view.
374pub fn prepare_depth_of_field_view_bind_group_layouts(
375    mut commands: Commands,
376    view_targets: Query<(Entity, &DepthOfField, &Msaa)>,
377) {
378    for (view, depth_of_field, msaa) in view_targets.iter() {
379        // Create the bind group layout for the passes that take one input.
380        let single_input = BindGroupLayoutDescriptor::new(
381            "depth of field bind group layout (single input)",
382            &BindGroupLayoutEntries::sequential(
383                ShaderStages::FRAGMENT,
384                (
385                    uniform_buffer::<ViewUniform>(true),
386                    if *msaa != Msaa::Off {
387                        texture_depth_2d_multisampled()
388                    } else {
389                        texture_depth_2d()
390                    },
391                    texture_2d(TextureSampleType::Float { filterable: true }),
392                ),
393            ),
394        );
395
396        // If needed, create the bind group layout for the second bokeh pass,
397        // which takes two inputs. We only need to do this if bokeh is in use.
398        let dual_input = match depth_of_field.mode {
399            DepthOfFieldMode::Gaussian => None,
400            DepthOfFieldMode::Bokeh => Some(BindGroupLayoutDescriptor::new(
401                "depth of field bind group layout (dual input)",
402                &BindGroupLayoutEntries::sequential(
403                    ShaderStages::FRAGMENT,
404                    (
405                        uniform_buffer::<ViewUniform>(true),
406                        if *msaa != Msaa::Off {
407                            texture_depth_2d_multisampled()
408                        } else {
409                            texture_depth_2d()
410                        },
411                        texture_2d(TextureSampleType::Float { filterable: true }),
412                        texture_2d(TextureSampleType::Float { filterable: true }),
413                    ),
414                ),
415            )),
416        };
417
418        commands
419            .entity(view)
420            .insert(ViewDepthOfFieldBindGroupLayouts {
421                single_input,
422                dual_input,
423            });
424    }
425}
426
427/// Configures depth textures so that the depth of field shader can read from
428/// them.
429///
430/// By default, the depth buffers that Bevy creates aren't able to be bound as
431/// textures. The depth of field shader, however, needs to read from them. So we
432/// need to set the appropriate flag to tell Bevy to make samplable depth
433/// buffers.
434pub fn configure_depth_of_field_view_targets(
435    mut view_targets: Query<&mut Camera3d, With<DepthOfField>>,
436) {
437    for mut camera_3d in view_targets.iter_mut() {
438        let mut depth_texture_usages = TextureUsages::from(camera_3d.depth_texture_usages);
439        depth_texture_usages |= TextureUsages::TEXTURE_BINDING;
440        camera_3d.depth_texture_usages = depth_texture_usages.into();
441    }
442}
443
444/// Creates depth of field bind group 1, which is shared among all instances of
445/// the depth of field shader.
446pub fn prepare_depth_of_field_global_bind_group(
447    global_bind_group_layout: Res<DepthOfFieldGlobalBindGroupLayout>,
448    mut dof_bind_group: ResMut<DepthOfFieldGlobalBindGroup>,
449    depth_of_field_uniforms: Res<ComponentUniforms<DepthOfFieldUniform>>,
450    render_device: Res<RenderDevice>,
451    pipeline_cache: Res<PipelineCache>,
452) {
453    let Some(depth_of_field_uniforms) = depth_of_field_uniforms.binding() else {
454        return;
455    };
456
457    **dof_bind_group = Some(render_device.create_bind_group(
458        Some("depth of field global bind group"),
459        &pipeline_cache.get_bind_group_layout(&global_bind_group_layout.layout),
460        &BindGroupEntries::sequential((
461            depth_of_field_uniforms,                         // `dof_params`
462            &global_bind_group_layout.color_texture_sampler, // `color_texture_sampler`
463        )),
464    ));
465}
466
467/// Creates the second render target texture that the first pass of the bokeh
468/// effect needs.
469pub fn prepare_auxiliary_depth_of_field_textures(
470    mut commands: Commands,
471    render_device: Res<RenderDevice>,
472    mut texture_cache: ResMut<TextureCache>,
473    mut view_targets: Query<(Entity, &ViewTarget, &DepthOfField)>,
474) {
475    for (entity, view_target, depth_of_field) in view_targets.iter_mut() {
476        // An auxiliary texture is only needed for bokeh.
477        if depth_of_field.mode != DepthOfFieldMode::Bokeh {
478            continue;
479        }
480
481        // The texture matches the main view target texture.
482        let texture_descriptor = TextureDescriptor {
483            label: Some("depth of field auxiliary texture"),
484            size: view_target.main_texture().size(),
485            mip_level_count: 1,
486            sample_count: view_target.main_texture().sample_count(),
487            dimension: TextureDimension::D2,
488            format: view_target.main_texture_format(),
489            usage: TextureUsages::RENDER_ATTACHMENT | TextureUsages::TEXTURE_BINDING,
490            view_formats: &[],
491        };
492
493        let texture = texture_cache.get(&render_device, texture_descriptor);
494
495        commands
496            .entity(entity)
497            .insert(AuxiliaryDepthOfFieldTexture(texture));
498    }
499}
500
501/// Specializes the depth of field pipelines specific to a view.
502pub fn prepare_depth_of_field_pipelines(
503    mut commands: Commands,
504    pipeline_cache: Res<PipelineCache>,
505    mut pipelines: ResMut<SpecializedRenderPipelines<DepthOfFieldPipeline>>,
506    global_bind_group_layout: Res<DepthOfFieldGlobalBindGroupLayout>,
507    view_targets: Query<
508        (
509            Entity,
510            &ExtractedView,
511            &DepthOfField,
512            &ViewDepthOfFieldBindGroupLayouts,
513            &Msaa,
514        ),
515        With<ExtractedCamera>,
516    >,
517    fullscreen_shader: Res<FullscreenShader>,
518    asset_server: Res<AssetServer>,
519) {
520    for (entity, view, depth_of_field, view_bind_group_layouts, msaa) in view_targets.iter() {
521        let dof_pipeline = DepthOfFieldPipeline {
522            view_bind_group_layouts: view_bind_group_layouts.clone(),
523            global_bind_group_layout: global_bind_group_layout.layout.clone(),
524            fullscreen_shader: fullscreen_shader.clone(),
525            fragment_shader: {
    let (path, asset_server) =
        {
            let path =
                {
                    {
                        let crate_name =
                            "bevy_post_process::dof".split(':').next().unwrap();
                        ::bevy_asset::io::embedded::_embedded_asset_path(crate_name,
                            "src".as_ref(), "src/dof/mod.rs".as_ref(),
                            "dof.wgsl".as_ref())
                    }
                };
            let path =
                ::bevy_asset::AssetPath::from_path_buf(path).with_source("embedded");
            let asset_server =
                ::bevy_asset::io::embedded::GetAssetServer::get_asset_server(asset_server.as_ref());
            (path, asset_server)
        };
    asset_server.load(path)
}load_embedded_asset!(asset_server.as_ref(), "dof.wgsl"),
526        };
527
528        // We'll need these two flags to create the `DepthOfFieldPipelineKey`s.
529        let (target_format, multisample) = (view.target_format, *msaa != Msaa::Off);
530
531        // Go ahead and specialize the pipelines.
532        match depth_of_field.mode {
533            DepthOfFieldMode::Gaussian => {
534                commands
535                    .entity(entity)
536                    .insert(DepthOfFieldPipelines::Gaussian {
537                        horizontal: pipelines.specialize(
538                            &pipeline_cache,
539                            &dof_pipeline,
540                            DepthOfFieldPipelineKey {
541                                target_format,
542                                multisample,
543                                pass: DofPass::GaussianHorizontal,
544                            },
545                        ),
546                        vertical: pipelines.specialize(
547                            &pipeline_cache,
548                            &dof_pipeline,
549                            DepthOfFieldPipelineKey {
550                                target_format,
551                                multisample,
552                                pass: DofPass::GaussianVertical,
553                            },
554                        ),
555                    });
556            }
557
558            DepthOfFieldMode::Bokeh => {
559                commands
560                    .entity(entity)
561                    .insert(DepthOfFieldPipelines::Bokeh {
562                        pass_0: pipelines.specialize(
563                            &pipeline_cache,
564                            &dof_pipeline,
565                            DepthOfFieldPipelineKey {
566                                target_format,
567                                multisample,
568                                pass: DofPass::BokehPass0,
569                            },
570                        ),
571                        pass_1: pipelines.specialize(
572                            &pipeline_cache,
573                            &dof_pipeline,
574                            DepthOfFieldPipelineKey {
575                                target_format,
576                                multisample,
577                                pass: DofPass::BokehPass1,
578                            },
579                        ),
580                    });
581            }
582        }
583    }
584}
585
586impl SpecializedRenderPipeline for DepthOfFieldPipeline {
587    type Key = DepthOfFieldPipelineKey;
588
589    fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
590        // Build up our pipeline layout.
591        let (mut layout, mut shader_defs) = (::alloc::vec::Vec::new()vec![], ::alloc::vec::Vec::new()vec![]);
592        let mut targets = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [Some(ColorTargetState {
                        format: key.target_format,
                        blend: None,
                        write_mask: ColorWrites::ALL,
                    })]))vec![Some(ColorTargetState {
593            format: key.target_format,
594            blend: None,
595            write_mask: ColorWrites::ALL,
596        })];
597
598        // Select bind group 0, the view-specific bind group.
599        match key.pass {
600            DofPass::GaussianHorizontal | DofPass::GaussianVertical => {
601                // Gaussian blurs take only a single input and output.
602                layout.push(self.view_bind_group_layouts.single_input.clone());
603            }
604            DofPass::BokehPass0 => {
605                // The first bokeh pass takes one input and produces two outputs.
606                layout.push(self.view_bind_group_layouts.single_input.clone());
607                targets.push(targets[0].clone());
608            }
609            DofPass::BokehPass1 => {
610                // The second bokeh pass takes the two outputs from the first
611                // bokeh pass and produces a single output.
612                let dual_input_bind_group_layout = self
613                    .view_bind_group_layouts
614                    .dual_input
615                    .as_ref()
616                    .expect("Dual-input depth of field bind group should have been created by now")
617                    .clone();
618                layout.push(dual_input_bind_group_layout);
619                shader_defs.push("DUAL_INPUT".into());
620            }
621        }
622
623        // Add bind group 1, the global bind group.
624        layout.push(self.global_bind_group_layout.clone());
625
626        if key.multisample {
627            shader_defs.push("MULTISAMPLED".into());
628        }
629
630        RenderPipelineDescriptor {
631            label: Some("depth of field pipeline".into()),
632            layout,
633            vertex: self.fullscreen_shader.to_vertex_state(),
634            fragment: Some(FragmentState {
635                shader: self.fragment_shader.clone(),
636                shader_defs,
637                entry_point: Some(match key.pass {
638                    DofPass::GaussianHorizontal => "gaussian_horizontal".into(),
639                    DofPass::GaussianVertical => "gaussian_vertical".into(),
640                    // Entry point names that end with number don't work on wasm. Perhaps `naga_oil` bug.
641                    // See <https://github.com/bevyengine/bevy/pull/23629>
642                    DofPass::BokehPass0 => "bokeh_pass_a".into(),
643                    DofPass::BokehPass1 => "bokeh_pass_b".into(),
644                }),
645                targets,
646            }),
647            ..default()
648        }
649    }
650}
651
652impl SyncComponent for DepthOfField {
653    type Target = (
654        DepthOfField,
655        DepthOfFieldUniform,
656        DepthOfFieldPipelines,
657        AuxiliaryDepthOfFieldTexture,
658        ViewDepthOfFieldBindGroupLayouts,
659    );
660}
661
662/// Extracts all [`DepthOfField`] components into the render world.
663fn extract_depth_of_field_settings(
664    mut commands: Commands,
665    mut query: Extract<Query<(RenderEntity, &DepthOfField, &Projection)>>,
666) {
667    if !DEPTH_PREPASS_TEXTURE_SUPPORTED {
668        {
    static SHOULD_FIRE: ::bevy_utils::OnceFlag =
        ::bevy_utils::OnceFlag::new();
    if SHOULD_FIRE.set() {
        {
            use ::tracing::__macro_support::Callsite as _;
            static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                {
                    static META: ::tracing::Metadata<'static> =
                        {
                            ::tracing_core::metadata::Metadata::new("event src/dof/mod.rs:668",
                                "bevy_post_process::dof", ::tracing::Level::INFO,
                                ::tracing_core::__macro_support::Option::Some("src/dof/mod.rs"),
                                ::tracing_core::__macro_support::Option::Some(668u32),
                                ::tracing_core::__macro_support::Option::Some("bevy_post_process::dof"),
                                ::tracing_core::field::FieldSet::new(&["message"],
                                    ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                ::tracing::metadata::Kind::EVENT)
                        };
                    ::tracing::callsite::DefaultCallsite::new(&META)
                };
            let enabled =
                ::tracing::Level::INFO <=
                            ::tracing::level_filters::STATIC_MAX_LEVEL &&
                        ::tracing::Level::INFO <=
                            ::tracing::level_filters::LevelFilter::current() &&
                    {
                        let interest = __CALLSITE.interest();
                        !interest.is_never() &&
                            ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                interest)
                    };
            if enabled {
                (|value_set: ::tracing::field::ValueSet|
                            {
                                let meta = __CALLSITE.metadata();
                                ::tracing::Event::dispatch(meta, &value_set);
                                ;
                            })({
                        #[allow(unused_imports)]
                        use ::tracing::field::{debug, display, Value};
                        __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("Disabling depth of field on this platform because depth textures aren\'t supported correctly")
                                                    as &dyn ::tracing::field::Value))])
                    });
            } else { ; }
        };
    }
};once!(info!(
669            "Disabling depth of field on this platform because depth textures aren't supported correctly"
670        ));
671        return;
672    }
673
674    for (entity, depth_of_field, projection) in query.iter_mut() {
675        let mut entity_commands = commands
676            .get_entity(entity)
677            .expect("Depth of field entity wasn't synced.");
678
679        // Depth of field is nonsensical without a perspective projection.
680        let Projection::Perspective(ref perspective_projection) = *projection else {
681            entity_commands.remove::<<DepthOfField as SyncComponent>::Target>();
682
683            continue;
684        };
685
686        let focal_length =
687            calculate_focal_length(depth_of_field.sensor_height, perspective_projection.fov);
688
689        // Convert `DepthOfField` to `DepthOfFieldUniform`.
690        entity_commands.insert((
691            *depth_of_field,
692            DepthOfFieldUniform {
693                focal_distance: depth_of_field.focal_distance,
694                focal_length,
695                coc_scale_factor: focal_length * focal_length
696                    / (depth_of_field.sensor_height * depth_of_field.aperture_f_stops),
697                max_circle_of_confusion_diameter: depth_of_field.max_circle_of_confusion_diameter,
698                max_depth: depth_of_field.max_depth,
699                pad_a: 0,
700                pad_b: 0,
701                pad_c: 0,
702            },
703        ));
704    }
705}
706
707/// Given the sensor height and the FOV, returns the focal length.
708///
709/// See <https://photo.stackexchange.com/a/97218>.
710pub fn calculate_focal_length(sensor_height: f32, fov: f32) -> f32 {
711    0.5 * sensor_height / ops::tan(0.5 * fov)
712}
713
714impl DepthOfFieldPipelines {
715    /// Populates the information that the `DepthOfFieldNode` needs for the two
716    /// depth of field render passes.
717    fn pipeline_render_info(&self) -> [DepthOfFieldPipelineRenderInfo; 2] {
718        match *self {
719            DepthOfFieldPipelines::Gaussian {
720                horizontal: horizontal_pipeline,
721                vertical: vertical_pipeline,
722            } => [
723                DepthOfFieldPipelineRenderInfo {
724                    pass_label: "depth of field pass (horizontal Gaussian)",
725                    view_bind_group_label: "depth of field view bind group (horizontal Gaussian)",
726                    pipeline: horizontal_pipeline,
727                    is_dual_input: false,
728                    is_dual_output: false,
729                },
730                DepthOfFieldPipelineRenderInfo {
731                    pass_label: "depth of field pass (vertical Gaussian)",
732                    view_bind_group_label: "depth of field view bind group (vertical Gaussian)",
733                    pipeline: vertical_pipeline,
734                    is_dual_input: false,
735                    is_dual_output: false,
736                },
737            ],
738
739            DepthOfFieldPipelines::Bokeh {
740                pass_0: pass_0_pipeline,
741                pass_1: pass_1_pipeline,
742            } => [
743                DepthOfFieldPipelineRenderInfo {
744                    pass_label: "depth of field pass (bokeh pass 0)",
745                    view_bind_group_label: "depth of field view bind group (bokeh pass 0)",
746                    pipeline: pass_0_pipeline,
747                    is_dual_input: false,
748                    is_dual_output: true,
749                },
750                DepthOfFieldPipelineRenderInfo {
751                    pass_label: "depth of field pass (bokeh pass 1)",
752                    view_bind_group_label: "depth of field view bind group (bokeh pass 1)",
753                    pipeline: pass_1_pipeline,
754                    is_dual_input: true,
755                    is_dual_output: false,
756                },
757            ],
758        }
759    }
760}
761
762pub(crate) fn depth_of_field(
763    view: ViewQuery<(
764        &ViewUniformOffset,
765        &ViewTarget,
766        &ViewDepthTexture,
767        &DepthOfFieldPipelines,
768        &ViewDepthOfFieldBindGroupLayouts,
769        &DynamicUniformIndex<DepthOfFieldUniform>,
770        Option<&AuxiliaryDepthOfFieldTexture>,
771    )>,
772    pipeline_cache: Res<PipelineCache>,
773    view_uniforms: Res<ViewUniforms>,
774    global_bind_group: Res<DepthOfFieldGlobalBindGroup>,
775    mut ctx: RenderContext,
776) {
777    let (
778        view_uniform_offset,
779        view_target,
780        view_depth_texture,
781        view_pipelines,
782        view_bind_group_layouts,
783        depth_of_field_uniform_index,
784        auxiliary_dof_texture,
785    ) = view.into_inner();
786
787    // We can be in either Gaussian blur or bokeh mode here. Both modes are
788    // similar, consisting of two passes each.
789    for pipeline_render_info in view_pipelines.pipeline_render_info().iter() {
790        let (Some(render_pipeline), Some(view_uniforms_binding), Some(global_bind_group)) = (
791            pipeline_cache.get_render_pipeline(pipeline_render_info.pipeline),
792            view_uniforms.uniforms.binding(),
793            &**global_bind_group,
794        ) else {
795            return;
796        };
797
798        // We use most of the postprocess infrastructure here. However,
799        // because the bokeh pass has an additional render target, we have
800        // to manage a secondary *auxiliary* texture alongside the textures
801        // managed by the postprocessing logic.
802        let postprocess = view_target.post_process_write();
803
804        let view_bind_group = if pipeline_render_info.is_dual_input {
805            let (Some(auxiliary_dof_texture), Some(dual_input_bind_group_layout)) = (
806                auxiliary_dof_texture,
807                view_bind_group_layouts.dual_input.as_ref(),
808            ) else {
809                {
    static SHOULD_FIRE: ::bevy_utils::OnceFlag =
        ::bevy_utils::OnceFlag::new();
    if SHOULD_FIRE.set() {
        {
            use ::tracing::__macro_support::Callsite as _;
            static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                {
                    static META: ::tracing::Metadata<'static> =
                        {
                            ::tracing_core::metadata::Metadata::new("event src/dof/mod.rs:809",
                                "bevy_post_process::dof", ::tracing::Level::WARN,
                                ::tracing_core::__macro_support::Option::Some("src/dof/mod.rs"),
                                ::tracing_core::__macro_support::Option::Some(809u32),
                                ::tracing_core::__macro_support::Option::Some("bevy_post_process::dof"),
                                ::tracing_core::field::FieldSet::new(&["message"],
                                    ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                ::tracing::metadata::Kind::EVENT)
                        };
                    ::tracing::callsite::DefaultCallsite::new(&META)
                };
            let enabled =
                ::tracing::Level::WARN <=
                            ::tracing::level_filters::STATIC_MAX_LEVEL &&
                        ::tracing::Level::WARN <=
                            ::tracing::level_filters::LevelFilter::current() &&
                    {
                        let interest = __CALLSITE.interest();
                        !interest.is_never() &&
                            ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                interest)
                    };
            if enabled {
                (|value_set: ::tracing::field::ValueSet|
                            {
                                let meta = __CALLSITE.metadata();
                                ::tracing::Event::dispatch(meta, &value_set);
                                ;
                            })({
                        #[allow(unused_imports)]
                        use ::tracing::field::{debug, display, Value};
                        __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("Should have created the auxiliary depth of field texture by now")
                                                    as &dyn ::tracing::field::Value))])
                    });
            } else { ; }
        };
    }
};once!(warn!(
810                    "Should have created the auxiliary depth of field texture by now"
811                ));
812                continue;
813            };
814            ctx.render_device().create_bind_group(
815                Some(pipeline_render_info.view_bind_group_label),
816                &pipeline_cache.get_bind_group_layout(dual_input_bind_group_layout),
817                &BindGroupEntries::sequential((
818                    view_uniforms_binding,
819                    view_depth_texture.view(),
820                    postprocess.source,
821                    &auxiliary_dof_texture.default_view,
822                )),
823            )
824        } else {
825            ctx.render_device().create_bind_group(
826                Some(pipeline_render_info.view_bind_group_label),
827                &pipeline_cache.get_bind_group_layout(&view_bind_group_layouts.single_input),
828                &BindGroupEntries::sequential((
829                    view_uniforms_binding,
830                    view_depth_texture.view(),
831                    postprocess.source,
832                )),
833            )
834        };
835
836        // Push the first input attachment.
837        let mut color_attachments: SmallVec<[_; 2]> = SmallVec::new();
838        color_attachments.push(Some(RenderPassColorAttachment {
839            view: postprocess.destination,
840            depth_slice: None,
841            resolve_target: None,
842            ops: Operations {
843                load: LoadOp::Clear(default()),
844                store: StoreOp::Store,
845            },
846        }));
847
848        // The first pass of the bokeh shader has two color outputs, not
849        // one. Handle this case by attaching the auxiliary texture, which
850        // should have been created by now in
851        // `prepare_auxiliary_depth_of_field_textures``.
852        if pipeline_render_info.is_dual_output {
853            let Some(auxiliary_dof_texture) = auxiliary_dof_texture else {
854                {
    static SHOULD_FIRE: ::bevy_utils::OnceFlag =
        ::bevy_utils::OnceFlag::new();
    if SHOULD_FIRE.set() {
        {
            use ::tracing::__macro_support::Callsite as _;
            static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                {
                    static META: ::tracing::Metadata<'static> =
                        {
                            ::tracing_core::metadata::Metadata::new("event src/dof/mod.rs:854",
                                "bevy_post_process::dof", ::tracing::Level::WARN,
                                ::tracing_core::__macro_support::Option::Some("src/dof/mod.rs"),
                                ::tracing_core::__macro_support::Option::Some(854u32),
                                ::tracing_core::__macro_support::Option::Some("bevy_post_process::dof"),
                                ::tracing_core::field::FieldSet::new(&["message"],
                                    ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                ::tracing::metadata::Kind::EVENT)
                        };
                    ::tracing::callsite::DefaultCallsite::new(&META)
                };
            let enabled =
                ::tracing::Level::WARN <=
                            ::tracing::level_filters::STATIC_MAX_LEVEL &&
                        ::tracing::Level::WARN <=
                            ::tracing::level_filters::LevelFilter::current() &&
                    {
                        let interest = __CALLSITE.interest();
                        !interest.is_never() &&
                            ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                interest)
                    };
            if enabled {
                (|value_set: ::tracing::field::ValueSet|
                            {
                                let meta = __CALLSITE.metadata();
                                ::tracing::Event::dispatch(meta, &value_set);
                                ;
                            })({
                        #[allow(unused_imports)]
                        use ::tracing::field::{debug, display, Value};
                        __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("Should have created the auxiliary depth of field texture by now")
                                                    as &dyn ::tracing::field::Value))])
                    });
            } else { ; }
        };
    }
};once!(warn!(
855                    "Should have created the auxiliary depth of field texture by now"
856                ));
857                continue;
858            };
859            color_attachments.push(Some(RenderPassColorAttachment {
860                view: &auxiliary_dof_texture.default_view,
861                depth_slice: None,
862                resolve_target: None,
863                ops: Operations {
864                    load: LoadOp::Clear(default()),
865                    store: StoreOp::Store,
866                },
867            }));
868        }
869
870        let render_pass_descriptor = RenderPassDescriptor {
871            label: Some(pipeline_render_info.pass_label),
872            color_attachments: &color_attachments,
873            ..default()
874        };
875
876        let mut render_pass = ctx
877            .command_encoder()
878            .begin_render_pass(&render_pass_descriptor);
879
880        render_pass.set_pipeline(render_pipeline);
881        // Set the per-view bind group.
882        render_pass.set_bind_group(0, &view_bind_group, &[view_uniform_offset.offset]);
883        // Set the global bind group shared among all invocations of the shader.
884        render_pass.set_bind_group(
885            1,
886            global_bind_group,
887            &[depth_of_field_uniform_index.index()],
888        );
889        // Render the full-screen pass.
890        render_pass.draw(0..3, 0..1);
891    }
892}