wde_pbr/deferred/
mod.rs

1//! Deferred PBR module.
2//!
3//! This module connects PBR data (materials, models, lights) to the engine deferred
4//! render graph.
5//!
6//! # PBR Overview
7//! The PBR rendering stack is composed of two passes.
8//!
9//! ## GBuffer pass (see [`RenderPassDeferredGBuffer`](crate::passes::RenderPassDeferredGBuffer))
10//! This pass is composed of a few steps that run every frame:
11//! - It extracts every entity with a `Transform` and [`PbrModel`](crate::prelude::PbrModel) (which have a vector of [`Mesh`](wde_renderer::prelude::Mesh) and [`PbrMaterial`](crate::pbr_material::PbrMaterial) elements) from the main world to the render world, and stores them in the `PbrModelRegistry` resource. Each model element is assigned a unique UUID, as well as a transform ID that corresponds to its entry in the GPU [SsboTransform](crate::SsboTransform) buffer.
12//! - When a transform or a model is added or changed in the main world, the corresponding transform is marked as dirty, and the [SsboTransform](crate::SsboTransform) buffer is updated with the new transform data at the next frame.
13//! - Then, for each frame, a `Batches` resource is created from the extracted entities, sorted by their material handle to minimize render pipeline changes. Each `Batch` points to the corresponding mesh and material handles, as well as an instance index. It then uses another buffer to store pointers from the entity instance indices to their transform IDs in the [SsboTransform](crate::SsboTransform) buffer (see `ModelUuidToTransformUuidRender`).
14//! - Finally, the render pass iterates over the batches and renders them, writing to the G-buffer [`DeferredTextures`](crate::DeferredTextures) and the depth texture.
15//! - It then resolves the G-buffer textures to `DeferredTexturesResolved` for use in the lighting pass, which doesn't use MSAA.
16//!
17//! ## Lighting pass (see [`RenderPassDeferredLighting`](crate::passes::RenderPassDeferredLighting))
18//! - This pass first extracts the light data from the main world to the render world, and stores it in the `LightsSsbo` ssbo. Supported light types are currently [DirectionalLight], [PointLight] and [SpotLight].
19//! - Then, for each frame, it reads the G-buffer textures and the light data, and computes the final lit colors, which it writes to a [`RenderTexture`](crate::prelude::RenderTexture) in MSAA format.
20//!
21//! ## Limitations
22//! The number of supported lights and tracked PBR transform entries is limited by:
23//!   - [`MAX_LIGHTS`](crate::MAX_LIGHTS) limits the GPU light buffer size.
24//!   - [`SSBO_TRANSFORM_MAX_ENTITY`](crate::SSBO_TRANSFORM_MAX_ENTITY) limits tracked PBR transform entries.
25//!
26//! ## Custom rendering
27//! To find out more about how to create custom subpasses, materials and render pipelines, see the documentation of the [`wde_renderer`](wde_renderer) crate.
28//!
29//! # Usage
30//! ```rust
31//! // Spawn a directional PBR light
32//! commands.spawn(DirectionalLight {
33//!     direction: Vec3::new(-0.5, -1.0, -0.25).normalize(),
34//!     ..Default::default()
35//! });
36//!
37//! // Spawn a simple PBR model (with a single mesh and material)
38//! commands.spawn((
39//!     Transform::from_xyz(0.0, 0.0, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
40//!     PbrModel(vec![(
41//!         asset_server.add("models/example_model.obj"),
42//!         asset_server.add(PbrMaterial {
43//!             albedo: Color::WHITE,
44//!             metallic: 0.5,
45//!             roughness: 0.5,
46//!             ..Default::default()
47//!         })
48//!     )]
49//! ));
50//! ```
51use bevy::prelude::*;
52use wde_renderer::prelude::*;
53
54mod batches;
55mod lights;
56mod subpass;
57mod transform;
58mod pbr_material;
59
60pub use batches::*;
61pub use lights::*;
62pub use transform::*;
63pub use pbr_material::{PbrMaterial, PbrMaterial3d};
64
65use crate::{
66    deferred::{
67        batches::DeferredDependenciesPlugin, lights::LightsPlugin, subpass::PbrRenderPlugin,
68        transform::PbrTransformPlugin
69    },
70    passes::{RenderPassDeferredLighting, SubRenderPassLightingPbr}
71};
72
73pub(crate) struct DeferredPlugin;
74impl Plugin for DeferredPlugin {
75    fn build(&self, app: &mut App) {
76        // Add the plugins
77        app.add_plugins((
78            LightsPlugin,
79            DeferredDependenciesPlugin,
80            PbrRenderPlugin,
81            PbrTransformPlugin,
82            RenderBindingRegisterPlugin::<PbrMaterial>::default(),
83        ));
84
85        // Add the render graph nodes
86        app.get_sub_app_mut(RenderApp)
87            .unwrap()
88            .world_mut()
89            .get_resource_mut::<RenderGraph>()
90            .unwrap()
91            .add_sub_pass::<SubRenderPassLightingPbr, RenderPassDeferredLighting>();
92    }
93}