Skip to main content

bevy_pbr/transmission/
mod.rs

1mod node;
2mod phase;
3mod texture;
4
5use bevy_app::{App, Plugin};
6use bevy_camera::Camera3d;
7use bevy_core_pipeline::{
8    core_3d::{main_opaque_pass_3d, main_transparent_pass_3d},
9    schedule::{Core3d, Core3dSystems},
10};
11use bevy_ecs::{prelude::*, schedule::IntoScheduleConfigs};
12use bevy_reflect::prelude::*;
13use bevy_render::{
14    extract_component::{ExtractComponent, ExtractComponentPlugin},
15    render_phase::{sort_phase_system, AddRenderCommand, DrawFunctions, ViewSortedRenderPhases},
16    ExtractSchedule, Render, RenderApp, RenderSystems,
17};
18use bevy_shader::load_shader_library;
19pub use node::main_transmissive_pass_3d;
20pub use phase::Transmissive3d;
21pub use texture::ViewTransmissionTexture;
22
23use texture::prepare_core_3d_transmission_textures;
24
25use crate::{DrawMaterial, MeshPipelineKey};
26
27/// Enables screen-space transmission for cameras.
28pub struct ScreenSpaceTransmissionPlugin;
29
30impl Plugin for ScreenSpaceTransmissionPlugin {
31    fn build(&self, app: &mut App) {
32        load_shader_library!(app, "transmission.wgsl");
33
34        app.add_plugins(ExtractComponentPlugin::<ScreenSpaceTransmission>::default())
35            .register_required_components::<Camera3d, ScreenSpaceTransmission>();
36
37        let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
38            return;
39        };
40
41        render_app
42            .init_resource::<DrawFunctions<Transmissive3d>>()
43            .init_resource::<ViewSortedRenderPhases<Transmissive3d>>()
44            .add_render_command::<Transmissive3d, DrawMaterial>()
45            .add_systems(
46                Render,
47                sort_phase_system::<Transmissive3d>.in_set(RenderSystems::PhaseSort),
48            )
49            .add_systems(ExtractSchedule, phase::extract_transmissive_camera_phases)
50            .add_systems(
51                Render,
52                prepare_core_3d_transmission_textures.in_set(RenderSystems::PrepareResources),
53            )
54            .add_systems(
55                Core3d,
56                main_transmissive_pass_3d
57                    .after(main_opaque_pass_3d)
58                    .before(main_transparent_pass_3d)
59                    .in_set(Core3dSystems::MainPass),
60            );
61    }
62}
63
64/// Configures transmission behavior, offering a trade-off between performance and visual fidelity.
65#[derive(Component, Reflect, Clone, ExtractComponent)]
66#[reflect(Component, Default, Clone)]
67pub struct ScreenSpaceTransmission {
68    /// How many individual steps should be performed in the `Transmissive3d` pass.
69    ///
70    /// Roughly corresponds to how many layers of transparency are rendered for screen space
71    /// specular transmissive objects. Each step requires making one additional
72    /// texture copy, so it's recommended to keep this number to a reasonably low value. Defaults to `1`.
73    ///
74    /// ### Notes
75    ///
76    /// - No copies will be performed if there are no transmissive materials currently being rendered,
77    ///   regardless of this setting.
78    /// - Setting this to `0` disables the screen-space refraction effect entirely, and falls
79    ///   back to refracting only the environment map light's texture.
80    /// - If set to more than `0`, any opaque [`clear_color`](bevy_camera::Camera::clear_color) will obscure the environment
81    ///   map light's texture, preventing it from being visible through transmissive materials. If you'd like
82    ///   to still have the environment map show up in your refractions, you can set the clear color's alpha to `0.0`.
83    ///   Keep in mind that depending on the platform and your window settings, this may cause the window to become
84    ///   transparent.
85    pub steps: usize,
86    /// The quality of the screen space specular transmission blur effect, applied to whatever's behind transmissive
87    /// objects when their `roughness` is greater than `0.0`.
88    ///
89    /// Higher qualities are more GPU-intensive.
90    ///
91    /// **Note:** You can get better-looking results at any quality level by enabling TAA. See: `TemporalAntiAliasPlugin`
92    pub quality: ScreenSpaceTransmissionQuality,
93}
94
95impl Default for ScreenSpaceTransmission {
96    fn default() -> Self {
97        Self {
98            steps: 1,
99            quality: Default::default(),
100        }
101    }
102}
103
104/// The quality of the screen space transmission blur effect, applied to whatever's behind transmissive
105/// objects when their `roughness` is greater than `0.0`.
106///
107/// Higher qualities are more GPU-intensive.
108///
109/// **Note:** You can get better-looking results at any quality level by enabling TAA. See: `TemporalAntiAliasPlugin`
110#[derive(Default, Clone, Copy, Reflect, PartialEq, PartialOrd, Debug)]
111#[reflect(Default, Clone, Debug, PartialEq)]
112pub enum ScreenSpaceTransmissionQuality {
113    /// Best performance at the cost of quality. Suitable for lower end GPUs. (e.g. Mobile)
114    ///
115    /// `num_taps` = 4
116    Low,
117
118    /// A balanced option between quality and performance.
119    ///
120    /// `num_taps` = 8
121    #[default]
122    Medium,
123
124    /// Better quality. Suitable for high end GPUs. (e.g. Desktop)
125    ///
126    /// `num_taps` = 16
127    High,
128
129    /// The highest quality, suitable for non-realtime rendering. (e.g. Pre-rendered cinematics and photo mode)
130    ///
131    /// `num_taps` = 32
132    Ultra,
133}
134
135impl ScreenSpaceTransmissionQuality {
136    pub const fn pipeline_key(self) -> MeshPipelineKey {
137        match self {
138            ScreenSpaceTransmissionQuality::Low => {
139                MeshPipelineKey::SCREEN_SPACE_SPECULAR_TRANSMISSION_LOW
140            }
141            ScreenSpaceTransmissionQuality::Medium => {
142                MeshPipelineKey::SCREEN_SPACE_SPECULAR_TRANSMISSION_MEDIUM
143            }
144            ScreenSpaceTransmissionQuality::High => {
145                MeshPipelineKey::SCREEN_SPACE_SPECULAR_TRANSMISSION_HIGH
146            }
147            ScreenSpaceTransmissionQuality::Ultra => {
148                MeshPipelineKey::SCREEN_SPACE_SPECULAR_TRANSMISSION_ULTRA
149            }
150        }
151    }
152}