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}