Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 0 additions & 11 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2456,17 +2456,6 @@ name = "fallback_image"
path = "examples/shader/fallback_image.rs"
doc-scrape-examples = true

[[example]]
name = "reflection_probes"
path = "examples/3d/reflection_probes.rs"
doc-scrape-examples = true

[package.metadata.example.reflection_probes]
name = "Reflection Probes"
description = "Demonstrates reflection probes"
category = "3D Rendering"
wasm = false

[package.metadata.example.fallback_image]
hidden = true

Expand Down
Binary file not shown.
Binary file removed assets/models/cubes/Cubes.glb
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
@group(0) @binding(3) var dt_lut_texture: texture_3d<f32>;
@group(0) @binding(4) var dt_lut_sampler: sampler;
#else
@group(0) @binding(16) var dt_lut_texture: texture_3d<f32>;
@group(0) @binding(17) var dt_lut_sampler: sampler;
@group(0) @binding(15) var dt_lut_texture: texture_3d<f32>;
@group(0) @binding(16) var dt_lut_sampler: sampler;
#endif

fn sample_current_lut(p: vec3<f32>) -> vec3<f32> {
Expand Down
5 changes: 1 addition & 4 deletions crates/bevy_internal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,7 @@ symphonia-vorbis = ["bevy_audio/symphonia-vorbis"]
symphonia-wav = ["bevy_audio/symphonia-wav"]

# Shader formats
shader_format_glsl = [
"bevy_render/shader_format_glsl",
"bevy_pbr?/shader_format_glsl",
]
shader_format_glsl = ["bevy_render/shader_format_glsl"]
shader_format_spirv = ["bevy_render/shader_format_spirv"]

serialize = [
Expand Down
12 changes: 1 addition & 11 deletions crates/bevy_pbr/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ keywords = ["bevy"]

[features]
webgl = []
shader_format_glsl = ["naga_oil/glsl"]
pbr_transmission_textures = []

[dependencies]
Expand All @@ -35,17 +34,8 @@ fixedbitset = "0.4"
# direct dependency required for derive macro
bytemuck = { version = "1", features = ["derive"] }
radsort = "0.1"
smallvec = "1.6"
naga_oil = "0.11"
thread_local = "1.0"

[target.'cfg(target_arch = "wasm32")'.dependencies]
naga_oil = { version = "0.11" }

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
# Omit the `glsl` feature in non-WebAssembly by default.
naga_oil = { version = "0.11", default-features = false, features = [
"test_shader",
] }

[lints]
workspace = true
44 changes: 24 additions & 20 deletions crates/bevy_pbr/src/deferred/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use crate::{
environment_map::RenderViewEnvironmentMaps, MeshPipeline, MeshViewBindGroup,
ScreenSpaceAmbientOcclusionSettings, ViewLightProbesUniformOffset,
};
use crate::{MeshPipeline, MeshViewBindGroup, ScreenSpaceAmbientOcclusionSettings};
use bevy_app::prelude::*;
use bevy_asset::{load_internal_asset, Handle};
use bevy_core_pipeline::{
Expand All @@ -17,17 +14,25 @@ use bevy_render::{
extract_component::{
ComponentUniforms, ExtractComponent, ExtractComponentPlugin, UniformComponentPlugin,
},
render_graph::{NodeRunError, RenderGraphApp, RenderGraphContext, ViewNode, ViewNodeRunner},
render_resource::binding_types::uniform_buffer,
render_resource::*,
render_asset::RenderAssets,
render_graph::{NodeRunError, RenderGraphContext, ViewNode, ViewNodeRunner},
render_resource::{
binding_types::uniform_buffer, Operations, PipelineCache, RenderPassDescriptor,
},
renderer::{RenderContext, RenderDevice},
texture::BevyDefault,
view::{ExtractedView, ViewTarget, ViewUniformOffset},
Render, RenderApp, RenderSet,
texture::Image,
view::{ViewTarget, ViewUniformOffset},
Render, RenderSet,
};

use bevy_render::{
render_graph::RenderGraphApp, render_resource::*, texture::BevyDefault, view::ExtractedView,
RenderApp,
};

use crate::{
MeshPipelineKey, ShadowFilteringMethod, ViewFogUniformOffset, ViewLightsUniformOffset,
EnvironmentMapLight, MeshPipelineKey, ShadowFilteringMethod, ViewFogUniformOffset,
ViewLightsUniformOffset,
};

pub struct DeferredPbrLightingPlugin;
Expand Down Expand Up @@ -146,7 +151,6 @@ impl ViewNode for DeferredOpaquePass3dPbrLightingNode {
&'static ViewUniformOffset,
&'static ViewLightsUniformOffset,
&'static ViewFogUniformOffset,
&'static ViewLightProbesUniformOffset,
&'static MeshViewBindGroup,
&'static ViewTarget,
&'static DeferredLightingIdDepthTexture,
Expand All @@ -161,7 +165,6 @@ impl ViewNode for DeferredOpaquePass3dPbrLightingNode {
view_uniform_offset,
view_lights_offset,
view_fog_offset,
view_light_probes_offset,
mesh_view_bind_group,
target,
deferred_lighting_id_depth_texture,
Expand Down Expand Up @@ -215,7 +218,6 @@ impl ViewNode for DeferredOpaquePass3dPbrLightingNode {
view_uniform_offset.offset,
view_lights_offset.offset,
view_fog_offset.offset,
**view_light_probes_offset,
],
);
render_pass.set_bind_group(1, &bind_group_1, &[]);
Expand Down Expand Up @@ -401,27 +403,28 @@ pub fn prepare_deferred_lighting_pipelines(
&ExtractedView,
Option<&Tonemapping>,
Option<&DebandDither>,
Option<&EnvironmentMapLight>,
Option<&ShadowFilteringMethod>,
Has<ScreenSpaceAmbientOcclusionSettings>,
(
Has<NormalPrepass>,
Has<DepthPrepass>,
Has<MotionVectorPrepass>,
),
Has<RenderViewEnvironmentMaps>,
),
With<DeferredPrepass>,
>,
images: Res<RenderAssets<Image>>,
) {
for (
entity,
view,
tonemapping,
dither,
environment_map,
shadow_filter_method,
ssao,
(normal_prepass, depth_prepass, motion_vector_prepass),
has_environment_maps,
) in &views
{
let mut view_key = MeshPipelineKey::from_hdr(view.hdr);
Expand Down Expand Up @@ -468,10 +471,11 @@ pub fn prepare_deferred_lighting_pipelines(
view_key |= MeshPipelineKey::SCREEN_SPACE_AMBIENT_OCCLUSION;
}

// We don't need to check to see whether the environment map is loaded
// because [`gather_light_probes`] already checked that for us before
// adding the [`RenderViewEnvironmentMaps`] component.
if has_environment_maps {
let environment_map_loaded = match environment_map {
Some(environment_map) => environment_map.is_loaded(&images),
None => false,
};
if environment_map_loaded {
view_key |= MeshPipelineKey::ENVIRONMENT_MAP;
}

Expand Down
50 changes: 50 additions & 0 deletions crates/bevy_pbr/src/environment_map/environment_map.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#define_import_path bevy_pbr::environment_map

#import bevy_pbr::mesh_view_bindings as bindings;

struct EnvironmentMapLight {
diffuse: vec3<f32>,
specular: vec3<f32>,
};

fn environment_map_light(
perceptual_roughness: f32,
roughness: f32,
diffuse_color: vec3<f32>,
NdotV: f32,
f_ab: vec2<f32>,
N: vec3<f32>,
R: vec3<f32>,
F0: vec3<f32>,
) -> EnvironmentMapLight {

// Split-sum approximation for image based lighting: https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf
// Technically we could use textureNumLevels(environment_map_specular) - 1 here, but we use a uniform
// because textureNumLevels() does not work on WebGL2
let radiance_level = perceptual_roughness * f32(bindings::lights.environment_map_smallest_specular_mip_level);
let irradiance = textureSampleLevel(bindings::environment_map_diffuse, bindings::environment_map_sampler, vec3(N.xy, -N.z), 0.0).rgb;
let radiance = textureSampleLevel(bindings::environment_map_specular, bindings::environment_map_sampler, vec3(R.xy, -R.z), radiance_level).rgb;

// No real world material has specular values under 0.02, so we use this range as a
// "pre-baked specular occlusion" that extinguishes the fresnel term, for artistic control.
// See: https://google.github.io/filament/Filament.html#specularocclusion
let specular_occlusion = saturate(dot(F0, vec3(50.0 * 0.33)));

// Multiscattering approximation: https://www.jcgt.org/published/0008/01/03/paper.pdf
// Useful reference: https://bruop.github.io/ibl
let Fr = max(vec3(1.0 - roughness), F0) - F0;
let kS = F0 + Fr * pow(1.0 - NdotV, 5.0);
let Ess = f_ab.x + f_ab.y;
let FssEss = kS * Ess * specular_occlusion;
let Ems = 1.0 - Ess;
let Favg = F0 + (1.0 - F0) / 21.0;
let Fms = FssEss * Favg / (1.0 - Ems * Favg);
let FmsEms = Fms * Ems;
let Edss = 1.0 - (FssEss + FmsEms);
let kD = diffuse_color * Edss;

var out: EnvironmentMapLight;
out.diffuse = (FmsEms + kD) * irradiance;
out.specular = FssEss * radiance;
return out;
}
91 changes: 91 additions & 0 deletions crates/bevy_pbr/src/environment_map/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
use bevy_app::{App, Plugin};
use bevy_asset::{load_internal_asset, Handle};
use bevy_core_pipeline::prelude::Camera3d;
use bevy_ecs::{prelude::Component, query::With};
use bevy_reflect::Reflect;
use bevy_render::{
extract_component::{ExtractComponent, ExtractComponentPlugin},
render_asset::RenderAssets,
render_resource::{
binding_types::{sampler, texture_cube},
*,
},
texture::{FallbackImageCubemap, Image},
};

pub const ENVIRONMENT_MAP_SHADER_HANDLE: Handle<Shader> =
Handle::weak_from_u128(154476556247605696);

pub struct EnvironmentMapPlugin;

impl Plugin for EnvironmentMapPlugin {
fn build(&self, app: &mut App) {
load_internal_asset!(
app,
ENVIRONMENT_MAP_SHADER_HANDLE,
"environment_map.wgsl",
Shader::from_wgsl
);

app.register_type::<EnvironmentMapLight>()
.add_plugins(ExtractComponentPlugin::<EnvironmentMapLight>::default());
}
}

/// Environment map based ambient lighting representing light from distant scenery.
///
/// When added to a 3D camera, this component adds indirect light
/// to every point of the scene (including inside, enclosed areas) based on
/// an environment cubemap texture. This is similar to [`crate::AmbientLight`], but
/// higher quality, and is intended for outdoor scenes.
///
/// The environment map must be prefiltered into a diffuse and specular cubemap based on the
/// [split-sum approximation](https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf).
///
/// To prefilter your environment map, you can use `KhronosGroup`'s [glTF-IBL-Sampler](https://github.com/KhronosGroup/glTF-IBL-Sampler).
/// The diffuse map uses the Lambertian distribution, and the specular map uses the GGX distribution.
///
/// `KhronosGroup` also has several prefiltered environment maps that can be found [here](https://github.com/KhronosGroup/glTF-Sample-Environments).
#[derive(Component, Reflect, Clone, ExtractComponent)]
#[extract_component_filter(With<Camera3d>)]
pub struct EnvironmentMapLight {
pub diffuse_map: Handle<Image>,
pub specular_map: Handle<Image>,
}

impl EnvironmentMapLight {
/// Whether or not all textures necessary to use the environment map
/// have been loaded by the asset server.
pub fn is_loaded(&self, images: &RenderAssets<Image>) -> bool {
images.get(&self.diffuse_map).is_some() && images.get(&self.specular_map).is_some()
}
}

pub fn get_bindings<'a>(
environment_map_light: Option<&EnvironmentMapLight>,
images: &'a RenderAssets<Image>,
fallback_image_cubemap: &'a FallbackImageCubemap,
) -> (&'a TextureView, &'a TextureView, &'a Sampler) {
let (diffuse_map, specular_map) = match (
environment_map_light.and_then(|env_map| images.get(&env_map.diffuse_map)),
environment_map_light.and_then(|env_map| images.get(&env_map.specular_map)),
) {
(Some(diffuse_map), Some(specular_map)) => {
(&diffuse_map.texture_view, &specular_map.texture_view)
}
_ => (
&fallback_image_cubemap.texture_view,
&fallback_image_cubemap.texture_view,
),
};

(diffuse_map, specular_map, &fallback_image_cubemap.sampler)
}

pub fn get_bind_group_layout_entries() -> [BindGroupLayoutEntryBuilder; 3] {
[
texture_cube(TextureSampleType::Float { filterable: true }),
texture_cube(TextureSampleType::Float { filterable: true }),
sampler(SamplerBindingType::Filtering),
]
}
12 changes: 5 additions & 7 deletions crates/bevy_pbr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ pub mod wireframe;
mod alpha;
mod bundle;
pub mod deferred;
mod environment_map;
mod extended_material;
mod fog;
mod light;
mod light_probe;
mod lightmap;
mod material;
mod parallax;
Expand All @@ -17,10 +17,10 @@ mod ssao;

pub use alpha::*;
pub use bundle::*;
pub use environment_map::EnvironmentMapLight;
pub use extended_material::*;
pub use fog::*;
pub use light::*;
pub use light_probe::*;
pub use lightmap::*;
pub use material::*;
pub use parallax::*;
Expand All @@ -37,12 +37,9 @@ pub mod prelude {
DirectionalLightBundle, MaterialMeshBundle, PbrBundle, PointLightBundle,
SpotLightBundle,
},
environment_map::EnvironmentMapLight,
fog::{FogFalloff, FogSettings},
light::{AmbientLight, DirectionalLight, PointLight, SpotLight},
light_probe::{
environment_map::{EnvironmentMapLight, ReflectionProbeBundle},
LightProbe,
},
material::{Material, MaterialPlugin},
parallax::ParallaxMappingMethod,
pbr_material::StandardMaterial,
Expand Down Expand Up @@ -74,6 +71,7 @@ use bevy_render::{
ExtractSchedule, Render, RenderApp, RenderSet,
};
use bevy_transform::TransformSystem;
use environment_map::EnvironmentMapPlugin;

use crate::deferred::DeferredPbrLightingPlugin;

Expand Down Expand Up @@ -257,12 +255,12 @@ impl Plugin for PbrPlugin {
..Default::default()
},
ScreenSpaceAmbientOcclusionPlugin,
EnvironmentMapPlugin,
ExtractResourcePlugin::<AmbientLight>::default(),
FogPlugin,
ExtractResourcePlugin::<DefaultOpaqueRendererMethod>::default(),
ExtractComponentPlugin::<ShadowFilteringMethod>::default(),
LightmapPlugin,
LightProbePlugin,
))
.configure_sets(
PostUpdate,
Expand Down
Loading