Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_pbr/src/lib.rs
9374 views
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
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 contact_shadows;
31
use bevy_gltf::{
32
extensions::{GltfExtensionHandler, GltfExtensionHandlers},
33
GltfAssetLabel,
34
};
35
use bevy_render::sync_component::SyncComponent;
36
pub use contact_shadows::{
37
ContactShadows, ContactShadowsBuffer, ContactShadowsPlugin, ContactShadowsUniform,
38
ViewContactShadowsUniformOffset,
39
};
40
pub mod decal;
41
pub mod deferred;
42
pub mod diagnostic;
43
mod extended_material;
44
mod fog;
45
mod light_probe;
46
mod lightmap;
47
mod material;
48
mod material_bind_groups;
49
mod medium;
50
mod mesh_material;
51
mod parallax;
52
mod pbr_material;
53
mod prepass;
54
mod render;
55
mod ssao;
56
mod ssr;
57
mod transmission;
58
mod volumetric_fog;
59
60
use bevy_color::{Color, LinearRgba};
61
62
pub use atmosphere::*;
63
use bevy_asset::LoadContext;
64
use bevy_gltf::{gltf, GltfMaterial};
65
use bevy_light::{AmbientLight, DirectionalLight, PointLight, ShadowFilteringMethod, SpotLight};
66
use bevy_shader::{load_shader_library, ShaderRef};
67
pub use cluster::*;
68
pub use components::*;
69
pub use decal::clustered::ClusteredDecalPlugin;
70
pub use extended_material::*;
71
pub use fog::*;
72
pub use light_probe::*;
73
pub use lightmap::*;
74
pub use material::*;
75
pub use material_bind_groups::*;
76
pub use medium::*;
77
pub use mesh_material::*;
78
pub use parallax::*;
79
pub use pbr_material::*;
80
pub use prepass::*;
81
pub use render::*;
82
pub use ssao::*;
83
pub use ssr::*;
84
pub use transmission::*;
85
pub use volumetric_fog::VolumetricFogPlugin;
86
87
/// The PBR prelude.
88
///
89
/// This includes the most common types in this crate, re-exported for your convenience.
90
pub mod prelude {
91
#[doc(hidden)]
92
pub use crate::{
93
contact_shadows::ContactShadowsPlugin,
94
fog::{DistanceFog, FogFalloff},
95
material::{Material, MaterialPlugin},
96
mesh_material::MeshMaterial3d,
97
parallax::ParallaxMappingMethod,
98
pbr_material::StandardMaterial,
99
ssao::ScreenSpaceAmbientOcclusionPlugin,
100
};
101
}
102
103
use crate::deferred::DeferredPbrLightingPlugin;
104
use bevy_app::prelude::*;
105
use bevy_asset::{AssetApp, AssetPath, Assets, Handle, RenderAssetUsages};
106
use bevy_core_pipeline::mip_generation::experimental::depth::early_downsample_depth;
107
use bevy_core_pipeline::schedule::{Core3d, Core3dSystems};
108
use bevy_ecs::prelude::*;
109
#[cfg(feature = "bluenoise_texture")]
110
use bevy_image::{CompressedImageFormats, ImageType};
111
use bevy_image::{Image, ImageSampler};
112
use bevy_material::AlphaMode;
113
use bevy_render::{
114
camera::sort_cameras,
115
extract_resource::ExtractResourcePlugin,
116
render_resource::{
117
Extent3d, TextureDataOrder, TextureDescriptor, TextureDimension, TextureFormat,
118
TextureUsages,
119
},
120
sync_component::SyncComponentPlugin,
121
ExtractSchedule, Render, RenderApp, RenderDebugFlags, RenderStartup, RenderSystems,
122
};
123
124
use std::path::PathBuf;
125
126
fn shader_ref(path: PathBuf) -> ShaderRef {
127
ShaderRef::Path(AssetPath::from_path_buf(path).with_source("embedded"))
128
}
129
130
pub const TONEMAPPING_LUT_TEXTURE_BINDING_INDEX: u32 = 19;
131
pub const TONEMAPPING_LUT_SAMPLER_BINDING_INDEX: u32 = 20;
132
133
/// Sets up the entire PBR infrastructure of bevy.
134
pub struct PbrPlugin {
135
/// Controls if the prepass is enabled for the [`StandardMaterial`].
136
/// For more information about what a prepass is, see the [`bevy_core_pipeline::prepass`] docs.
137
pub prepass_enabled: bool,
138
/// Controls if [`DeferredPbrLightingPlugin`] is added.
139
pub add_default_deferred_lighting_plugin: bool,
140
/// Controls if GPU [`MeshUniform`] building is enabled.
141
///
142
/// This requires compute shader support and so will be forcibly disabled if
143
/// the platform doesn't support those.
144
pub use_gpu_instance_buffer_builder: bool,
145
/// Debugging flags that can optionally be set when constructing the renderer.
146
pub debug_flags: RenderDebugFlags,
147
/// Renders GLTFs with PBR.
148
pub gltf_render_enabled: bool,
149
}
150
151
impl Default for PbrPlugin {
152
fn default() -> Self {
153
Self {
154
prepass_enabled: true,
155
add_default_deferred_lighting_plugin: true,
156
use_gpu_instance_buffer_builder: true,
157
debug_flags: RenderDebugFlags::default(),
158
gltf_render_enabled: true,
159
}
160
}
161
}
162
163
/// A resource that stores the spatio-temporal blue noise texture.
164
#[derive(Resource)]
165
pub struct Bluenoise {
166
/// Texture handle for spatio-temporal blue noise
167
pub texture: Handle<Image>,
168
}
169
170
impl Plugin for PbrPlugin {
171
fn build(&self, app: &mut App) {
172
load_shader_library!(app, "render/pbr_types.wgsl");
173
load_shader_library!(app, "render/pbr_bindings.wgsl");
174
load_shader_library!(app, "render/utils.wgsl");
175
load_shader_library!(app, "render/clustered_forward.wgsl");
176
load_shader_library!(app, "render/pbr_lighting.wgsl");
177
load_shader_library!(app, "render/shadows.wgsl");
178
load_shader_library!(app, "deferred/pbr_deferred_types.wgsl");
179
load_shader_library!(app, "deferred/pbr_deferred_functions.wgsl");
180
load_shader_library!(app, "render/shadow_sampling.wgsl");
181
load_shader_library!(app, "render/pbr_functions.wgsl");
182
load_shader_library!(app, "render/rgb9e5.wgsl");
183
load_shader_library!(app, "render/pbr_ambient.wgsl");
184
load_shader_library!(app, "render/pbr_fragment.wgsl");
185
load_shader_library!(app, "render/pbr.wgsl");
186
load_shader_library!(app, "render/pbr_prepass_functions.wgsl");
187
load_shader_library!(app, "render/pbr_prepass.wgsl");
188
load_shader_library!(app, "render/parallax_mapping.wgsl");
189
load_shader_library!(app, "render/view_transformations.wgsl");
190
191
// Setup dummy shaders for when MeshletPlugin is not used to prevent shader import errors.
192
load_shader_library!(app, "meshlet/dummy_visibility_buffer_resolve.wgsl");
193
194
app.register_asset_reflect::<StandardMaterial>()
195
.init_resource::<DefaultOpaqueRendererMethod>()
196
.add_plugins((
197
MeshRenderPlugin {
198
use_gpu_instance_buffer_builder: self.use_gpu_instance_buffer_builder,
199
debug_flags: self.debug_flags,
200
},
201
MaterialsPlugin {
202
debug_flags: self.debug_flags,
203
},
204
MaterialPlugin::<StandardMaterial> {
205
debug_flags: self.debug_flags,
206
..Default::default()
207
},
208
ScreenSpaceAmbientOcclusionPlugin,
209
FogPlugin,
210
ExtractResourcePlugin::<DefaultOpaqueRendererMethod>::default(),
211
SyncComponentPlugin::<ShadowFilteringMethod, Self>::default(),
212
LightmapPlugin,
213
LightProbePlugin,
214
GpuMeshPreprocessPlugin {
215
use_gpu_instance_buffer_builder: self.use_gpu_instance_buffer_builder,
216
},
217
VolumetricFogPlugin,
218
ScreenSpaceReflectionsPlugin,
219
ScreenSpaceTransmissionPlugin,
220
ClusteredDecalPlugin,
221
ContactShadowsPlugin,
222
))
223
.add_plugins((
224
decal::ForwardDecalPlugin,
225
SyncComponentPlugin::<DirectionalLight, Self>::default(),
226
SyncComponentPlugin::<PointLight, Self>::default(),
227
SyncComponentPlugin::<SpotLight, Self>::default(),
228
SyncComponentPlugin::<AmbientLight, Self>::default(),
229
))
230
.add_plugins((ScatteringMediumPlugin, AtmospherePlugin));
231
232
if self.gltf_render_enabled {
233
#[cfg(target_family = "wasm")]
234
bevy_tasks::block_on(async {
235
app.world_mut()
236
.resource_mut::<GltfExtensionHandlers>()
237
.0
238
.write()
239
.await
240
.push(Box::new(GltfExtensionHandlerPbr))
241
});
242
243
#[cfg(not(target_family = "wasm"))]
244
app.world_mut()
245
.resource_mut::<GltfExtensionHandlers>()
246
.0
247
.write_blocking()
248
.push(Box::new(GltfExtensionHandlerPbr));
249
}
250
251
if self.add_default_deferred_lighting_plugin {
252
app.add_plugins(DeferredPbrLightingPlugin);
253
}
254
255
// Initialize the default material handle.
256
app.world_mut()
257
.resource_mut::<Assets<StandardMaterial>>()
258
.insert(
259
&Handle::<StandardMaterial>::default(),
260
StandardMaterial {
261
base_color: Color::srgb(1.0, 0.0, 0.5),
262
..Default::default()
263
},
264
)
265
.unwrap();
266
267
let has_bluenoise = app
268
.get_sub_app(RenderApp)
269
.is_some_and(|render_app| render_app.world().is_resource_added::<Bluenoise>());
270
271
if !has_bluenoise {
272
let mut images = app.world_mut().resource_mut::<Assets<Image>>();
273
#[cfg(feature = "bluenoise_texture")]
274
let handle = {
275
let image = Image::from_buffer(
276
include_bytes!("bluenoise/stbn.ktx2"),
277
ImageType::Extension("ktx2"),
278
CompressedImageFormats::NONE,
279
false,
280
ImageSampler::Default,
281
RenderAssetUsages::RENDER_WORLD,
282
)
283
.expect("Failed to decode embedded blue-noise texture");
284
images.add(image)
285
};
286
287
#[cfg(not(feature = "bluenoise_texture"))]
288
let handle = { images.add(stbn_placeholder()) };
289
290
if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
291
render_app
292
.world_mut()
293
.insert_resource(Bluenoise { texture: handle });
294
}
295
}
296
297
let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
298
return;
299
};
300
301
// Extract the required data from the main world
302
render_app
303
.add_systems(
304
RenderStartup,
305
(
306
init_shadow_samplers,
307
init_global_clusterable_object_meta,
308
init_fallback_bindless_resources,
309
),
310
)
311
.add_systems(
312
ExtractSchedule,
313
(
314
extract_clusters,
315
extract_lights,
316
extract_ambient_light_resource,
317
extract_ambient_light,
318
extract_shadow_filtering_method,
319
late_sweep_material_instances,
320
),
321
)
322
.add_systems(
323
Render,
324
(
325
prepare_lights
326
.in_set(RenderSystems::ManageViews)
327
.after(sort_cameras),
328
prepare_clusters.in_set(RenderSystems::PrepareResources),
329
),
330
)
331
.init_resource::<LightMeta>()
332
.init_resource::<RenderMaterialBindings>();
333
334
render_app.world_mut().add_observer(add_light_view_entities);
335
render_app
336
.world_mut()
337
.add_observer(remove_light_view_entities);
338
render_app.world_mut().add_observer(extracted_light_removed);
339
340
render_app.add_systems(
341
Core3d,
342
(
343
shadow_pass::<EARLY_SHADOW_PASS>
344
.after(early_prepass_build_indirect_parameters)
345
.before(early_downsample_depth)
346
.before(shadow_pass::<LATE_SHADOW_PASS>),
347
shadow_pass::<LATE_SHADOW_PASS>
348
.after(late_prepass_build_indirect_parameters)
349
.before(main_build_indirect_parameters)
350
.before(Core3dSystems::MainPass),
351
),
352
);
353
}
354
355
fn finish(&self, app: &mut App) {
356
let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
357
return;
358
};
359
360
let global_cluster_settings = make_global_cluster_settings(render_app.world());
361
app.insert_resource(global_cluster_settings);
362
}
363
}
364
365
pub fn stbn_placeholder() -> Image {
366
let format = TextureFormat::Rgba8Unorm;
367
let data = vec![255, 0, 255, 255];
368
Image {
369
data: Some(data),
370
data_order: TextureDataOrder::default(),
371
texture_descriptor: TextureDescriptor {
372
size: Extent3d::default(),
373
format,
374
dimension: TextureDimension::D2,
375
label: None,
376
mip_level_count: 1,
377
sample_count: 1,
378
usage: TextureUsages::TEXTURE_BINDING,
379
view_formats: &[],
380
},
381
sampler: ImageSampler::Default,
382
texture_view_descriptor: None,
383
asset_usage: RenderAssetUsages::RENDER_WORLD,
384
copy_on_resize: false,
385
}
386
}
387
388
fn standard_material_from_gltf_material(material: &GltfMaterial) -> StandardMaterial {
389
StandardMaterial {
390
base_color: material.base_color,
391
base_color_channel: material.base_color_channel.clone(),
392
base_color_texture: material.base_color_texture.clone(),
393
emissive: material.emissive,
394
emissive_channel: material.emissive_channel.clone(),
395
emissive_texture: material.emissive_texture.clone(),
396
perceptual_roughness: material.perceptual_roughness,
397
metallic: material.metallic,
398
metallic_roughness_channel: material.metallic_roughness_channel.clone(),
399
metallic_roughness_texture: material.metallic_roughness_texture.clone(),
400
reflectance: material.reflectance,
401
specular_tint: material.specular_tint,
402
specular_transmission: material.specular_transmission,
403
#[cfg(feature = "pbr_transmission_textures")]
404
specular_transmission_channel: material.specular_transmission_channel.clone(),
405
#[cfg(feature = "pbr_transmission_textures")]
406
specular_transmission_texture: material.specular_transmission_texture.clone(),
407
thickness: material.thickness,
408
#[cfg(feature = "pbr_transmission_textures")]
409
thickness_channel: material.thickness_channel.clone(),
410
#[cfg(feature = "pbr_transmission_textures")]
411
thickness_texture: material.thickness_texture.clone(),
412
ior: material.ior,
413
attenuation_distance: material.attenuation_distance,
414
attenuation_color: material.attenuation_color,
415
normal_map_channel: material.normal_map_channel.clone(),
416
normal_map_texture: material.normal_map_texture.clone(),
417
occlusion_channel: material.occlusion_channel.clone(),
418
occlusion_texture: material.occlusion_texture.clone(),
419
#[cfg(feature = "pbr_specular_textures")]
420
specular_channel: material.specular_channel.clone(),
421
#[cfg(feature = "pbr_specular_textures")]
422
specular_texture: material.specular_texture.clone(),
423
#[cfg(feature = "pbr_specular_textures")]
424
specular_tint_channel: material.specular_tint_channel.clone(),
425
#[cfg(feature = "pbr_specular_textures")]
426
specular_tint_texture: material.specular_tint_texture.clone(),
427
clearcoat: material.clearcoat,
428
clearcoat_perceptual_roughness: material.clearcoat_perceptual_roughness,
429
#[cfg(feature = "pbr_multi_layer_material_textures")]
430
clearcoat_roughness_channel: material.clearcoat_roughness_channel.clone(),
431
#[cfg(feature = "pbr_multi_layer_material_textures")]
432
clearcoat_roughness_texture: material.clearcoat_roughness_texture.clone(),
433
#[cfg(feature = "pbr_multi_layer_material_textures")]
434
clearcoat_normal_channel: material.clearcoat_normal_channel.clone(),
435
#[cfg(feature = "pbr_multi_layer_material_textures")]
436
clearcoat_normal_texture: material.clearcoat_normal_texture.clone(),
437
anisotropy_strength: material.anisotropy_strength,
438
anisotropy_rotation: material.anisotropy_rotation,
439
#[cfg(feature = "pbr_anisotropy_texture")]
440
anisotropy_channel: material.anisotropy_channel.clone(),
441
#[cfg(feature = "pbr_anisotropy_texture")]
442
anisotropy_texture: material.anisotropy_texture.clone(),
443
double_sided: material.double_sided,
444
cull_mode: material.cull_mode,
445
unlit: material.unlit,
446
alpha_mode: material.alpha_mode,
447
uv_transform: material.uv_transform,
448
..Default::default()
449
}
450
}
451
452
#[derive(Default, Clone)]
453
struct GltfExtensionHandlerPbr;
454
455
impl GltfExtensionHandler for GltfExtensionHandlerPbr {
456
fn dyn_clone(&self) -> Box<dyn GltfExtensionHandler> {
457
Box::new((*self).clone())
458
}
459
fn on_root(&mut self, load_context: &mut LoadContext<'_>, _gltf: &gltf::Gltf) {
460
// create the `StandardMaterial` for the glTF `DefaultMaterial` so
461
// it can be accessed when meshes don't have materials.
462
let std_label = format!("{}#std", GltfAssetLabel::DefaultMaterial);
463
464
load_context.add_labeled_asset(
465
std_label,
466
standard_material_from_gltf_material(&GltfMaterial::default()),
467
);
468
}
469
470
fn on_material(
471
&mut self,
472
load_context: &mut LoadContext<'_>,
473
_gltf_material: &gltf::Material,
474
_material: Handle<GltfMaterial>,
475
material_asset: &GltfMaterial,
476
material_label: &str,
477
) {
478
let std_label = format!("{}#std", material_label);
479
480
load_context.add_labeled_asset(
481
std_label,
482
standard_material_from_gltf_material(material_asset),
483
);
484
}
485
486
fn on_spawn_mesh_and_material(
487
&mut self,
488
load_context: &mut LoadContext<'_>,
489
_primitive: &gltf::Primitive,
490
_mesh: &gltf::Mesh,
491
_material: &gltf::Material,
492
entity: &mut EntityWorldMut,
493
material_label: &str,
494
) {
495
let std_label = format!("{}#std", material_label);
496
let handle = load_context.get_label_handle::<StandardMaterial>(std_label);
497
498
entity.insert(MeshMaterial3d(handle));
499
}
500
}
501
502
impl SyncComponent<PbrPlugin> for DirectionalLight {
503
type Out = Self;
504
}
505
impl SyncComponent<PbrPlugin> for PointLight {
506
type Out = Self;
507
}
508
impl SyncComponent<PbrPlugin> for SpotLight {
509
type Out = Self;
510
}
511
impl SyncComponent<PbrPlugin> for AmbientLight {
512
type Out = Self;
513
}
514
impl SyncComponent<PbrPlugin> for ShadowFilteringMethod {
515
type Out = Self;
516
}
517
518