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
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,9 @@ gltf_convert_coordinates_default = [
# Enable collecting debug information about systems and components to help with diagnostics
debug = ["bevy_internal/debug"]

# Include spatio-temporal blue noise KTX2 file used by generated environment maps
bluenoise_texture = ["bevy_internal/bluenoise_texture", "ktx2", "bevy_image/zstd"]

[dependencies]
bevy_internal = { path = "crates/bevy_internal", version = "0.17.0-dev", default-features = false }
tracing = { version = "0.1", default-features = false, optional = true }
Expand Down
2 changes: 2 additions & 0 deletions crates/bevy_internal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ statically-linked-dxc = ["bevy_render/statically-linked-dxc"]

# Include tonemapping LUT KTX2 files.
tonemapping_luts = ["bevy_core_pipeline/tonemapping_luts"]
# Include Bluenoise texture for environment map generation.
bluenoise_texture = ["bevy_pbr?/bluenoise_texture"]

# Include SMAA LUT KTX2 Files
smaa_luts = ["bevy_anti_aliasing/smaa_luts"]
Expand Down
1 change: 1 addition & 0 deletions crates/bevy_pbr/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ experimental_pbr_pcss = ["bevy_light/experimental_pbr_pcss"]
pbr_specular_textures = []
pbr_clustered_decals = []
pbr_light_textures = []
bluenoise_texture = ["bevy_render/ktx2", "bevy_image/ktx2", "bevy_image/zstd"]
shader_format_glsl = ["bevy_render/shader_format_glsl"]
trace = ["bevy_render/trace"]
# Enables the meshlet renderer for dense high-poly scenes (experimental)
Expand Down
File renamed without changes.
76 changes: 64 additions & 12 deletions crates/bevy_pbr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,18 +133,23 @@ pub mod graph {

use crate::{deferred::DeferredPbrLightingPlugin, graph::NodePbr};
use bevy_app::prelude::*;
use bevy_asset::{io::embedded::GetAssetServer, AssetApp, AssetPath, Assets, Handle};
use bevy_asset::{AssetApp, AssetPath, Assets, Handle, RenderAssetUsages};
use bevy_core_pipeline::core_3d::graph::{Core3d, Node3d};
use bevy_ecs::prelude::*;
use bevy_image::Image;
#[cfg(feature = "bluenoise_texture")]
use bevy_image::{CompressedImageFormats, ImageSampler, ImageType};
use bevy_image::{Image, ImageSampler};
use bevy_render::{
alpha::AlphaMode,
camera::{sort_cameras, Projection},
extract_component::ExtractComponentPlugin,
extract_resource::ExtractResourcePlugin,
load_shader_library,
render_graph::RenderGraph,
render_resource::ShaderRef,
render_resource::{
Extent3d, ShaderRef, TextureDataOrder, TextureDescriptor, TextureDimension, TextureFormat,
TextureUsages,
},
sync_component::SyncComponentPlugin,
ExtractSchedule, Render, RenderApp, RenderDebugFlags, RenderStartup, RenderSystems,
};
Expand Down Expand Up @@ -186,20 +191,12 @@ impl Default for PbrPlugin {
}

/// A resource that stores the spatio-temporal blue noise texture.
#[derive(Resource, Clone)]
#[derive(Resource)]
pub struct Bluenoise {
/// Texture handle for spatio-temporal blue noise
pub texture: Handle<Image>,
}

impl FromWorld for Bluenoise {
fn from_world(world: &mut World) -> Self {
Self {
texture: world.get_asset_server().load("textures/stbn.ktx2"),
}
}
}

impl Plugin for PbrPlugin {
fn build(&self, app: &mut App) {
load_shader_library!(app, "render/pbr_types.wgsl");
Expand Down Expand Up @@ -288,6 +285,38 @@ impl Plugin for PbrPlugin {
},
);

let has_bluenoise = if let Some(render_app) = app.get_sub_app(RenderApp) {
render_app.world().is_resource_added::<Bluenoise>()
} else {
true
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this true here?

};

if !has_bluenoise {
let mut images = app.world_mut().resource_mut::<Assets<Image>>();
#[cfg(feature = "bluenoise_texture")]
let handle = {
let image = Image::from_buffer(
include_bytes!("bluenoise/stbn.ktx2"),
ImageType::Extension("ktx2"),
CompressedImageFormats::NONE,
false,
ImageSampler::Default,
RenderAssetUsages::RENDER_WORLD,
)
.expect("Failed to decode embedded blue-noise texture");
images.add(image)
};

#[cfg(not(feature = "bluenoise_texture"))]
let handle = { images.add(stbn_placeholder()) };

if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
render_app
.world_mut()
.insert_resource(Bluenoise { texture: handle });
}
}

let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
return;
};
Expand Down Expand Up @@ -350,3 +379,26 @@ impl Plugin for PbrPlugin {
app.insert_resource(global_cluster_settings);
}
}

pub fn stbn_placeholder() -> Image {
let format = TextureFormat::Rgba8Unorm;
let data = vec![255, 0, 255, 255];
Image {
data: Some(data),
data_order: TextureDataOrder::default(),
texture_descriptor: TextureDescriptor {
size: Extent3d::default(),
format,
dimension: TextureDimension::D2,
label: None,
mip_level_count: 1,
sample_count: 1,
usage: TextureUsages::TEXTURE_BINDING,
view_formats: &[],
},
sampler: ImageSampler::Default,
texture_view_descriptor: None,
asset_usage: RenderAssetUsages::RENDER_WORLD,
copy_on_resize: false,
}
}
11 changes: 10 additions & 1 deletion crates/bevy_pbr/src/light_probe/environment_filter.wgsl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#import bevy_render::maths::PI
#import bevy_pbr::{
lighting,
utils::{sample_cosine_hemisphere, dir_to_cube_uv, sample_cube_dir, hammersley_2d}
utils::{sample_cosine_hemisphere, dir_to_cube_uv, sample_cube_dir, hammersley_2d, rand_vec2f}
}

struct FilteringConstants {
Expand All @@ -24,13 +24,22 @@ fn sample_environment(dir: vec3f, level: f32) -> vec4f {
}

// Blue noise randomization
#ifdef HAS_BLUE_NOISE
fn sample_noise(pixel_coords: vec2u) -> vec4f {
let noise_size = vec2u(1) << constants.noise_size_bits;
let noise_size_mask = noise_size - vec2u(1u);
let noise_coords = pixel_coords & noise_size_mask;
let uv = vec2f(noise_coords) / vec2f(noise_size);
return textureSampleLevel(blue_noise_texture, input_sampler, uv, 0u, 0.0);
}
#else
// pseudo-random numbers using RNG
fn sample_noise(pixel_coords: vec2u) -> vec4f {
var rng_state: u32 = (pixel_coords.x * 3966231743u) ^ (pixel_coords.y * 3928936651u);
let rnd = rand_vec2f(&rng_state);
return vec4f(rnd, 0.0, 0.0);
}
#endif

// Calculate LOD for environment map lookup using filtered importance sampling
fn calculate_environment_map_lod(pdf: f32, width: f32, samples: f32) -> f32 {
Expand Down
22 changes: 17 additions & 5 deletions crates/bevy_pbr/src/light_probe/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,6 @@ impl Plugin for EnvironmentMapGenerationPlugin {
};

render_app
.init_resource::<Bluenoise>()
.add_render_graph_node::<DownsamplingNode>(Core3d, GeneratorNode::Downsampling)
.add_render_graph_node::<FilteringNode>(Core3d, GeneratorNode::Filtering)
.add_render_graph_edges(
Expand Down Expand Up @@ -366,6 +365,10 @@ pub fn initialize_generated_environment_map_resources(
if combine_bind_group {
shader_defs.push(ShaderDefVal::Int("COMBINE_BIND_GROUP".into(), 1));
}
#[cfg(feature = "bluenoise_texture")]
{
shader_defs.push(ShaderDefVal::Int("HAS_BLUE_NOISE".into(), 1));
}

let downsampling_shader = load_embedded_asset!(asset_server.as_ref(), "downsample.wgsl");
let env_filter_shader = load_embedded_asset!(asset_server.as_ref(), "environment_filter.wgsl");
Expand Down Expand Up @@ -410,7 +413,7 @@ pub fn initialize_generated_environment_map_resources(
layout: vec![layouts.radiance.clone()],
push_constant_ranges: vec![],
shader: env_filter_shader.clone(),
shader_defs: vec![],
shader_defs: shader_defs.clone(),
entry_point: Some("generate_radiance_map".into()),
zero_initialize_workgroup_memory: false,
});
Expand All @@ -421,7 +424,7 @@ pub fn initialize_generated_environment_map_resources(
layout: vec![layouts.irradiance.clone()],
push_constant_ranges: vec![],
shader: env_filter_shader,
shader_defs: vec![],
shader_defs: shader_defs.clone(),
entry_point: Some("generate_irradiance_map".into()),
zero_initialize_workgroup_memory: false,
});
Expand Down Expand Up @@ -716,6 +719,15 @@ pub fn prepare_generated_environment_map_bind_groups(
(first, second)
};

// create a 2d array view of the bluenoise texture
let stbn_texture_view = stbn_texture
.texture
.clone()
.create_view(&TextureViewDescriptor {
dimension: Some(TextureViewDimension::D2Array),
..Default::default()
});

// Create radiance map bind groups for each mip level
let num_mips = mip_count as usize;
let mut radiance_bind_groups = Vec::with_capacity(num_mips);
Expand Down Expand Up @@ -749,7 +761,7 @@ pub fn prepare_generated_environment_map_bind_groups(
&samplers.linear,
&mip_storage_view,
&radiance_constants_buffer,
&stbn_texture.texture_view,
&stbn_texture_view,
)),
);

Expand Down Expand Up @@ -786,7 +798,7 @@ pub fn prepare_generated_environment_map_bind_groups(
&samplers.linear,
&irradiance_map,
&irradiance_constants_buffer,
&stbn_texture.texture_view,
&stbn_texture_view,
)),
);

Expand Down