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