diff options
Diffstat (limited to 'shaders/post/bloom.glsl')
| -rw-r--r-- | shaders/post/bloom.glsl | 40 |
1 files changed, 40 insertions, 0 deletions
diff --git a/shaders/post/bloom.glsl b/shaders/post/bloom.glsl new file mode 100644 index 00000000..d54a0aac --- /dev/null +++ b/shaders/post/bloom.glsl @@ -0,0 +1,40 @@ +// Bloom: the brightest ink glows, a little. The glow itself is made by the +// shell at half resolution and below (bloom-down, bloom-up: a dual Kawase +// filter over a bright pass, in linear light) and arrives here in +// pardesBloom; this pass adds it to the frame. Only true highlights pass +// the threshold, and the strength stays in ยง8.2's budget (at most 5%) and +// under pardesCap, so no text or selection loses contrast below its own or +// 4.5. Tags, grips, notices and the cursor are left alone (pardesSpare). +// It is a Shadertoy file: pardes puts its prefix before it. + +layout(set = 2, binding = 1) uniform sampler2D pardesBloom; + +float strength() { return min(pardesByLevel(0.02, 0.035, 0.05), pardesCap); } + +vec3 toLinear(vec3 c) { + return mix(pow((c + 0.055) / 1.055, vec3(2.4)), c / 12.92, lessThanEqual(c, vec3(0.04045))); +} + +vec3 toSrgb(vec3 c) { + c = max(c, vec3(0.0)); + return mix(1.055 * pow(c, vec3(1.0 / 2.4)) - 0.055, c * 12.92, lessThanEqual(c, vec3(0.0031308))); +} + +float ign(vec2 p) { + return fract(52.9829189 * fract(dot(p, vec2(0.06711056, 0.00583715)))); +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + vec2 uv = fragCoord / iResolution.xy; + vec4 frame = texture(iChannel0, uv); + if (pardesSpared(fragCoord)) { + fragColor = frame; + return; + } + vec3 glow = texture(pardesBloom, uv).rgb; + vec3 col = toLinear(frame.rgb) + glow * strength(); + vec3 srgb = toSrgb(col); + // Dithered: a glow's long falloff never bands. + srgb += (ign(fragCoord) - 0.5) / 255.0 * step(1e-4, dot(glow, vec3(1.0))); + fragColor = vec4(clamp(srgb, 0.0, 1.0), frame.a); +} |
