Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Merged by Bors] - Bloom #6397

Closed
wants to merge 33 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
3a86a0e
add separate tonemapping and upscaling pass
jakobhellermann Dec 23, 2021
315ef6f
return rendered-to texture view as output
jakobhellermann Dec 24, 2021
cf014e8
create bind group in tonemapping/upscaling node to enable customization
jakobhellermann Dec 29, 2021
babcbb2
make hdr configurable
jakobhellermann Dec 30, 2021
21ba00d
add UpscalingPipelineKey
jakobhellermann Mar 20, 2022
08e4ff2
add bloom node
jakobhellermann Dec 24, 2021
3ab3c4f
make bloom spheres sometimes non-emissive
jakobhellermann Dec 24, 2021
c056271
Merge commit '838b318863a4d9374e16c8b46dce8be53519c88f' into bloom-no…
JMS55 Oct 26, 2022
33198fb
Small cleanup
JMS55 Oct 27, 2022
19bec71
Initial bloom shader cleanup/port
JMS55 Oct 27, 2022
57782c8
Bloom WIP
JMS55 Oct 27, 2022
cfd8ac4
Bloom fixes
JMS55 Oct 27, 2022
584575e
Fix wrong texture binding
JMS55 Oct 27, 2022
2c33c96
Document example a little more
JMS55 Oct 28, 2022
17c401d
Add intensity and reorganize
cart Nov 2, 2022
7b87364
Merge remote-tracking branch 'origin/main' into pr/JMS55/6397
cart Nov 2, 2022
fd5b01a
Add MSAA support
cart Nov 2, 2022
4584aa3
Merge pull request #1 from cart/bloom-tweaks
JMS55 Nov 2, 2022
1fd95b8
Resolve Bloom Clippy
cart Nov 2, 2022
7792070
Merge pull request #2 from cart/bloom-tweaks
JMS55 Nov 2, 2022
04346c8
support for camera_2d
DGriffin91 Nov 3, 2022
cea7545
Merge pull request #3 from DGriffin91/bloom-node-new
JMS55 Nov 3, 2022
7a17524
Bloom cleanup, move to core_pipeline
JMS55 Nov 3, 2022
8aad516
Add bloom example controls
JMS55 Nov 3, 2022
d82813b
Tweak bloom example
JMS55 Nov 3, 2022
acdf2da
Merge commit '157f2c1584a7b535b07fdb43871cab7fed643ad1' into bloom-no…
JMS55 Nov 3, 2022
feabf64
Merge commit 'e6a016458768312e72ad669e49cd082a389272a3' into bloom-no…
JMS55 Nov 3, 2022
87a5b77
Improve bloom example controls
JMS55 Nov 3, 2022
48ed761
Update crates/bevy_core_pipeline/src/bloom/mod.rs
cart Nov 3, 2022
fa80a08
Apply suggestions from code review
cart Nov 3, 2022
b84f768
Update Cargo.toml
cart Nov 3, 2022
f7fd53f
Update Cargo.toml
JMS55 Nov 4, 2022
8559e67
Add bloom example to readme
JMS55 Nov 4, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions Cargo.toml
Expand Up @@ -313,6 +313,16 @@ description = "Illustrates spot lights"
category = "3D Rendering"
wasm = true

[[example]]
name = "bloom"
path = "examples/3d/bloom.rs"

cart marked this conversation as resolved.
Show resolved Hide resolved
[package.metadata.example.bloom]
name = "Bloom"
description = "Illustrates bloom configuration using HDR and emissive materials"
category = "3D Rendering"
JMS55 marked this conversation as resolved.
Show resolved Hide resolved
wasm = false

[[example]]
name = "load_gltf"
path = "examples/3d/load_gltf.rs"
Expand Down
1 change: 1 addition & 0 deletions crates/bevy_core_pipeline/Cargo.toml
Expand Up @@ -25,6 +25,7 @@ bevy_ecs = { path = "../bevy_ecs", version = "0.9.0-dev" }
bevy_reflect = { path = "../bevy_reflect", version = "0.9.0-dev" }
bevy_render = { path = "../bevy_render", version = "0.9.0-dev" }
bevy_transform = { path = "../bevy_transform", version = "0.9.0-dev" }
bevy_math = { path = "../bevy_math", version = "0.9.0-dev" }
bevy_utils = { path = "../bevy_utils", version = "0.9.0-dev" }

serde = { version = "1", features = ["derive"] }
Expand Down
136 changes: 136 additions & 0 deletions crates/bevy_core_pipeline/src/bloom/bloom.wgsl
@@ -0,0 +1,136 @@
#import bevy_core_pipeline::fullscreen_vertex_shader

struct BloomUniforms {
threshold: f32,
knee: f32,
scale: f32,
intensity: f32,
};

@group(0) @binding(0)
var original: texture_2d<f32>;
@group(0) @binding(1)
var original_sampler: sampler;
@group(0) @binding(2)
var<uniform> uniforms: BloomUniforms;
@group(0) @binding(3)
var up: texture_2d<f32>;

fn quadratic_threshold(color: vec4<f32>, threshold: f32, curve: vec3<f32>) -> vec4<f32> {
let br = max(max(color.r, color.g), color.b);

var rq: f32 = clamp(br - curve.x, 0.0, curve.y);
rq = curve.z * rq * rq;

return color * max(rq, br - threshold) / max(br, 0.0001);
}

// Samples original around the supplied uv using a filter.
//
// o o o
// o o
// o o o
// o o
// o o o
//
// This is used because it has a number of advantages that
// outweigh the cost of 13 samples that basically boil down
// to it looking better.
//
// These advantages are outlined in a youtube video by the Cherno:
// https://www.youtube.com/watch?v=tI70-HIc5ro
fn sample_13_tap(uv: vec2<f32>, scale: vec2<f32>) -> vec4<f32> {
let a = textureSample(original, original_sampler, uv + vec2<f32>(-1.0, -1.0) * scale);
let b = textureSample(original, original_sampler, uv + vec2<f32>(0.0, -1.0) * scale);
let c = textureSample(original, original_sampler, uv + vec2<f32>(1.0, -1.0) * scale);
let d = textureSample(original, original_sampler, uv + vec2<f32>(-0.5, -0.5) * scale);
let e = textureSample(original, original_sampler, uv + vec2<f32>(0.5, -0.5) * scale);
let f = textureSample(original, original_sampler, uv + vec2<f32>(-1.0, 0.0) * scale);
let g = textureSample(original, original_sampler, uv + vec2<f32>(0.0, 0.0) * scale);
let h = textureSample(original, original_sampler, uv + vec2<f32>(1.0, 0.0) * scale);
let i = textureSample(original, original_sampler, uv + vec2<f32>(-0.5, 0.5) * scale);
let j = textureSample(original, original_sampler, uv + vec2<f32>(0.5, 0.5) * scale);
let k = textureSample(original, original_sampler, uv + vec2<f32>(-1.0, 1.0) * scale);
let l = textureSample(original, original_sampler, uv + vec2<f32>(0.0, 1.0) * scale);
let m = textureSample(original, original_sampler, uv + vec2<f32>(1.0, 1.0) * scale);

let div = (1.0 / 4.0) * vec2<f32>(0.5, 0.125);

var o: vec4<f32> = (d + e + i + j) * div.x;
o = o + (a + b + g + f) * div.y;
o = o + (b + c + h + g) * div.y;
o = o + (f + g + l + k) * div.y;
o = o + (g + h + m + l) * div.y;

return o;
}

// Samples original using a 3x3 tent filter.
//
// NOTE: Use a 2x2 filter for better perf, but 3x3 looks better.
fn sample_original_3x3_tent(uv: vec2<f32>, scale: vec2<f32>) -> vec4<f32> {
let d = vec4<f32>(1.0, 1.0, -1.0, 0.0);

var s: vec4<f32> = textureSample(original, original_sampler, uv - d.xy * scale);
s = s + textureSample(original, original_sampler, uv - d.wy * scale) * 2.0;
s = s + textureSample(original, original_sampler, uv - d.zy * scale);

s = s + textureSample(original, original_sampler, uv + d.zw * scale) * 2.0;
s = s + textureSample(original, original_sampler, uv) * 4.0;
s = s + textureSample(original, original_sampler, uv + d.xw * scale) * 2.0;

s = s + textureSample(original, original_sampler, uv + d.zy * scale);
s = s + textureSample(original, original_sampler, uv + d.wy * scale) * 2.0;
s = s + textureSample(original, original_sampler, uv + d.xy * scale);

return s / 16.0;
}

@fragment
fn downsample_prefilter(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {
let texel_size = 1.0 / vec2<f32>(textureDimensions(original));

let scale = texel_size;

let curve = vec3<f32>(
uniforms.threshold - uniforms.knee,
uniforms.knee * 2.0,
0.25 / uniforms.knee,
);

var o: vec4<f32> = sample_13_tap(uv, scale);

o = quadratic_threshold(o, uniforms.threshold, curve);
o = max(o, vec4<f32>(0.00001));

return o;
}

@fragment
fn downsample(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {
let texel_size = 1.0 / vec2<f32>(textureDimensions(original));

let scale = texel_size;

return sample_13_tap(uv, scale);
}

@fragment
fn upsample(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {
let texel_size = 1.0 / vec2<f32>(textureDimensions(original));

let upsample = sample_original_3x3_tent(uv, texel_size * uniforms.scale);
var color: vec4<f32> = textureSample(up, original_sampler, uv);
color = vec4<f32>(color.rgb + upsample.rgb, upsample.a);

return color;
}

@fragment
fn upsample_final(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {
let texel_size = 1.0 / vec2<f32>(textureDimensions(original));

let upsample = sample_original_3x3_tent(uv, texel_size * uniforms.scale);

return vec4<f32>(upsample.rgb * uniforms.intensity, upsample.a);
}