Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_pbr/src/lib.rs
6598 views
1
#![expect(missing_docs, reason = "Not all docs are written yet, see #3492.")]
2
#![cfg_attr(docsrs, feature(doc_auto_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
9
extern crate alloc;
10
11
#[cfg(feature = "meshlet")]
12
mod meshlet;
13
pub mod wireframe;
14
15
/// Experimental features that are not yet finished. Please report any issues you encounter!
16
///
17
/// Expect bugs, missing features, compatibility issues, low performance, and/or future breaking changes.
18
#[cfg(feature = "meshlet")]
19
pub mod experimental {
20
/// Render high-poly 3d meshes using an efficient GPU-driven method.
21
/// See [`MeshletPlugin`](meshlet::MeshletPlugin) and [`MeshletMesh`](meshlet::MeshletMesh) for details.
22
pub mod meshlet {
23
pub use crate::meshlet::*;
24
}
25
}
26
27
mod atmosphere;
28
mod cluster;
29
mod components;
30
pub mod decal;
31
pub mod deferred;
32
mod extended_material;
33
mod fog;
34
mod light_probe;
35
mod lightmap;
36
mod material;
37
mod material_bind_groups;
38
mod mesh_material;
39
mod parallax;
40
mod pbr_material;
41
mod prepass;
42
mod render;
43
mod ssao;
44
mod ssr;
45
mod volumetric_fog;
46
47
use bevy_color::{Color, LinearRgba};
48
49
pub use atmosphere::*;
50
use bevy_light::{
51
AmbientLight, DirectionalLight, PointLight, ShadowFilteringMethod, SimulationLightSystems,
52
SpotLight,
53
};
54
use bevy_shader::{load_shader_library, ShaderRef};
55
pub use cluster::*;
56
pub use components::*;
57
pub use decal::clustered::ClusteredDecalPlugin;
58
pub use extended_material::*;
59
pub use fog::*;
60
pub use light_probe::*;
61
pub use lightmap::*;
62
pub use material::*;
63
pub use material_bind_groups::*;
64
pub use mesh_material::*;
65
pub use parallax::*;
66
pub use pbr_material::*;
67
pub use prepass::*;
68
pub use render::*;
69
pub use ssao::*;
70
pub use ssr::*;
71
pub use volumetric_fog::VolumetricFogPlugin;
72
73
/// The PBR prelude.
74
///
75
/// This includes the most common types in this crate, re-exported for your convenience.
76
pub mod prelude {
77
#[doc(hidden)]
78
pub use crate::{
79
fog::{DistanceFog, FogFalloff},
80
material::{Material, MaterialPlugin},
81
mesh_material::MeshMaterial3d,
82
parallax::ParallaxMappingMethod,
83
pbr_material::StandardMaterial,
84
ssao::ScreenSpaceAmbientOcclusionPlugin,
85
};
86
}
87
88
pub mod graph {
89
use bevy_render::render_graph::RenderLabel;
90
91
/// Render graph nodes specific to 3D PBR rendering.
92
#[derive(Debug, Hash, PartialEq, Eq, Clone, RenderLabel)]
93
pub enum NodePbr {
94
/// Label for the shadow pass node that draws meshes that were visible
95
/// from the light last frame.
96
EarlyShadowPass,
97
/// Label for the shadow pass node that draws meshes that became visible
98
/// from the light this frame.
99
LateShadowPass,
100
/// Label for the screen space ambient occlusion render node.
101
ScreenSpaceAmbientOcclusion,
102
DeferredLightingPass,
103
/// Label for the volumetric lighting pass.
104
VolumetricFog,
105
/// Label for the shader that transforms and culls meshes that were
106
/// visible last frame.
107
EarlyGpuPreprocess,
108
/// Label for the shader that transforms and culls meshes that became
109
/// visible this frame.
110
LateGpuPreprocess,
111
/// Label for the screen space reflections pass.
112
ScreenSpaceReflections,
113
/// Label for the node that builds indirect draw parameters for meshes
114
/// that were visible last frame.
115
EarlyPrepassBuildIndirectParameters,
116
/// Label for the node that builds indirect draw parameters for meshes
117
/// that became visible this frame.
118
LatePrepassBuildIndirectParameters,
119
/// Label for the node that builds indirect draw parameters for the main
120
/// rendering pass, containing all meshes that are visible this frame.
121
MainBuildIndirectParameters,
122
ClearIndirectParametersMetadata,
123
}
124
}
125
126
use crate::{deferred::DeferredPbrLightingPlugin, graph::NodePbr};
127
use bevy_app::prelude::*;
128
use bevy_asset::{AssetApp, AssetPath, Assets, Handle, RenderAssetUsages};
129
use bevy_core_pipeline::core_3d::graph::{Core3d, Node3d};
130
use bevy_ecs::prelude::*;
131
#[cfg(feature = "bluenoise_texture")]
132
use bevy_image::{CompressedImageFormats, ImageType};
133
use bevy_image::{Image, ImageSampler};
134
use bevy_render::{
135
alpha::AlphaMode,
136
camera::sort_cameras,
137
extract_resource::ExtractResourcePlugin,
138
render_graph::RenderGraph,
139
render_resource::{
140
Extent3d, TextureDataOrder, TextureDescriptor, TextureDimension, TextureFormat,
141
TextureUsages,
142
},
143
sync_component::SyncComponentPlugin,
144
ExtractSchedule, Render, RenderApp, RenderDebugFlags, RenderStartup, RenderSystems,
145
};
146
147
use std::path::PathBuf;
148
149
fn shader_ref(path: PathBuf) -> ShaderRef {
150
ShaderRef::Path(AssetPath::from_path_buf(path).with_source("embedded"))
151
}
152
153
pub const TONEMAPPING_LUT_TEXTURE_BINDING_INDEX: u32 = 18;
154
pub const TONEMAPPING_LUT_SAMPLER_BINDING_INDEX: u32 = 19;
155
156
/// Sets up the entire PBR infrastructure of bevy.
157
pub struct PbrPlugin {
158
/// Controls if the prepass is enabled for the [`StandardMaterial`].
159
/// For more information about what a prepass is, see the [`bevy_core_pipeline::prepass`] docs.
160
pub prepass_enabled: bool,
161
/// Controls if [`DeferredPbrLightingPlugin`] is added.
162
pub add_default_deferred_lighting_plugin: bool,
163
/// Controls if GPU [`MeshUniform`] building is enabled.
164
///
165
/// This requires compute shader support and so will be forcibly disabled if
166
/// the platform doesn't support those.
167
pub use_gpu_instance_buffer_builder: bool,
168
/// Debugging flags that can optionally be set when constructing the renderer.
169
pub debug_flags: RenderDebugFlags,
170
}
171
172
impl Default for PbrPlugin {
173
fn default() -> Self {
174
Self {
175
prepass_enabled: true,
176
add_default_deferred_lighting_plugin: true,
177
use_gpu_instance_buffer_builder: true,
178
debug_flags: RenderDebugFlags::default(),
179
}
180
}
181
}
182
183
/// A resource that stores the spatio-temporal blue noise texture.
184
#[derive(Resource)]
185
pub struct Bluenoise {
186
/// Texture handle for spatio-temporal blue noise
187
pub texture: Handle<Image>,
188
}
189
190
impl Plugin for PbrPlugin {
191
fn build(&self, app: &mut App) {
192
load_shader_library!(app, "render/pbr_types.wgsl");
193
load_shader_library!(app, "render/pbr_bindings.wgsl");
194
load_shader_library!(app, "render/utils.wgsl");
195
load_shader_library!(app, "render/clustered_forward.wgsl");
196
load_shader_library!(app, "render/pbr_lighting.wgsl");
197
load_shader_library!(app, "render/pbr_transmission.wgsl");
198
load_shader_library!(app, "render/shadows.wgsl");
199
load_shader_library!(app, "deferred/pbr_deferred_types.wgsl");
200
load_shader_library!(app, "deferred/pbr_deferred_functions.wgsl");
201
load_shader_library!(app, "render/shadow_sampling.wgsl");
202
load_shader_library!(app, "render/pbr_functions.wgsl");
203
load_shader_library!(app, "render/rgb9e5.wgsl");
204
load_shader_library!(app, "render/pbr_ambient.wgsl");
205
load_shader_library!(app, "render/pbr_fragment.wgsl");
206
load_shader_library!(app, "render/pbr.wgsl");
207
load_shader_library!(app, "render/pbr_prepass_functions.wgsl");
208
load_shader_library!(app, "render/pbr_prepass.wgsl");
209
load_shader_library!(app, "render/parallax_mapping.wgsl");
210
load_shader_library!(app, "render/view_transformations.wgsl");
211
212
// Setup dummy shaders for when MeshletPlugin is not used to prevent shader import errors.
213
load_shader_library!(app, "meshlet/dummy_visibility_buffer_resolve.wgsl");
214
215
app.register_asset_reflect::<StandardMaterial>()
216
.init_resource::<DefaultOpaqueRendererMethod>()
217
.add_plugins((
218
MeshRenderPlugin {
219
use_gpu_instance_buffer_builder: self.use_gpu_instance_buffer_builder,
220
debug_flags: self.debug_flags,
221
},
222
MaterialsPlugin {
223
debug_flags: self.debug_flags,
224
},
225
MaterialPlugin::<StandardMaterial> {
226
prepass_enabled: self.prepass_enabled,
227
debug_flags: self.debug_flags,
228
..Default::default()
229
},
230
ScreenSpaceAmbientOcclusionPlugin,
231
FogPlugin,
232
ExtractResourcePlugin::<DefaultOpaqueRendererMethod>::default(),
233
SyncComponentPlugin::<ShadowFilteringMethod>::default(),
234
LightmapPlugin,
235
LightProbePlugin,
236
GpuMeshPreprocessPlugin {
237
use_gpu_instance_buffer_builder: self.use_gpu_instance_buffer_builder,
238
},
239
VolumetricFogPlugin,
240
ScreenSpaceReflectionsPlugin,
241
ClusteredDecalPlugin,
242
))
243
.add_plugins((
244
decal::ForwardDecalPlugin,
245
SyncComponentPlugin::<DirectionalLight>::default(),
246
SyncComponentPlugin::<PointLight>::default(),
247
SyncComponentPlugin::<SpotLight>::default(),
248
SyncComponentPlugin::<AmbientLight>::default(),
249
))
250
.add_plugins(AtmospherePlugin)
251
.configure_sets(
252
PostUpdate,
253
(
254
SimulationLightSystems::AddClusters,
255
SimulationLightSystems::AssignLightsToClusters,
256
)
257
.chain(),
258
);
259
260
if self.add_default_deferred_lighting_plugin {
261
app.add_plugins(DeferredPbrLightingPlugin);
262
}
263
264
// Initialize the default material handle.
265
app.world_mut()
266
.resource_mut::<Assets<StandardMaterial>>()
267
.insert(
268
&Handle::<StandardMaterial>::default(),
269
StandardMaterial {
270
base_color: Color::srgb(1.0, 0.0, 0.5),
271
..Default::default()
272
},
273
)
274
.unwrap();
275
276
let has_bluenoise = app
277
.get_sub_app(RenderApp)
278
.is_some_and(|render_app| render_app.world().is_resource_added::<Bluenoise>());
279
280
if !has_bluenoise {
281
let mut images = app.world_mut().resource_mut::<Assets<Image>>();
282
#[cfg(feature = "bluenoise_texture")]
283
let handle = {
284
let image = Image::from_buffer(
285
include_bytes!("bluenoise/stbn.ktx2"),
286
ImageType::Extension("ktx2"),
287
CompressedImageFormats::NONE,
288
false,
289
ImageSampler::Default,
290
RenderAssetUsages::RENDER_WORLD,
291
)
292
.expect("Failed to decode embedded blue-noise texture");
293
images.add(image)
294
};
295
296
#[cfg(not(feature = "bluenoise_texture"))]
297
let handle = { images.add(stbn_placeholder()) };
298
299
if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
300
render_app
301
.world_mut()
302
.insert_resource(Bluenoise { texture: handle });
303
}
304
}
305
306
let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
307
return;
308
};
309
310
// Extract the required data from the main world
311
render_app
312
.add_systems(
313
RenderStartup,
314
(
315
init_shadow_samplers,
316
init_global_clusterable_object_meta,
317
init_fallback_bindless_resources,
318
),
319
)
320
.add_systems(
321
ExtractSchedule,
322
(
323
extract_clusters,
324
extract_lights,
325
extract_ambient_light_resource,
326
extract_ambient_light,
327
extract_shadow_filtering_method,
328
late_sweep_material_instances,
329
),
330
)
331
.add_systems(
332
Render,
333
(
334
prepare_lights
335
.in_set(RenderSystems::ManageViews)
336
.after(sort_cameras),
337
prepare_clusters.in_set(RenderSystems::PrepareResources),
338
),
339
)
340
.init_resource::<LightMeta>()
341
.init_resource::<RenderMaterialBindings>();
342
343
render_app.world_mut().add_observer(add_light_view_entities);
344
render_app
345
.world_mut()
346
.add_observer(remove_light_view_entities);
347
render_app.world_mut().add_observer(extracted_light_removed);
348
349
let early_shadow_pass_node = EarlyShadowPassNode::from_world(render_app.world_mut());
350
let late_shadow_pass_node = LateShadowPassNode::from_world(render_app.world_mut());
351
let mut graph = render_app.world_mut().resource_mut::<RenderGraph>();
352
let draw_3d_graph = graph.get_sub_graph_mut(Core3d).unwrap();
353
draw_3d_graph.add_node(NodePbr::EarlyShadowPass, early_shadow_pass_node);
354
draw_3d_graph.add_node(NodePbr::LateShadowPass, late_shadow_pass_node);
355
draw_3d_graph.add_node_edges((
356
NodePbr::EarlyShadowPass,
357
NodePbr::LateShadowPass,
358
Node3d::StartMainPass,
359
));
360
}
361
362
fn finish(&self, app: &mut App) {
363
let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
364
return;
365
};
366
367
let global_cluster_settings = make_global_cluster_settings(render_app.world());
368
app.insert_resource(global_cluster_settings);
369
}
370
}
371
372
pub fn stbn_placeholder() -> Image {
373
let format = TextureFormat::Rgba8Unorm;
374
let data = vec![255, 0, 255, 255];
375
Image {
376
data: Some(data),
377
data_order: TextureDataOrder::default(),
378
texture_descriptor: TextureDescriptor {
379
size: Extent3d::default(),
380
format,
381
dimension: TextureDimension::D2,
382
label: None,
383
mip_level_count: 1,
384
sample_count: 1,
385
usage: TextureUsages::TEXTURE_BINDING,
386
view_formats: &[],
387
},
388
sampler: ImageSampler::Default,
389
texture_view_descriptor: None,
390
asset_usage: RenderAssetUsages::RENDER_WORLD,
391
copy_on_resize: false,
392
}
393
}
394
395