1#![allow(missing_docs, reason = "Not all docs are written yet, see #3492.")]
3#![cfg_attr(docsrs, feature(doc_auto_cfg))]
4#![deny(unsafe_code)]
5#![doc(
6 html_logo_url = "https://bevyengine.org/assets/icon.png",
7 html_favicon_url = "https://bevyengine.org/assets/icon.png"
8)]
9
10extern crate alloc;
11
12#[cfg(feature = "meshlet")]
13mod meshlet;
14pub mod wireframe;
15
16#[cfg(feature = "meshlet")]
20pub mod experimental {
21 pub mod meshlet {
24 pub use crate::meshlet::*;
25 }
26}
27
28mod bundle;
29mod cluster;
30pub mod deferred;
31mod extended_material;
32mod fog;
33mod light;
34mod light_probe;
35mod lightmap;
36mod material;
37mod mesh_material;
38mod parallax;
39mod pbr_material;
40mod prepass;
41mod render;
42mod ssao;
43mod ssr;
44mod volumetric_fog;
45
46use bevy_color::{Color, LinearRgba};
47use core::marker::PhantomData;
48
49pub use bundle::*;
50pub use cluster::*;
51pub use extended_material::*;
52pub use fog::*;
53pub use light::*;
54pub use light_probe::*;
55pub use lightmap::*;
56pub use material::*;
57pub use mesh_material::*;
58pub use parallax::*;
59pub use pbr_material::*;
60pub use prepass::*;
61pub use render::*;
62pub use ssao::*;
63pub use ssr::*;
64#[allow(deprecated)]
65pub use volumetric_fog::{
66 FogVolume, FogVolumeBundle, VolumetricFog, VolumetricFogPlugin, VolumetricFogSettings,
67 VolumetricLight,
68};
69
70#[expect(deprecated)]
74pub mod prelude {
75 #[doc(hidden)]
76 pub use crate::{
77 bundle::{
78 DirectionalLightBundle, MaterialMeshBundle, PbrBundle, PointLightBundle,
79 SpotLightBundle,
80 },
81 fog::{DistanceFog, FogFalloff},
82 light::{light_consts, AmbientLight, DirectionalLight, PointLight, SpotLight},
83 light_probe::{
84 environment_map::{EnvironmentMapLight, ReflectionProbeBundle},
85 LightProbe,
86 },
87 material::{Material, MaterialPlugin},
88 mesh_material::MeshMaterial3d,
89 parallax::ParallaxMappingMethod,
90 pbr_material::StandardMaterial,
91 ssao::ScreenSpaceAmbientOcclusionPlugin,
92 };
93}
94
95pub mod graph {
96 use bevy_render::render_graph::RenderLabel;
97
98 #[derive(Debug, Hash, PartialEq, Eq, Clone, RenderLabel)]
99 pub enum NodePbr {
100 ShadowPass,
102 ScreenSpaceAmbientOcclusion,
104 DeferredLightingPass,
105 VolumetricFog,
107 GpuPreprocess,
109 ScreenSpaceReflections,
111 }
112}
113
114use crate::{deferred::DeferredPbrLightingPlugin, graph::NodePbr};
115use bevy_app::prelude::*;
116use bevy_asset::{load_internal_asset, AssetApp, Assets, Handle};
117use bevy_core_pipeline::core_3d::graph::{Core3d, Node3d};
118use bevy_ecs::prelude::*;
119use bevy_image::Image;
120use bevy_render::{
121 alpha::AlphaMode,
122 camera::{
123 CameraProjection, CameraUpdateSystem, OrthographicProjection, PerspectiveProjection,
124 Projection,
125 },
126 extract_component::ExtractComponentPlugin,
127 extract_resource::ExtractResourcePlugin,
128 render_asset::prepare_assets,
129 render_graph::RenderGraph,
130 render_resource::Shader,
131 sync_component::SyncComponentPlugin,
132 texture::GpuImage,
133 view::{check_visibility, VisibilitySystems},
134 ExtractSchedule, Render, RenderApp, RenderSet,
135};
136
137use bevy_transform::TransformSystem;
138
139pub const PBR_TYPES_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(1708015359337029744);
140pub const PBR_BINDINGS_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(5635987986427308186);
141pub const UTILS_HANDLE: Handle<Shader> = Handle::weak_from_u128(1900548483293416725);
142pub const CLUSTERED_FORWARD_HANDLE: Handle<Shader> = Handle::weak_from_u128(166852093121196815);
143pub const PBR_LIGHTING_HANDLE: Handle<Shader> = Handle::weak_from_u128(14170772752254856967);
144pub const PBR_TRANSMISSION_HANDLE: Handle<Shader> = Handle::weak_from_u128(77319684653223658032);
145pub const SHADOWS_HANDLE: Handle<Shader> = Handle::weak_from_u128(11350275143789590502);
146pub const SHADOW_SAMPLING_HANDLE: Handle<Shader> = Handle::weak_from_u128(3145627513789590502);
147pub const PBR_FRAGMENT_HANDLE: Handle<Shader> = Handle::weak_from_u128(2295049283805286543);
148pub const PBR_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(4805239651767701046);
149pub const PBR_PREPASS_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(9407115064344201137);
150pub const PBR_FUNCTIONS_HANDLE: Handle<Shader> = Handle::weak_from_u128(16550102964439850292);
151pub const PBR_AMBIENT_HANDLE: Handle<Shader> = Handle::weak_from_u128(2441520459096337034);
152pub const PARALLAX_MAPPING_SHADER_HANDLE: Handle<Shader> =
153 Handle::weak_from_u128(17035894873630133905);
154pub const VIEW_TRANSFORMATIONS_SHADER_HANDLE: Handle<Shader> =
155 Handle::weak_from_u128(2098345702398750291);
156pub const PBR_PREPASS_FUNCTIONS_SHADER_HANDLE: Handle<Shader> =
157 Handle::weak_from_u128(73204817249182637);
158pub const PBR_DEFERRED_TYPES_HANDLE: Handle<Shader> = Handle::weak_from_u128(3221241127431430599);
159pub const PBR_DEFERRED_FUNCTIONS_HANDLE: Handle<Shader> = Handle::weak_from_u128(72019026415438599);
160pub const RGB9E5_FUNCTIONS_HANDLE: Handle<Shader> = Handle::weak_from_u128(2659010996143919192);
161const MESHLET_VISIBILITY_BUFFER_RESOLVE_SHADER_HANDLE: Handle<Shader> =
162 Handle::weak_from_u128(2325134235233421);
163
164pub const TONEMAPPING_LUT_TEXTURE_BINDING_INDEX: u32 = 23;
165pub const TONEMAPPING_LUT_SAMPLER_BINDING_INDEX: u32 = 24;
166
167pub struct PbrPlugin {
169 pub prepass_enabled: bool,
172 pub add_default_deferred_lighting_plugin: bool,
174 pub use_gpu_instance_buffer_builder: bool,
179}
180
181impl Default for PbrPlugin {
182 fn default() -> Self {
183 Self {
184 prepass_enabled: true,
185 add_default_deferred_lighting_plugin: true,
186 use_gpu_instance_buffer_builder: true,
187 }
188 }
189}
190
191impl Plugin for PbrPlugin {
192 fn build(&self, app: &mut App) {
193 load_internal_asset!(
194 app,
195 PBR_TYPES_SHADER_HANDLE,
196 "render/pbr_types.wgsl",
197 Shader::from_wgsl
198 );
199 load_internal_asset!(
200 app,
201 PBR_BINDINGS_SHADER_HANDLE,
202 "render/pbr_bindings.wgsl",
203 Shader::from_wgsl
204 );
205 load_internal_asset!(app, UTILS_HANDLE, "render/utils.wgsl", Shader::from_wgsl);
206 load_internal_asset!(
207 app,
208 CLUSTERED_FORWARD_HANDLE,
209 "render/clustered_forward.wgsl",
210 Shader::from_wgsl
211 );
212 load_internal_asset!(
213 app,
214 PBR_LIGHTING_HANDLE,
215 "render/pbr_lighting.wgsl",
216 Shader::from_wgsl
217 );
218 load_internal_asset!(
219 app,
220 PBR_TRANSMISSION_HANDLE,
221 "render/pbr_transmission.wgsl",
222 Shader::from_wgsl
223 );
224 load_internal_asset!(
225 app,
226 SHADOWS_HANDLE,
227 "render/shadows.wgsl",
228 Shader::from_wgsl
229 );
230 load_internal_asset!(
231 app,
232 PBR_DEFERRED_TYPES_HANDLE,
233 "deferred/pbr_deferred_types.wgsl",
234 Shader::from_wgsl
235 );
236 load_internal_asset!(
237 app,
238 PBR_DEFERRED_FUNCTIONS_HANDLE,
239 "deferred/pbr_deferred_functions.wgsl",
240 Shader::from_wgsl
241 );
242 load_internal_asset!(
243 app,
244 SHADOW_SAMPLING_HANDLE,
245 "render/shadow_sampling.wgsl",
246 Shader::from_wgsl
247 );
248 load_internal_asset!(
249 app,
250 PBR_FUNCTIONS_HANDLE,
251 "render/pbr_functions.wgsl",
252 Shader::from_wgsl
253 );
254 load_internal_asset!(
255 app,
256 RGB9E5_FUNCTIONS_HANDLE,
257 "render/rgb9e5.wgsl",
258 Shader::from_wgsl
259 );
260 load_internal_asset!(
261 app,
262 PBR_AMBIENT_HANDLE,
263 "render/pbr_ambient.wgsl",
264 Shader::from_wgsl
265 );
266 load_internal_asset!(
267 app,
268 PBR_FRAGMENT_HANDLE,
269 "render/pbr_fragment.wgsl",
270 Shader::from_wgsl
271 );
272 load_internal_asset!(app, PBR_SHADER_HANDLE, "render/pbr.wgsl", Shader::from_wgsl);
273 load_internal_asset!(
274 app,
275 PBR_PREPASS_FUNCTIONS_SHADER_HANDLE,
276 "render/pbr_prepass_functions.wgsl",
277 Shader::from_wgsl
278 );
279 load_internal_asset!(
280 app,
281 PBR_PREPASS_SHADER_HANDLE,
282 "render/pbr_prepass.wgsl",
283 Shader::from_wgsl
284 );
285 load_internal_asset!(
286 app,
287 PARALLAX_MAPPING_SHADER_HANDLE,
288 "render/parallax_mapping.wgsl",
289 Shader::from_wgsl
290 );
291 load_internal_asset!(
292 app,
293 VIEW_TRANSFORMATIONS_SHADER_HANDLE,
294 "render/view_transformations.wgsl",
295 Shader::from_wgsl
296 );
297 load_internal_asset!(
299 app,
300 MESHLET_VISIBILITY_BUFFER_RESOLVE_SHADER_HANDLE,
301 "meshlet/dummy_visibility_buffer_resolve.wgsl",
302 Shader::from_wgsl
303 );
304
305 app.register_asset_reflect::<StandardMaterial>()
306 .register_type::<AmbientLight>()
307 .register_type::<CascadeShadowConfig>()
308 .register_type::<Cascades>()
309 .register_type::<CascadesVisibleEntities>()
310 .register_type::<VisibleMeshEntities>()
311 .register_type::<ClusterConfig>()
312 .register_type::<CubemapVisibleEntities>()
313 .register_type::<DirectionalLight>()
314 .register_type::<DirectionalLightShadowMap>()
315 .register_type::<NotShadowCaster>()
316 .register_type::<NotShadowReceiver>()
317 .register_type::<PointLight>()
318 .register_type::<PointLightShadowMap>()
319 .register_type::<SpotLight>()
320 .register_type::<ShadowFilteringMethod>()
321 .init_resource::<AmbientLight>()
322 .init_resource::<GlobalVisibleClusterableObjects>()
323 .init_resource::<DirectionalLightShadowMap>()
324 .init_resource::<PointLightShadowMap>()
325 .register_type::<DefaultOpaqueRendererMethod>()
326 .init_resource::<DefaultOpaqueRendererMethod>()
327 .add_plugins((
328 MeshRenderPlugin {
329 use_gpu_instance_buffer_builder: self.use_gpu_instance_buffer_builder,
330 },
331 MaterialPlugin::<StandardMaterial> {
332 prepass_enabled: self.prepass_enabled,
333 ..Default::default()
334 },
335 ScreenSpaceAmbientOcclusionPlugin,
336 ExtractResourcePlugin::<AmbientLight>::default(),
337 FogPlugin,
338 ExtractResourcePlugin::<DefaultOpaqueRendererMethod>::default(),
339 ExtractComponentPlugin::<ShadowFilteringMethod>::default(),
340 LightmapPlugin,
341 LightProbePlugin,
342 PbrProjectionPlugin::<Projection>::default(),
343 PbrProjectionPlugin::<PerspectiveProjection>::default(),
344 PbrProjectionPlugin::<OrthographicProjection>::default(),
345 GpuMeshPreprocessPlugin {
346 use_gpu_instance_buffer_builder: self.use_gpu_instance_buffer_builder,
347 },
348 VolumetricFogPlugin,
349 ScreenSpaceReflectionsPlugin,
350 ))
351 .add_plugins((
352 SyncComponentPlugin::<DirectionalLight>::default(),
353 SyncComponentPlugin::<PointLight>::default(),
354 SyncComponentPlugin::<SpotLight>::default(),
355 ))
356 .configure_sets(
357 PostUpdate,
358 (
359 SimulationLightSystems::AddClusters,
360 SimulationLightSystems::AssignLightsToClusters,
361 )
362 .chain(),
363 )
364 .configure_sets(
365 PostUpdate,
366 SimulationLightSystems::UpdateDirectionalLightCascades
367 .ambiguous_with(SimulationLightSystems::UpdateDirectionalLightCascades),
368 )
369 .configure_sets(
370 PostUpdate,
371 SimulationLightSystems::CheckLightVisibility
372 .ambiguous_with(SimulationLightSystems::CheckLightVisibility),
373 )
374 .add_systems(
375 PostUpdate,
376 (
377 add_clusters
378 .in_set(SimulationLightSystems::AddClusters)
379 .after(CameraUpdateSystem),
380 assign_objects_to_clusters
381 .in_set(SimulationLightSystems::AssignLightsToClusters)
382 .after(TransformSystem::TransformPropagate)
383 .after(VisibilitySystems::CheckVisibility)
384 .after(CameraUpdateSystem),
385 clear_directional_light_cascades
386 .in_set(SimulationLightSystems::UpdateDirectionalLightCascades)
387 .after(TransformSystem::TransformPropagate)
388 .after(CameraUpdateSystem),
389 update_directional_light_frusta
390 .in_set(SimulationLightSystems::UpdateLightFrusta)
391 .after(VisibilitySystems::CheckVisibility)
393 .after(TransformSystem::TransformPropagate)
394 .after(SimulationLightSystems::UpdateDirectionalLightCascades)
395 .ambiguous_with(update_spot_light_frusta),
399 update_point_light_frusta
400 .in_set(SimulationLightSystems::UpdateLightFrusta)
401 .after(TransformSystem::TransformPropagate)
402 .after(SimulationLightSystems::AssignLightsToClusters),
403 update_spot_light_frusta
404 .in_set(SimulationLightSystems::UpdateLightFrusta)
405 .after(TransformSystem::TransformPropagate)
406 .after(SimulationLightSystems::AssignLightsToClusters),
407 check_visibility::<WithLight>.in_set(VisibilitySystems::CheckVisibility),
408 (
409 check_dir_light_mesh_visibility,
410 check_point_light_mesh_visibility,
411 )
412 .in_set(SimulationLightSystems::CheckLightVisibility)
413 .after(VisibilitySystems::CalculateBounds)
414 .after(TransformSystem::TransformPropagate)
415 .after(SimulationLightSystems::UpdateLightFrusta)
416 .after(VisibilitySystems::CheckVisibility),
420 ),
421 );
422
423 if self.add_default_deferred_lighting_plugin {
424 app.add_plugins(DeferredPbrLightingPlugin);
425 }
426
427 app.world_mut()
429 .resource_mut::<Assets<StandardMaterial>>()
430 .insert(
431 &Handle::<StandardMaterial>::default(),
432 StandardMaterial {
433 base_color: Color::srgb(1.0, 0.0, 0.5),
434 ..Default::default()
435 },
436 );
437
438 let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
439 return;
440 };
441
442 render_app
444 .add_systems(ExtractSchedule, (extract_clusters, extract_lights))
445 .add_systems(
446 Render,
447 (
448 prepare_lights
449 .in_set(RenderSet::ManageViews)
450 .after(prepare_assets::<GpuImage>),
451 prepare_clusters.in_set(RenderSet::PrepareResources),
452 ),
453 )
454 .init_resource::<LightMeta>();
455
456 render_app.world_mut().add_observer(add_light_view_entities);
457 render_app
458 .world_mut()
459 .add_observer(remove_light_view_entities);
460 render_app.world_mut().add_observer(extracted_light_removed);
461
462 let shadow_pass_node = ShadowPassNode::new(render_app.world_mut());
463 let mut graph = render_app.world_mut().resource_mut::<RenderGraph>();
464 let draw_3d_graph = graph.get_sub_graph_mut(Core3d).unwrap();
465 draw_3d_graph.add_node(NodePbr::ShadowPass, shadow_pass_node);
466 draw_3d_graph.add_node_edge(NodePbr::ShadowPass, Node3d::StartMainPass);
467 }
468
469 fn finish(&self, app: &mut App) {
470 let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
471 return;
472 };
473
474 render_app
476 .init_resource::<ShadowSamplers>()
477 .init_resource::<GlobalClusterableObjectMeta>();
478 }
479}
480
481pub struct PbrProjectionPlugin<T: CameraProjection + Component>(PhantomData<T>);
483impl<T: CameraProjection + Component> Plugin for PbrProjectionPlugin<T> {
484 fn build(&self, app: &mut App) {
485 app.add_systems(
486 PostUpdate,
487 build_directional_light_cascades::<T>
488 .in_set(SimulationLightSystems::UpdateDirectionalLightCascades)
489 .after(clear_directional_light_cascades),
490 );
491 }
492}
493impl<T: CameraProjection + Component> Default for PbrProjectionPlugin<T> {
494 fn default() -> Self {
495 Self(Default::default())
496 }
497}