Skip to content

Commit 11735a2

Browse files
committed
Improve bloom add option to use faster but lower quality bloom
1 parent 11059de commit 11735a2

File tree

8 files changed

+90
-10
lines changed

8 files changed

+90
-10
lines changed

crates/bevy_post_process/src/bloom/bloom.wgsl

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,41 @@ fn karis_average(color: vec3<f32>) -> f32 {
4949
return 1.0 / (1.0 + luma);
5050
}
5151

52+
// https://www.shadertoy.com/view/mdsyDf
53+
#ifdef FAST_BLUR
54+
fn bloom_down_kernel4(uv: vec2<f32>) -> vec3<f32> {
55+
let ps = uniforms.scale / vec2<f32>(textureDimensions(input_texture));
56+
let o = 0.5 + 1.0 / 4.0;
57+
58+
let a = textureSample(input_texture, s, uv + vec2<f32>(-1.0, -1.0) * o * ps).rgb * 0.25;
59+
let b = textureSample(input_texture, s, uv + vec2<f32>(1.0, -1.0) * o * ps).rgb * 0.25;
60+
let c = textureSample(input_texture, s, uv + vec2<f32>(-1.0, 1.0) * o * ps).rgb * 0.25;
61+
let d = textureSample(input_texture, s, uv + vec2<f32>(1.0, 1.0) * o * ps).rgb * 0.25;
62+
63+
#ifdef FIRST_DOWNSAMPLE
64+
return (a + b + c + d) * karis_average(a + b + c + d);
65+
#else
66+
return a + b + c + d;
67+
#endif
68+
}
69+
70+
fn bloom_up_kernel4(uv: vec2<f32>) -> vec3<f32> {
71+
let ps = uniforms.scale / vec2<f32>(textureDimensions(input_texture));
72+
let w = vec4<f32>(0.211029, 0.288971, 0.288971, 0.211029);
73+
let l00 = vec2<f32>(0.347209, 0.526425);
74+
let l10 = vec2<f32>(0.109840, 0.334045);
75+
let l01 = vec2<f32>(0.334045, 0.109840);
76+
let l11 = vec2<f32>(0.526425, 0.347209);
77+
78+
let a = textureSample(input_texture, s, uv + (vec2<f32>( -0.5, -1.5) + l00) * ps).rgb * w.x;
79+
let b = textureSample(input_texture, s, uv + (vec2<f32>(0.5, -0.5) + l10) * ps).rgb * w.y;
80+
let c = textureSample(input_texture, s, uv + (vec2<f32>( -0.5, 0.5) + l01) * ps).rgb * w.z;
81+
let d = textureSample(input_texture, s, uv + (vec2<f32>( -1.5,-0.5) + l11) * ps).rgb * w.w;
82+
83+
return a + b + c + d;
84+
}
85+
#endif
86+
5287
// [COD] slide 153
5388
fn sample_input_13_tap(uv: vec2<f32>) -> vec3<f32> {
5489
#ifdef UNIFORM_SCALE
@@ -161,7 +196,11 @@ fn sample_input_3x3_tent(uv: vec2<f32>) -> vec3<f32> {
161196
@fragment
162197
fn downsample_first(@location(0) output_uv: vec2<f32>) -> @location(0) vec4<f32> {
163198
let sample_uv = uniforms.viewport.xy + output_uv * uniforms.viewport.zw;
199+
#ifdef FAST_BLUR
200+
var sample = bloom_down_kernel4(sample_uv);
201+
#else
164202
var sample = sample_input_13_tap(sample_uv);
203+
#endif
165204
// Lower bound of 0.0001 is to avoid propagating multiplying by 0.0 through the
166205
// downscaling and upscaling which would result in black boxes.
167206
// The upper bound is to prevent NaNs.
@@ -178,10 +217,18 @@ fn downsample_first(@location(0) output_uv: vec2<f32>) -> @location(0) vec4<f32>
178217

179218
@fragment
180219
fn downsample(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {
220+
#ifdef FAST_BLUR
221+
return vec4<f32>(bloom_down_kernel4(uv), 1.0);
222+
#else
181223
return vec4<f32>(sample_input_13_tap(uv), 1.0);
224+
#endif
182225
}
183226

184227
@fragment
185228
fn upsample(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {
229+
#ifdef FAST_BLUR
230+
return vec4<f32>(bloom_up_kernel4(uv), 1.0);
231+
#else
186232
return vec4<f32>(sample_input_3x3_tent(uv), 1.0);
233+
#endif
187234
}

crates/bevy_post_process/src/bloom/downsampling_pipeline.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ pub struct BloomDownsamplingPipelineKeys {
4040
prefilter: bool,
4141
first_downsample: bool,
4242
uniform_scale: bool,
43+
high_quality: bool,
4344
}
4445

4546
/// The uniform struct extracted from [`Bloom`] attached to a Camera.
@@ -79,8 +80,9 @@ pub fn init_bloom_downsampling_pipeline(
7980
let sampler = render_device.create_sampler(&SamplerDescriptor {
8081
min_filter: FilterMode::Linear,
8182
mag_filter: FilterMode::Linear,
82-
address_mode_u: AddressMode::ClampToEdge,
83-
address_mode_v: AddressMode::ClampToEdge,
83+
address_mode_u: AddressMode::ClampToBorder,
84+
address_mode_v: AddressMode::ClampToBorder,
85+
border_color: Some(SamplerBorderColor::TransparentBlack),
8486
..Default::default()
8587
});
8688

@@ -110,6 +112,10 @@ impl SpecializedRenderPipeline for BloomDownsamplingPipeline {
110112
shader_defs.push("FIRST_DOWNSAMPLE".into());
111113
}
112114

115+
if !key.high_quality {
116+
shader_defs.push("FAST_BLUR".into());
117+
}
118+
113119
if key.prefilter {
114120
shader_defs.push("USE_THRESHOLD".into());
115121
}
@@ -161,6 +167,7 @@ pub fn prepare_downsampling_pipeline(
161167
prefilter,
162168
first_downsample: false,
163169
uniform_scale: bloom.scale == Vec2::ONE,
170+
high_quality: bloom.high_quality,
164171
},
165172
);
166173

@@ -171,6 +178,7 @@ pub fn prepare_downsampling_pipeline(
171178
prefilter,
172179
first_downsample: true,
173180
uniform_scale: bloom.scale == Vec2::ONE,
181+
high_quality: bloom.high_quality,
174182
},
175183
);
176184

crates/bevy_post_process/src/bloom/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -362,15 +362,15 @@ fn prepare_bloom_textures(
362362
if let Some(viewport) = camera.physical_viewport_size {
363363
// How many times we can halve the resolution minus one so we don't go unnecessarily low
364364
let mip_count = bloom.max_mip_dimension.ilog2().max(2) - 1;
365-
let mip_height_ratio = if viewport.y != 0 {
366-
bloom.max_mip_dimension as f32 / viewport.y as f32
365+
let mip_dim_ratio = if viewport.y != 0 && viewport.x != 0 {
366+
(bloom.max_mip_dimension as f32 / viewport.as_vec2()).max_element()
367367
} else {
368368
0.
369369
};
370370

371371
let texture_descriptor = TextureDescriptor {
372372
label: Some("bloom_texture"),
373-
size: (viewport.as_vec2() * mip_height_ratio)
373+
size: (viewport.as_vec2() * mip_dim_ratio)
374374
.round()
375375
.as_uvec2()
376376
.max(UVec2::ONE)

crates/bevy_post_process/src/bloom/settings.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,13 +116,17 @@ pub struct Bloom {
116116
pub composite_mode: BloomCompositeMode,
117117

118118
/// Maximum size of each dimension for the largest mipchain texture used in downscaling/upscaling.
119-
/// Only tweak if you are seeing visual artifacts.
119+
/// Lower values can improve performance but reduce quality.
120120
pub max_mip_dimension: u32,
121121

122122
/// Amount to stretch the bloom on each axis. Artistic control, can be used to emulate
123123
/// anamorphic blur by using a large x-value. For large values, you may need to increase
124124
/// [`Bloom::max_mip_dimension`] to reduce sampling artifacts.
125125
pub scale: Vec2,
126+
127+
// Whether to use a high quality bloom implementation (default: true).
128+
// If false, bloom will use an implementation that significantly reduces the number of texture samples and improves performance, but at the cost of lower quality.
129+
pub high_quality: bool,
126130
}
127131

128132
impl Bloom {
@@ -143,6 +147,7 @@ impl Bloom {
143147
composite_mode: BloomCompositeMode::EnergyConserving,
144148
max_mip_dimension: Self::DEFAULT_MAX_MIP_DIMENSION,
145149
scale: Vec2::ONE,
150+
high_quality: true,
146151
};
147152

148153
/// Emulates the look of stylized anamorphic bloom, stretched horizontally.
@@ -166,6 +171,7 @@ impl Bloom {
166171
composite_mode: BloomCompositeMode::Additive,
167172
max_mip_dimension: Self::DEFAULT_MAX_MIP_DIMENSION,
168173
scale: Vec2::ONE,
174+
high_quality: true,
169175
};
170176

171177
/// A preset that applies a very strong bloom, and blurs the whole screen.
@@ -181,6 +187,7 @@ impl Bloom {
181187
composite_mode: BloomCompositeMode::EnergyConserving,
182188
max_mip_dimension: Self::DEFAULT_MAX_MIP_DIMENSION,
183189
scale: Vec2::ONE,
190+
high_quality: true,
184191
};
185192
}
186193

crates/bevy_post_process/src/bloom/upsampling_pipeline.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ pub struct BloomUpsamplingPipeline {
3939
pub struct BloomUpsamplingPipelineKeys {
4040
composite_mode: BloomCompositeMode,
4141
final_pipeline: bool,
42+
high_quality: bool,
4243
}
4344

4445
pub fn init_bloom_upscaling_pipeline(
@@ -79,6 +80,11 @@ impl SpecializedRenderPipeline for BloomUpsamplingPipeline {
7980
BLOOM_TEXTURE_FORMAT
8081
};
8182

83+
let mut shader_defs = vec![];
84+
if !key.high_quality {
85+
shader_defs.push("FAST_BLUR".into());
86+
}
87+
8288
let color_blend = match key.composite_mode {
8389
BloomCompositeMode::EnergyConserving => {
8490
// At the time of developing this we decided to blend our
@@ -117,6 +123,7 @@ impl SpecializedRenderPipeline for BloomUpsamplingPipeline {
117123
vertex: self.fullscreen_shader.to_vertex_state(),
118124
fragment: Some(FragmentState {
119125
shader: self.fragment_shader.clone(),
126+
shader_defs,
120127
entry_point: Some("upsample".into()),
121128
targets: vec![Some(ColorTargetState {
122129
format: texture_format,
@@ -130,7 +137,6 @@ impl SpecializedRenderPipeline for BloomUpsamplingPipeline {
130137
}),
131138
write_mask: ColorWrites::ALL,
132139
})],
133-
..default()
134140
}),
135141
..default()
136142
}
@@ -151,6 +157,7 @@ pub fn prepare_upsampling_pipeline(
151157
BloomUpsamplingPipelineKeys {
152158
composite_mode: bloom.composite_mode,
153159
final_pipeline: false,
160+
high_quality: bloom.high_quality,
154161
},
155162
);
156163

@@ -160,6 +167,7 @@ pub fn prepare_upsampling_pipeline(
160167
BloomUpsamplingPipelineKeys {
161168
composite_mode: bloom.composite_mode,
162169
final_pipeline: true,
170+
high_quality: bloom.high_quality,
163171
},
164172
);
165173

crates/bevy_render/src/render_resource/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ pub use wgpu::{
5555
PushConstantRange, RenderPassColorAttachment, RenderPassDepthStencilAttachment,
5656
RenderPassDescriptor, RenderPipelineDescriptor as RawRenderPipelineDescriptor,
5757
Sampler as WgpuSampler, SamplerBindingType, SamplerBindingType as WgpuSamplerBindingType,
58-
SamplerDescriptor, ShaderModule, ShaderModuleDescriptor, ShaderSource, ShaderStages,
59-
StencilFaceState, StencilOperation, StencilState, StorageTextureAccess, StoreOp,
58+
SamplerBorderColor, SamplerDescriptor, ShaderModule, ShaderModuleDescriptor, ShaderSource,
59+
ShaderStages, StencilFaceState, StencilOperation, StencilState, StorageTextureAccess, StoreOp,
6060
TexelCopyBufferInfo, TexelCopyBufferLayout, TexelCopyTextureInfo, TextureAspect,
6161
TextureDescriptor, TextureDimension, TextureFormat, TextureFormatFeatureFlags,
6262
TextureFormatFeatures, TextureSampleType, TextureUsages, TextureView as WgpuTextureView,

examples/2d/bloom_2d.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ fn update_bloom_settings(
110110
bloom.prefilter.threshold_softness
111111
));
112112
text.push_str(&format!("(I/K) Horizontal Scale: {:.2}\n", bloom.scale.x));
113+
text.push_str(&format!("(P) High quality: {}\n", bloom.high_quality));
113114

114115
if keycode.just_pressed(KeyCode::Space) {
115116
commands.entity(camera_entity).remove::<Bloom>();
@@ -180,6 +181,10 @@ fn update_bloom_settings(
180181
bloom.scale.x += dt * 2.0;
181182
}
182183
bloom.scale.x = bloom.scale.x.clamp(0.0, 16.0);
184+
185+
if keycode.just_pressed(KeyCode::KeyP) {
186+
bloom.high_quality = !bloom.high_quality;
187+
}
183188
}
184189

185190
None => {

examples/3d/bloom_3d.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,8 @@ fn update_bloom_settings(
134134
"(U/J) Threshold softness: {:.2}\n",
135135
bloom.prefilter.threshold_softness
136136
));
137-
text.push_str(&format!("(I/K) Horizontal Scale: {:.2}\n", bloom.scale.x));
137+
text.push_str(&format!("(I/K) Horizontal scale: {:.2}\n", bloom.scale.x));
138+
text.push_str(&format!("(P) High quality: {}\n", bloom.high_quality));
138139

139140
if keycode.just_pressed(KeyCode::Space) {
140141
commands.entity(entity).remove::<Bloom>();
@@ -205,6 +206,10 @@ fn update_bloom_settings(
205206
bloom.scale.x += dt * 2.0;
206207
}
207208
bloom.scale.x = bloom.scale.x.clamp(0.0, 8.0);
209+
210+
if keycode.just_pressed(KeyCode::KeyP) {
211+
bloom.high_quality = !bloom.high_quality;
212+
}
208213
}
209214

210215
(entity, None) => {

0 commit comments

Comments
 (0)