Skip to main content

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 [`bevy_camera::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 background_motion_vectors;
29pub mod node;
30
31pub use background_motion_vectors::{
32    BackgroundMotionVectorsBindGroup, BackgroundMotionVectorsPipelineId,
33    BackgroundMotionVectorsPlugin, NoBackgroundMotionVectors,
34};
35
36use core::ops::Range;
37
38use crate::deferred::{DEFERRED_LIGHTING_PASS_ID_FORMAT, DEFERRED_PREPASS_FORMAT};
39use bevy_asset::UntypedAssetId;
40use bevy_ecs::prelude::*;
41use bevy_math::Mat4;
42use bevy_reflect::{std_traits::ReflectDefault, Reflect};
43use bevy_render::mesh::allocator::MeshSlabs;
44use bevy_render::render_phase::PhaseItemBatchSetKey;
45use bevy_render::sync_world::MainEntity;
46use bevy_render::{
47    render_phase::{
48        BinnedPhaseItem, CachedRenderPipelinePhaseItem, DrawFunctionId, PhaseItem,
49        PhaseItemExtraIndex,
50    },
51    render_resource::{
52        CachedRenderPipelineId, ColorTargetState, ColorWrites, DynamicUniformBuffer, Extent3d,
53        ShaderType, TextureFormat, TextureView,
54    },
55    texture::ColorAttachment,
56};
57
58pub const NORMAL_PREPASS_FORMAT: TextureFormat = TextureFormat::Rgb10a2Unorm;
59pub const MOTION_VECTOR_PREPASS_FORMAT: TextureFormat = TextureFormat::Rg16Float;
60
61/// If added to a [`bevy_camera::Camera3d`] then depth values will be copied to a separate texture available to the main pass.
62#[derive(Component, Default, Reflect, Clone)]
63#[reflect(Component, Default, Clone)]
64pub struct DepthPrepass;
65
66/// If added to a [`bevy_camera::Camera3d`] then vertex world normals will be copied to a separate texture available to the main pass.
67/// Normals will have normal map textures already applied.
68#[derive(Component, Default, Reflect, Clone)]
69#[reflect(Component, Default, Clone)]
70pub struct NormalPrepass;
71
72/// If added to a [`bevy_camera::Camera3d`] then screen space motion vectors will be copied to a separate texture available to the main pass.
73///
74/// Motion vectors are stored in the range -1,1, with +x right and +y down.
75/// A value of (1.0,1.0) indicates a pixel moved from the top left corner to the bottom right corner of the screen.
76#[derive(Component, Default, Reflect, Clone)]
77#[reflect(Component, Default, Clone)]
78pub struct MotionVectorPrepass;
79
80/// If added to a [`bevy_camera::Camera3d`] then deferred materials will be rendered to the deferred gbuffer texture and will be available to subsequent passes.
81/// Note the default deferred lighting plugin also requires `DepthPrepass` to work correctly.
82#[derive(Component, Default, Reflect)]
83#[reflect(Component, Default)]
84pub struct DeferredPrepass;
85
86/// Allows querying the previous frame's [`DepthPrepass`].
87#[derive(Component, Default, Reflect, Clone)]
88#[reflect(Component, Default, Clone)]
89#[require(DepthPrepass)]
90pub struct DepthPrepassDoubleBuffer;
91
92/// Allows querying the previous frame's [`DeferredPrepass`].
93#[derive(Component, Default, Reflect, Clone)]
94#[reflect(Component, Default, Clone)]
95#[require(DeferredPrepass)]
96pub struct DeferredPrepassDoubleBuffer;
97
98/// View matrices from the previous frame.
99///
100/// Useful for temporal rendering techniques that need access to last frame's camera data.
101#[derive(Component, ShaderType, Clone)]
102pub struct PreviousViewData {
103    pub view_from_world: Mat4,
104    pub clip_from_world: Mat4,
105    pub clip_from_view: Mat4,
106    pub world_from_clip: Mat4,
107    pub view_from_clip: Mat4,
108}
109
110#[derive(Resource, Default)]
111pub struct PreviousViewUniforms {
112    pub uniforms: DynamicUniformBuffer<PreviousViewData>,
113}
114
115#[derive(Component)]
116pub struct PreviousViewUniformOffset {
117    pub offset: u32,
118}
119
120/// Textures that are written to by the prepass.
121///
122/// This component will only be present if any of the relevant prepass components are also present.
123#[derive(Component)]
124pub struct ViewPrepassTextures {
125    /// The depth texture generated by the prepass.
126    /// Exists only if [`DepthPrepass`] is added to the [`ViewTarget`](bevy_render::view::ViewTarget)
127    pub depth: Option<ColorAttachment>,
128    /// The normals texture generated by the prepass.
129    /// Exists only if [`NormalPrepass`] is added to the [`ViewTarget`](bevy_render::view::ViewTarget)
130    pub normal: Option<ColorAttachment>,
131    /// The motion vectors texture generated by the prepass.
132    /// Exists only if [`MotionVectorPrepass`] is added to the `ViewTarget`
133    pub motion_vectors: Option<ColorAttachment>,
134    /// The deferred gbuffer generated by the deferred pass.
135    /// Exists only if [`DeferredPrepass`] is added to the `ViewTarget`
136    pub deferred: Option<ColorAttachment>,
137    /// A texture that specifies the deferred lighting pass id for a material.
138    /// Exists only if [`DeferredPrepass`] is added to the `ViewTarget`
139    pub deferred_lighting_pass_id: Option<ColorAttachment>,
140    /// The size of the textures.
141    pub size: Extent3d,
142}
143
144impl ViewPrepassTextures {
145    pub fn depth_view(&self) -> Option<&TextureView> {
146        self.depth.as_ref().map(|t| &t.texture.default_view)
147    }
148
149    pub fn previous_depth_view(&self) -> Option<&TextureView> {
150        self.depth
151            .as_ref()
152            .and_then(|t| t.previous_frame_texture.as_ref().map(|t| &t.default_view))
153    }
154
155    pub fn normal_view(&self) -> Option<&TextureView> {
156        self.normal.as_ref().map(|t| &t.texture.default_view)
157    }
158
159    pub fn motion_vectors_view(&self) -> Option<&TextureView> {
160        self.motion_vectors
161            .as_ref()
162            .map(|t| &t.texture.default_view)
163    }
164
165    pub fn deferred_view(&self) -> Option<&TextureView> {
166        self.deferred.as_ref().map(|t| &t.texture.default_view)
167    }
168
169    pub fn previous_deferred_view(&self) -> Option<&TextureView> {
170        self.deferred
171            .as_ref()
172            .and_then(|t| t.previous_frame_texture.as_ref().map(|t| &t.default_view))
173    }
174}
175
176/// Opaque phase of the 3D prepass.
177///
178/// Sorted by pipeline, then by mesh to improve batching.
179///
180/// Used to render all 3D meshes with materials that have no transparency.
181pub struct Opaque3dPrepass {
182    /// Determines which objects can be placed into a *batch set*.
183    ///
184    /// Objects in a single batch set can potentially be multi-drawn together,
185    /// if it's enabled and the current platform supports it.
186    pub batch_set_key: OpaqueNoLightmap3dBatchSetKey,
187    /// Information that separates items into bins.
188    pub bin_key: OpaqueNoLightmap3dBinKey,
189
190    /// An entity from which Bevy fetches data common to all instances in this
191    /// batch, such as the mesh.
192    pub representative_entity: (Entity, MainEntity),
193    pub batch_range: Range<u32>,
194    pub extra_index: PhaseItemExtraIndex,
195}
196
197/// Information that must be identical in order to place opaque meshes in the
198/// same *batch set* in the prepass and deferred pass.
199///
200/// A batch set is a set of batches that can be multi-drawn together, if
201/// multi-draw is in use.
202#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
203pub struct OpaqueNoLightmap3dBatchSetKey {
204    /// The ID of the GPU pipeline.
205    pub pipeline: CachedRenderPipelineId,
206
207    /// The function used to draw the mesh.
208    pub draw_function: DrawFunctionId,
209
210    /// The ID of a bind group specific to the material.
211    ///
212    /// In the case of PBR, this is the `MaterialBindGroupIndex`.
213    pub material_bind_group_index: Option<u32>,
214
215    /// The IDs of the slabs of GPU memory in the mesh allocator that contain
216    /// the mesh data.
217    ///
218    /// For non-mesh items, you can fill the [`MeshSlabs::vertex_slab_id`] with
219    /// 0 if your items can be multi-drawn, or with a unique value if they
220    /// can't.
221    pub slabs: MeshSlabs,
222}
223
224impl PhaseItemBatchSetKey for OpaqueNoLightmap3dBatchSetKey {
225    fn indexed(&self) -> bool {
226        self.slabs.index_slab_id.is_some()
227    }
228}
229
230// TODO: Try interning these.
231/// The data used to bin each opaque 3D object in the prepass and deferred pass.
232#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
233pub struct OpaqueNoLightmap3dBinKey {
234    /// The ID of the asset.
235    pub asset_id: UntypedAssetId,
236}
237
238impl PhaseItem for Opaque3dPrepass {
239    #[inline]
240    fn entity(&self) -> Entity {
241        self.representative_entity.0
242    }
243
244    fn main_entity(&self) -> MainEntity {
245        self.representative_entity.1
246    }
247
248    #[inline]
249    fn draw_function(&self) -> DrawFunctionId {
250        self.batch_set_key.draw_function
251    }
252
253    #[inline]
254    fn batch_range(&self) -> &Range<u32> {
255        &self.batch_range
256    }
257
258    #[inline]
259    fn batch_range_mut(&mut self) -> &mut Range<u32> {
260        &mut self.batch_range
261    }
262
263    #[inline]
264    fn extra_index(&self) -> PhaseItemExtraIndex {
265        self.extra_index.clone()
266    }
267
268    #[inline]
269    fn batch_range_and_extra_index_mut(&mut self) -> (&mut Range<u32>, &mut PhaseItemExtraIndex) {
270        (&mut self.batch_range, &mut self.extra_index)
271    }
272}
273
274impl BinnedPhaseItem for Opaque3dPrepass {
275    type BatchSetKey = OpaqueNoLightmap3dBatchSetKey;
276    type BinKey = OpaqueNoLightmap3dBinKey;
277
278    #[inline]
279    fn new(
280        batch_set_key: Self::BatchSetKey,
281        bin_key: Self::BinKey,
282        representative_entity: (Entity, MainEntity),
283        batch_range: Range<u32>,
284        extra_index: PhaseItemExtraIndex,
285    ) -> Self {
286        Opaque3dPrepass {
287            batch_set_key,
288            bin_key,
289            representative_entity,
290            batch_range,
291            extra_index,
292        }
293    }
294}
295
296impl CachedRenderPipelinePhaseItem for Opaque3dPrepass {
297    #[inline]
298    fn cached_pipeline(&self) -> CachedRenderPipelineId {
299        self.batch_set_key.pipeline
300    }
301}
302
303/// Alpha mask phase of the 3D prepass.
304///
305/// Sorted by pipeline, then by mesh to improve batching.
306///
307/// Used to render all meshes with a material with an alpha mask.
308pub struct AlphaMask3dPrepass {
309    /// Determines which objects can be placed into a *batch set*.
310    ///
311    /// Objects in a single batch set can potentially be multi-drawn together,
312    /// if it's enabled and the current platform supports it.
313    pub batch_set_key: OpaqueNoLightmap3dBatchSetKey,
314    /// Information that separates items into bins.
315    pub bin_key: OpaqueNoLightmap3dBinKey,
316    pub representative_entity: (Entity, MainEntity),
317    pub batch_range: Range<u32>,
318    pub extra_index: PhaseItemExtraIndex,
319}
320
321impl PhaseItem for AlphaMask3dPrepass {
322    #[inline]
323    fn entity(&self) -> Entity {
324        self.representative_entity.0
325    }
326
327    fn main_entity(&self) -> MainEntity {
328        self.representative_entity.1
329    }
330
331    #[inline]
332    fn draw_function(&self) -> DrawFunctionId {
333        self.batch_set_key.draw_function
334    }
335
336    #[inline]
337    fn batch_range(&self) -> &Range<u32> {
338        &self.batch_range
339    }
340
341    #[inline]
342    fn batch_range_mut(&mut self) -> &mut Range<u32> {
343        &mut self.batch_range
344    }
345
346    #[inline]
347    fn extra_index(&self) -> PhaseItemExtraIndex {
348        self.extra_index.clone()
349    }
350
351    #[inline]
352    fn batch_range_and_extra_index_mut(&mut self) -> (&mut Range<u32>, &mut PhaseItemExtraIndex) {
353        (&mut self.batch_range, &mut self.extra_index)
354    }
355}
356
357impl BinnedPhaseItem for AlphaMask3dPrepass {
358    type BatchSetKey = OpaqueNoLightmap3dBatchSetKey;
359    type BinKey = OpaqueNoLightmap3dBinKey;
360
361    #[inline]
362    fn new(
363        batch_set_key: Self::BatchSetKey,
364        bin_key: Self::BinKey,
365        representative_entity: (Entity, MainEntity),
366        batch_range: Range<u32>,
367        extra_index: PhaseItemExtraIndex,
368    ) -> Self {
369        Self {
370            batch_set_key,
371            bin_key,
372            representative_entity,
373            batch_range,
374            extra_index,
375        }
376    }
377}
378
379impl CachedRenderPipelinePhaseItem for AlphaMask3dPrepass {
380    #[inline]
381    fn cached_pipeline(&self) -> CachedRenderPipelineId {
382        self.batch_set_key.pipeline
383    }
384}
385
386pub fn prepass_target_descriptors(
387    normal_prepass: bool,
388    motion_vector_prepass: bool,
389    deferred_prepass: bool,
390) -> Vec<Option<ColorTargetState>> {
391    vec![
392        normal_prepass.then_some(ColorTargetState {
393            format: NORMAL_PREPASS_FORMAT,
394            blend: None,
395            write_mask: ColorWrites::ALL,
396        }),
397        motion_vector_prepass.then_some(ColorTargetState {
398            format: MOTION_VECTOR_PREPASS_FORMAT,
399            blend: None,
400            write_mask: ColorWrites::ALL,
401        }),
402        deferred_prepass.then_some(ColorTargetState {
403            format: DEFERRED_PREPASS_FORMAT,
404            blend: None,
405            write_mask: ColorWrites::ALL,
406        }),
407        deferred_prepass.then_some(ColorTargetState {
408            format: DEFERRED_LIGHTING_PASS_ID_FORMAT,
409            blend: None,
410            write_mask: ColorWrites::ALL,
411        }),
412    ]
413}