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