From 882973a5288837deffd3da2f500d5af0ba8901d2 Mon Sep 17 00:00:00 2001 From: Josiah Putman Date: Tue, 13 Aug 2024 08:01:42 -0700 Subject: [PATCH] Expose max_mip_dimension and uv_offset in BloomSettings. (#14512) # Objective By default, Bevy's bloom effect shows square artifacts on small bright particles due to a low max mip resolution. This PR makes this configurable via BloomSettings so users can customize these parameters instead of having them in private module constants. ## Solution Expose max_mip_dimension and uv_offset in BloomSettings. ## Testing I tested these changes by running the Bloom 2D / 3D examples. --------- Co-authored-by: Alice Cecile --- crates/bevy_core_pipeline/src/bloom/bloom.wgsl | 7 ++++--- .../src/bloom/downsampling_pipeline.rs | 1 + crates/bevy_core_pipeline/src/bloom/mod.rs | 12 ++++-------- .../bevy_core_pipeline/src/bloom/settings.rs | 18 ++++++++++++++++++ 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/crates/bevy_core_pipeline/src/bloom/bloom.wgsl b/crates/bevy_core_pipeline/src/bloom/bloom.wgsl index 8234b72213690..0b10333192382 100644 --- a/crates/bevy_core_pipeline/src/bloom/bloom.wgsl +++ b/crates/bevy_core_pipeline/src/bloom/bloom.wgsl @@ -10,6 +10,7 @@ struct BloomUniforms { threshold_precomputations: vec4, viewport: vec4, aspect: f32, + uv_offset: f32 }; @group(0) @binding(0) var input_texture: texture_2d; @@ -94,9 +95,9 @@ fn sample_input_13_tap(uv: vec2) -> vec3 { // [COD] slide 162 fn sample_input_3x3_tent(uv: vec2) -> vec3 { - // Radius. Empirically chosen by and tweaked from the LearnOpenGL article. - let x = 0.004 / uniforms.aspect; - let y = 0.004; + // UV offsets configured from uniforms. + let x = uniforms.uv_offset / uniforms.aspect; + let y = uniforms.uv_offset; let a = textureSample(input_texture, s, vec2(uv.x - x, uv.y + y)).rgb; let b = textureSample(input_texture, s, vec2(uv.x, uv.y + y)).rgb; diff --git a/crates/bevy_core_pipeline/src/bloom/downsampling_pipeline.rs b/crates/bevy_core_pipeline/src/bloom/downsampling_pipeline.rs index 736ebeaf24288..ba48e4b0fe78b 100644 --- a/crates/bevy_core_pipeline/src/bloom/downsampling_pipeline.rs +++ b/crates/bevy_core_pipeline/src/bloom/downsampling_pipeline.rs @@ -41,6 +41,7 @@ pub struct BloomUniforms { pub threshold_precomputations: Vec4, pub viewport: Vec4, pub aspect: f32, + pub uv_offset: f32, } impl FromWorld for BloomDownsamplingPipeline { diff --git a/crates/bevy_core_pipeline/src/bloom/mod.rs b/crates/bevy_core_pipeline/src/bloom/mod.rs index 064cd47c8e34b..b5c4c6b72c524 100644 --- a/crates/bevy_core_pipeline/src/bloom/mod.rs +++ b/crates/bevy_core_pipeline/src/bloom/mod.rs @@ -38,10 +38,6 @@ const BLOOM_SHADER_HANDLE: Handle = Handle::weak_from_u128(9295994769239 const BLOOM_TEXTURE_FORMAT: TextureFormat = TextureFormat::Rg11b10Float; -// Maximum size of each dimension for the largest mipchain texture used in downscaling/upscaling. -// 512 behaves well with the UV offset of 0.004 used in bloom.wgsl -const MAX_MIP_DIMENSION: u32 = 512; - pub struct BloomPlugin; impl Plugin for BloomPlugin { @@ -328,18 +324,18 @@ fn prepare_bloom_textures( mut commands: Commands, mut texture_cache: ResMut, render_device: Res, - views: Query<(Entity, &ExtractedCamera), With>, + views: Query<(Entity, &ExtractedCamera, &BloomSettings)>, ) { - for (entity, camera) in &views { + for (entity, camera, settings) in &views { if let Some(UVec2 { x: width, y: height, }) = camera.physical_viewport_size { // How many times we can halve the resolution minus one so we don't go unnecessarily low - let mip_count = MAX_MIP_DIMENSION.ilog2().max(2) - 1; + let mip_count = settings.max_mip_dimension.ilog2().max(2) - 1; let mip_height_ratio = if height != 0 { - MAX_MIP_DIMENSION as f32 / height as f32 + settings.max_mip_dimension as f32 / height as f32 } else { 0. }; diff --git a/crates/bevy_core_pipeline/src/bloom/settings.rs b/crates/bevy_core_pipeline/src/bloom/settings.rs index 055f66c8d2d6a..8fe66282144d1 100644 --- a/crates/bevy_core_pipeline/src/bloom/settings.rs +++ b/crates/bevy_core_pipeline/src/bloom/settings.rs @@ -102,9 +102,20 @@ pub struct BloomSettings { /// configured in a non-energy-conserving way, /// otherwise set to [`BloomCompositeMode::EnergyConserving`]. pub composite_mode: BloomCompositeMode, + + /// Maximum size of each dimension for the largest mipchain texture used in downscaling/upscaling. + /// Only tweak if you are seeing visual artifacts. + pub max_mip_dimension: u32, + + /// UV offset for bloom shader. Ideally close to 2.0 / `max_mip_dimension`. + /// Only tweak if you are seeing visual artifacts. + pub uv_offset: f32, } impl BloomSettings { + const DEFAULT_MAX_MIP_DIMENSION: u32 = 512; + const DEFAULT_UV_OFFSET: f32 = 0.004; + /// The default bloom preset. /// /// This uses the [`EnergyConserving`](BloomCompositeMode::EnergyConserving) composite mode. @@ -118,6 +129,8 @@ impl BloomSettings { threshold_softness: 0.0, }, composite_mode: BloomCompositeMode::EnergyConserving, + max_mip_dimension: Self::DEFAULT_MAX_MIP_DIMENSION, + uv_offset: Self::DEFAULT_UV_OFFSET, }; /// A preset that's similar to how older games did bloom. @@ -131,6 +144,8 @@ impl BloomSettings { threshold_softness: 0.2, }, composite_mode: BloomCompositeMode::Additive, + max_mip_dimension: Self::DEFAULT_MAX_MIP_DIMENSION, + uv_offset: Self::DEFAULT_UV_OFFSET, }; /// A preset that applies a very strong bloom, and blurs the whole screen. @@ -144,6 +159,8 @@ impl BloomSettings { threshold_softness: 0.0, }, composite_mode: BloomCompositeMode::EnergyConserving, + max_mip_dimension: Self::DEFAULT_MAX_MIP_DIMENSION, + uv_offset: Self::DEFAULT_UV_OFFSET, }; } @@ -213,6 +230,7 @@ impl ExtractComponent for BloomSettings { / UVec4::new(target_size.x, target_size.y, target_size.x, target_size.y) .as_vec4(), aspect: AspectRatio::from_pixels(size.x, size.y).into(), + uv_offset: settings.uv_offset, }; Some((settings.clone(), uniform))