1#![expect(missing_docs, reason = "Not all docs are written yet, see #3492.")]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![forbid(unsafe_code)]
4#![doc(
5 html_logo_url = "https://bevy.org/assets/icon.png",
6 html_favicon_url = "https://bevy.org/assets/icon.png"
7)]
8
9extern crate alloc;
10
11#[cfg(feature = "meshlet")]
12mod meshlet;
13pub mod wireframe;
14
15#[cfg(feature = "meshlet")]
19pub mod experimental {
20 pub mod meshlet {
23 pub use crate::meshlet::*;
24 }
25}
26
27mod atmosphere;
28mod cluster;
29mod components;
30pub mod decal;
31pub mod deferred;
32pub mod diagnostic;
33mod extended_material;
34mod fog;
35mod light_probe;
36mod lightmap;
37mod material;
38mod material_bind_groups;
39mod medium;
40mod mesh_material;
41mod parallax;
42mod pbr_material;
43mod prepass;
44mod render;
45mod ssao;
46mod ssr;
47mod volumetric_fog;
48
49use bevy_color::{Color, LinearRgba};
50
51pub use atmosphere::*;
52use bevy_light::{
53 AmbientLight, DirectionalLight, PointLight, ShadowFilteringMethod, SimulationLightSystems,
54 SpotLight,
55};
56use bevy_shader::{load_shader_library, ShaderRef};
57pub use cluster::*;
58pub use components::*;
59pub use decal::clustered::ClusteredDecalPlugin;
60pub use extended_material::*;
61pub use fog::*;
62pub use light_probe::*;
63pub use lightmap::*;
64pub use material::*;
65pub use material_bind_groups::*;
66pub use medium::*;
67pub use mesh_material::*;
68pub use parallax::*;
69pub use pbr_material::*;
70pub use prepass::*;
71pub use render::*;
72pub use ssao::*;
73pub use ssr::*;
74pub use volumetric_fog::VolumetricFogPlugin;
75
76pub mod prelude {
80 #[doc(hidden)]
81 pub use crate::{
82 fog::{DistanceFog, FogFalloff},
83 material::{Material, MaterialPlugin},
84 mesh_material::MeshMaterial3d,
85 parallax::ParallaxMappingMethod,
86 pbr_material::StandardMaterial,
87 ssao::ScreenSpaceAmbientOcclusionPlugin,
88 };
89}
90
91pub mod graph {
92 use bevy_render::render_graph::RenderLabel;
93
94 #[derive(Debug, Hash, PartialEq, Eq, Clone, RenderLabel)]
96 pub enum NodePbr {
97 EarlyShadowPass,
100 LateShadowPass,
103 ScreenSpaceAmbientOcclusion,
105 DeferredLightingPass,
106 VolumetricFog,
108 EarlyGpuPreprocess,
111 LateGpuPreprocess,
114 ScreenSpaceReflections,
116 EarlyPrepassBuildIndirectParameters,
119 LatePrepassBuildIndirectParameters,
122 MainBuildIndirectParameters,
125 ClearIndirectParametersMetadata,
126 }
127}
128
129use crate::{deferred::DeferredPbrLightingPlugin, graph::NodePbr};
130use bevy_app::prelude::*;
131use bevy_asset::{AssetApp, AssetPath, Assets, Handle, RenderAssetUsages};
132use bevy_core_pipeline::core_3d::graph::{Core3d, Node3d};
133use bevy_ecs::prelude::*;
134#[cfg(feature = "bluenoise_texture")]
135use bevy_image::{CompressedImageFormats, ImageType};
136use bevy_image::{Image, ImageSampler};
137use bevy_render::{
138 alpha::AlphaMode,
139 camera::sort_cameras,
140 extract_resource::ExtractResourcePlugin,
141 render_graph::RenderGraph,
142 render_resource::{
143 Extent3d, TextureDataOrder, TextureDescriptor, TextureDimension, TextureFormat,
144 TextureUsages,
145 },
146 sync_component::SyncComponentPlugin,
147 ExtractSchedule, Render, RenderApp, RenderDebugFlags, RenderStartup, RenderSystems,
148};
149
150use std::path::PathBuf;
151
152fn shader_ref(path: PathBuf) -> ShaderRef {
153 ShaderRef::Path(AssetPath::from_path_buf(path).with_source("embedded"))
154}
155
156pub const TONEMAPPING_LUT_TEXTURE_BINDING_INDEX: u32 = 18;
157pub const TONEMAPPING_LUT_SAMPLER_BINDING_INDEX: u32 = 19;
158
159pub struct PbrPlugin {
161 pub prepass_enabled: bool,
164 pub add_default_deferred_lighting_plugin: bool,
166 pub use_gpu_instance_buffer_builder: bool,
171 pub debug_flags: RenderDebugFlags,
173}
174
175impl Default for PbrPlugin {
176 fn default() -> Self {
177 Self {
178 prepass_enabled: true,
179 add_default_deferred_lighting_plugin: true,
180 use_gpu_instance_buffer_builder: true,
181 debug_flags: RenderDebugFlags::default(),
182 }
183 }
184}
185
186#[derive(Resource)]
188pub struct Bluenoise {
189 pub texture: Handle<Image>,
191}
192
193impl Plugin for PbrPlugin {
194 fn build(&self, app: &mut App) {
195 load_shader_library!(app, "render/pbr_types.wgsl");
196 load_shader_library!(app, "render/pbr_bindings.wgsl");
197 load_shader_library!(app, "render/utils.wgsl");
198 load_shader_library!(app, "render/clustered_forward.wgsl");
199 load_shader_library!(app, "render/pbr_lighting.wgsl");
200 load_shader_library!(app, "render/pbr_transmission.wgsl");
201 load_shader_library!(app, "render/shadows.wgsl");
202 load_shader_library!(app, "deferred/pbr_deferred_types.wgsl");
203 load_shader_library!(app, "deferred/pbr_deferred_functions.wgsl");
204 load_shader_library!(app, "render/shadow_sampling.wgsl");
205 load_shader_library!(app, "render/pbr_functions.wgsl");
206 load_shader_library!(app, "render/rgb9e5.wgsl");
207 load_shader_library!(app, "render/pbr_ambient.wgsl");
208 load_shader_library!(app, "render/pbr_fragment.wgsl");
209 load_shader_library!(app, "render/pbr.wgsl");
210 load_shader_library!(app, "render/pbr_prepass_functions.wgsl");
211 load_shader_library!(app, "render/pbr_prepass.wgsl");
212 load_shader_library!(app, "render/parallax_mapping.wgsl");
213 load_shader_library!(app, "render/view_transformations.wgsl");
214
215 load_shader_library!(app, "meshlet/dummy_visibility_buffer_resolve.wgsl");
217
218 app.register_asset_reflect::<StandardMaterial>()
219 .init_resource::<DefaultOpaqueRendererMethod>()
220 .add_plugins((
221 MeshRenderPlugin {
222 use_gpu_instance_buffer_builder: self.use_gpu_instance_buffer_builder,
223 debug_flags: self.debug_flags,
224 },
225 MaterialsPlugin {
226 debug_flags: self.debug_flags,
227 },
228 MaterialPlugin::<StandardMaterial> {
229 debug_flags: self.debug_flags,
230 ..Default::default()
231 },
232 ScreenSpaceAmbientOcclusionPlugin,
233 FogPlugin,
234 ExtractResourcePlugin::<DefaultOpaqueRendererMethod>::default(),
235 SyncComponentPlugin::<ShadowFilteringMethod>::default(),
236 LightmapPlugin,
237 LightProbePlugin,
238 GpuMeshPreprocessPlugin {
239 use_gpu_instance_buffer_builder: self.use_gpu_instance_buffer_builder,
240 },
241 VolumetricFogPlugin,
242 ScreenSpaceReflectionsPlugin,
243 ClusteredDecalPlugin,
244 ))
245 .add_plugins((
246 decal::ForwardDecalPlugin,
247 SyncComponentPlugin::<DirectionalLight>::default(),
248 SyncComponentPlugin::<PointLight>::default(),
249 SyncComponentPlugin::<SpotLight>::default(),
250 SyncComponentPlugin::<AmbientLight>::default(),
251 ))
252 .add_plugins((ScatteringMediumPlugin, AtmospherePlugin))
253 .configure_sets(
254 PostUpdate,
255 (
256 SimulationLightSystems::AddClusters,
257 SimulationLightSystems::AssignLightsToClusters,
258 )
259 .chain(),
260 );
261
262 if self.add_default_deferred_lighting_plugin {
263 app.add_plugins(DeferredPbrLightingPlugin);
264 }
265
266 app.world_mut()
268 .resource_mut::<Assets<StandardMaterial>>()
269 .insert(
270 &Handle::<StandardMaterial>::default(),
271 StandardMaterial {
272 base_color: Color::srgb(1.0, 0.0, 0.5),
273 ..Default::default()
274 },
275 )
276 .unwrap();
277
278 let has_bluenoise = app
279 .get_sub_app(RenderApp)
280 .is_some_and(|render_app| render_app.world().is_resource_added::<Bluenoise>());
281
282 if !has_bluenoise {
283 let mut images = app.world_mut().resource_mut::<Assets<Image>>();
284 #[cfg(feature = "bluenoise_texture")]
285 let handle = {
286 let image = Image::from_buffer(
287 include_bytes!("bluenoise/stbn.ktx2"),
288 ImageType::Extension("ktx2"),
289 CompressedImageFormats::NONE,
290 false,
291 ImageSampler::Default,
292 RenderAssetUsages::RENDER_WORLD,
293 )
294 .expect("Failed to decode embedded blue-noise texture");
295 images.add(image)
296 };
297
298 #[cfg(not(feature = "bluenoise_texture"))]
299 let handle = { images.add(stbn_placeholder()) };
300
301 if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
302 render_app
303 .world_mut()
304 .insert_resource(Bluenoise { texture: handle });
305 }
306 }
307
308 let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
309 return;
310 };
311
312 render_app
314 .add_systems(
315 RenderStartup,
316 (
317 init_shadow_samplers,
318 init_global_clusterable_object_meta,
319 init_fallback_bindless_resources,
320 ),
321 )
322 .add_systems(
323 ExtractSchedule,
324 (
325 extract_clusters,
326 extract_lights,
327 extract_ambient_light_resource,
328 extract_ambient_light,
329 extract_shadow_filtering_method,
330 late_sweep_material_instances,
331 ),
332 )
333 .add_systems(
334 Render,
335 (
336 prepare_lights
337 .in_set(RenderSystems::ManageViews)
338 .after(sort_cameras),
339 prepare_clusters.in_set(RenderSystems::PrepareResources),
340 ),
341 )
342 .init_resource::<LightMeta>()
343 .init_resource::<RenderMaterialBindings>();
344
345 render_app.world_mut().add_observer(add_light_view_entities);
346 render_app
347 .world_mut()
348 .add_observer(remove_light_view_entities);
349 render_app.world_mut().add_observer(extracted_light_removed);
350
351 let early_shadow_pass_node = EarlyShadowPassNode::from_world(render_app.world_mut());
352 let late_shadow_pass_node = LateShadowPassNode::from_world(render_app.world_mut());
353 let mut graph = render_app.world_mut().resource_mut::<RenderGraph>();
354 let draw_3d_graph = graph.get_sub_graph_mut(Core3d).unwrap();
355 draw_3d_graph.add_node(NodePbr::EarlyShadowPass, early_shadow_pass_node);
356 draw_3d_graph.add_node(NodePbr::LateShadowPass, late_shadow_pass_node);
357 draw_3d_graph.add_node_edges((
358 NodePbr::EarlyShadowPass,
359 NodePbr::LateShadowPass,
360 Node3d::StartMainPass,
361 ));
362 }
363
364 fn finish(&self, app: &mut App) {
365 let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
366 return;
367 };
368
369 let global_cluster_settings = make_global_cluster_settings(render_app.world());
370 app.insert_resource(global_cluster_settings);
371 }
372}
373
374pub fn stbn_placeholder() -> Image {
375 let format = TextureFormat::Rgba8Unorm;
376 let data = vec![255, 0, 255, 255];
377 Image {
378 data: Some(data),
379 data_order: TextureDataOrder::default(),
380 texture_descriptor: TextureDescriptor {
381 size: Extent3d::default(),
382 format,
383 dimension: TextureDimension::D2,
384 label: None,
385 mip_level_count: 1,
386 sample_count: 1,
387 usage: TextureUsages::TEXTURE_BINDING,
388 view_formats: &[],
389 },
390 sampler: ImageSampler::Default,
391 texture_view_descriptor: None,
392 asset_usage: RenderAssetUsages::RENDER_WORLD,
393 copy_on_resize: false,
394 }
395}