bevy_core_pipeline/prepass/
mod.rs

1//! Run a prepass before the main pass to generate depth, normals, and/or motion vectors textures, sometimes called a thin g-buffer.
2//! These textures are useful for various screen-space effects and reducing overdraw in the main pass.
3//!
4//! The prepass only runs for opaque meshes or meshes with an alpha mask. Transparent meshes are ignored.
5//!
6//! To enable the prepass, you need to add a prepass component to a [`crate::prelude::Camera3d`].
7//!
8//! [`DepthPrepass`]
9//! [`NormalPrepass`]
10//! [`MotionVectorPrepass`]
11//!
12//! The textures are automatically added to the default mesh view bindings. You can also get the raw textures
13//! by querying the [`ViewPrepassTextures`] component on any camera with a prepass component.
14//!
15//! The depth prepass will always run and generate the depth buffer as a side effect, but it won't copy it
16//! to a separate texture unless the [`DepthPrepass`] is activated. This means that if any prepass component is present
17//! it will always create a depth buffer that will be used by the main pass.
18//!
19//! When using the default mesh view bindings you should be able to use `prepass_depth()`,
20//! `prepass_normal()`, and `prepass_motion_vector()` to load the related textures.
21//! These functions are defined in `bevy_pbr::prepass_utils`. See the `shader_prepass` example that shows how to use them.
22//!
23//! The prepass runs for each `Material`. You can control if the prepass should run per-material by setting the `prepass_enabled`
24//! flag on the `MaterialPlugin`.
25//!
26//! Currently only works for 3D.
27
28pub mod node;
29
30use core::ops::Range;
31
32use crate::deferred::{DEFERRED_LIGHTING_PASS_ID_FORMAT, DEFERRED_PREPASS_FORMAT};
33use bevy_asset::UntypedAssetId;
34use bevy_ecs::prelude::*;
35use bevy_math::Mat4;
36use bevy_reflect::{std_traits::ReflectDefault, Reflect};
37use bevy_render::sync_world::MainEntity;
38use bevy_render::{
39    render_phase::{
40        BinnedPhaseItem, CachedRenderPipelinePhaseItem, DrawFunctionId, PhaseItem,
41        PhaseItemExtraIndex,
42    },
43    render_resource::{
44        BindGroupId, CachedRenderPipelineId, ColorTargetState, ColorWrites, DynamicUniformBuffer,
45        Extent3d, ShaderType, TextureFormat, TextureView,
46    },
47    texture::ColorAttachment,
48};
49
50pub const NORMAL_PREPASS_FORMAT: TextureFormat = TextureFormat::Rgb10a2Unorm;
51pub const MOTION_VECTOR_PREPASS_FORMAT: TextureFormat = TextureFormat::Rg16Float;
52
53/// If added to a [`crate::prelude::Camera3d`] then depth values will be copied to a separate texture available to the main pass.
54#[derive(Component, Default, Reflect, Clone)]
55#[reflect(Component, Default)]
56pub struct DepthPrepass;
57
58/// If added to a [`crate::prelude::Camera3d`] then vertex world normals will be copied to a separate texture available to the main pass.
59/// Normals will have normal map textures already applied.
60#[derive(Component, Default, Reflect, Clone)]
61#[reflect(Component, Default)]
62pub struct NormalPrepass;
63
64/// If added to a [`crate::prelude::Camera3d`] then screen space motion vectors will be copied to a separate texture available to the main pass.
65#[derive(Component, Default, Reflect, Clone)]
66#[reflect(Component, Default)]
67pub struct MotionVectorPrepass;
68
69/// If added to a [`crate::prelude::Camera3d`] then deferred materials will be rendered to the deferred gbuffer texture and will be available to subsequent passes.
70/// Note the default deferred lighting plugin also requires `DepthPrepass` to work correctly.
71#[derive(Component, Default, Reflect)]
72#[reflect(Component, Default)]
73pub struct DeferredPrepass;
74
75#[derive(Component, ShaderType, Clone)]
76pub struct PreviousViewData {
77    pub view_from_world: Mat4,
78    pub clip_from_world: Mat4,
79}
80
81#[derive(Resource, Default)]
82pub struct PreviousViewUniforms {
83    pub uniforms: DynamicUniformBuffer<PreviousViewData>,
84}
85
86#[derive(Component)]
87pub struct PreviousViewUniformOffset {
88    pub offset: u32,
89}
90
91/// Textures that are written to by the prepass.
92///
93/// This component will only be present if any of the relevant prepass components are also present.
94#[derive(Component)]
95pub struct ViewPrepassTextures {
96    /// The depth texture generated by the prepass.
97    /// Exists only if [`DepthPrepass`] is added to the [`ViewTarget`](bevy_render::view::ViewTarget)
98    pub depth: Option<ColorAttachment>,
99    /// The normals texture generated by the prepass.
100    /// Exists only if [`NormalPrepass`] is added to the [`ViewTarget`](bevy_render::view::ViewTarget)
101    pub normal: Option<ColorAttachment>,
102    /// The motion vectors texture generated by the prepass.
103    /// Exists only if [`MotionVectorPrepass`] is added to the `ViewTarget`
104    pub motion_vectors: Option<ColorAttachment>,
105    /// The deferred gbuffer generated by the deferred pass.
106    /// Exists only if [`DeferredPrepass`] is added to the `ViewTarget`
107    pub deferred: Option<ColorAttachment>,
108    /// A texture that specifies the deferred lighting pass id for a material.
109    /// Exists only if [`DeferredPrepass`] is added to the `ViewTarget`
110    pub deferred_lighting_pass_id: Option<ColorAttachment>,
111    /// The size of the textures.
112    pub size: Extent3d,
113}
114
115impl ViewPrepassTextures {
116    pub fn depth_view(&self) -> Option<&TextureView> {
117        self.depth.as_ref().map(|t| &t.texture.default_view)
118    }
119
120    pub fn normal_view(&self) -> Option<&TextureView> {
121        self.normal.as_ref().map(|t| &t.texture.default_view)
122    }
123
124    pub fn motion_vectors_view(&self) -> Option<&TextureView> {
125        self.motion_vectors
126            .as_ref()
127            .map(|t| &t.texture.default_view)
128    }
129
130    pub fn deferred_view(&self) -> Option<&TextureView> {
131        self.deferred.as_ref().map(|t| &t.texture.default_view)
132    }
133}
134
135/// Opaque phase of the 3D prepass.
136///
137/// Sorted by pipeline, then by mesh to improve batching.
138///
139/// Used to render all 3D meshes with materials that have no transparency.
140pub struct Opaque3dPrepass {
141    /// Information that separates items into bins.
142    pub key: OpaqueNoLightmap3dBinKey,
143
144    /// An entity from which Bevy fetches data common to all instances in this
145    /// batch, such as the mesh.
146    pub representative_entity: (Entity, MainEntity),
147    pub batch_range: Range<u32>,
148    pub extra_index: PhaseItemExtraIndex,
149}
150
151// TODO: Try interning these.
152/// The data used to bin each opaque 3D object in the prepass and deferred pass.
153#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
154pub struct OpaqueNoLightmap3dBinKey {
155    /// The ID of the GPU pipeline.
156    pub pipeline: CachedRenderPipelineId,
157
158    /// The function used to draw the mesh.
159    pub draw_function: DrawFunctionId,
160
161    /// The ID of the asset.
162    pub asset_id: UntypedAssetId,
163
164    /// The ID of a bind group specific to the material.
165    ///
166    /// In the case of PBR, this is the `MaterialBindGroupId`.
167    pub material_bind_group_id: Option<BindGroupId>,
168}
169
170impl PhaseItem for Opaque3dPrepass {
171    #[inline]
172    fn entity(&self) -> Entity {
173        self.representative_entity.0
174    }
175
176    fn main_entity(&self) -> MainEntity {
177        self.representative_entity.1
178    }
179
180    #[inline]
181    fn draw_function(&self) -> DrawFunctionId {
182        self.key.draw_function
183    }
184
185    #[inline]
186    fn batch_range(&self) -> &Range<u32> {
187        &self.batch_range
188    }
189
190    #[inline]
191    fn batch_range_mut(&mut self) -> &mut Range<u32> {
192        &mut self.batch_range
193    }
194
195    #[inline]
196    fn extra_index(&self) -> PhaseItemExtraIndex {
197        self.extra_index
198    }
199
200    #[inline]
201    fn batch_range_and_extra_index_mut(&mut self) -> (&mut Range<u32>, &mut PhaseItemExtraIndex) {
202        (&mut self.batch_range, &mut self.extra_index)
203    }
204}
205
206impl BinnedPhaseItem for Opaque3dPrepass {
207    type BinKey = OpaqueNoLightmap3dBinKey;
208
209    #[inline]
210    fn new(
211        key: Self::BinKey,
212        representative_entity: (Entity, MainEntity),
213        batch_range: Range<u32>,
214        extra_index: PhaseItemExtraIndex,
215    ) -> Self {
216        Opaque3dPrepass {
217            key,
218            representative_entity,
219            batch_range,
220            extra_index,
221        }
222    }
223}
224
225impl CachedRenderPipelinePhaseItem for Opaque3dPrepass {
226    #[inline]
227    fn cached_pipeline(&self) -> CachedRenderPipelineId {
228        self.key.pipeline
229    }
230}
231
232/// Alpha mask phase of the 3D prepass.
233///
234/// Sorted by pipeline, then by mesh to improve batching.
235///
236/// Used to render all meshes with a material with an alpha mask.
237pub struct AlphaMask3dPrepass {
238    pub key: OpaqueNoLightmap3dBinKey,
239    pub representative_entity: (Entity, MainEntity),
240    pub batch_range: Range<u32>,
241    pub extra_index: PhaseItemExtraIndex,
242}
243
244impl PhaseItem for AlphaMask3dPrepass {
245    #[inline]
246    fn entity(&self) -> Entity {
247        self.representative_entity.0
248    }
249
250    fn main_entity(&self) -> MainEntity {
251        self.representative_entity.1
252    }
253
254    #[inline]
255    fn draw_function(&self) -> DrawFunctionId {
256        self.key.draw_function
257    }
258
259    #[inline]
260    fn batch_range(&self) -> &Range<u32> {
261        &self.batch_range
262    }
263
264    #[inline]
265    fn batch_range_mut(&mut self) -> &mut Range<u32> {
266        &mut self.batch_range
267    }
268
269    #[inline]
270    fn extra_index(&self) -> PhaseItemExtraIndex {
271        self.extra_index
272    }
273
274    #[inline]
275    fn batch_range_and_extra_index_mut(&mut self) -> (&mut Range<u32>, &mut PhaseItemExtraIndex) {
276        (&mut self.batch_range, &mut self.extra_index)
277    }
278}
279
280impl BinnedPhaseItem for AlphaMask3dPrepass {
281    type BinKey = OpaqueNoLightmap3dBinKey;
282
283    #[inline]
284    fn new(
285        key: Self::BinKey,
286        representative_entity: (Entity, MainEntity),
287        batch_range: Range<u32>,
288        extra_index: PhaseItemExtraIndex,
289    ) -> Self {
290        Self {
291            key,
292            representative_entity,
293            batch_range,
294            extra_index,
295        }
296    }
297}
298
299impl CachedRenderPipelinePhaseItem for AlphaMask3dPrepass {
300    #[inline]
301    fn cached_pipeline(&self) -> CachedRenderPipelineId {
302        self.key.pipeline
303    }
304}
305
306pub fn prepass_target_descriptors(
307    normal_prepass: bool,
308    motion_vector_prepass: bool,
309    deferred_prepass: bool,
310) -> Vec<Option<ColorTargetState>> {
311    vec![
312        normal_prepass.then_some(ColorTargetState {
313            format: NORMAL_PREPASS_FORMAT,
314            blend: None,
315            write_mask: ColorWrites::ALL,
316        }),
317        motion_vector_prepass.then_some(ColorTargetState {
318            format: MOTION_VECTOR_PREPASS_FORMAT,
319            blend: None,
320            write_mask: ColorWrites::ALL,
321        }),
322        deferred_prepass.then_some(ColorTargetState {
323            format: DEFERRED_PREPASS_FORMAT,
324            blend: None,
325            write_mask: ColorWrites::ALL,
326        }),
327        deferred_prepass.then_some(ColorTargetState {
328            format: DEFERRED_LIGHTING_PASS_ID_FORMAT,
329            blend: None,
330            write_mask: ColorWrites::ALL,
331        }),
332    ]
333}