From 9b24041394ecf8210514845372d965f8d65302c9 Mon Sep 17 00:00:00 2001 From: x2048 Date: Wed, 2 Nov 2022 09:09:48 +0100 Subject: Improve bloom effect (#12916) * Remove the built-in exposure factor of 2.5 * Add physics-based bloom (https://learnopengl.com/Guest-Articles/2022/Phys.-Based-Bloom) * Add luminance scaling for bloom layer to simulate HDR * Add setting to control bloom strength --- .../shaders/bloom_downsample/opengl_fragment.glsl | 37 ++++++++++++++++++++++ client/shaders/bloom_downsample/opengl_vertex.glsl | 11 +++++++ client/shaders/bloom_upsample/opengl_fragment.glsl | 35 ++++++++++++++++++++ client/shaders/bloom_upsample/opengl_vertex.glsl | 11 +++++++ client/shaders/blur_h/opengl_fragment.glsl | 12 +++++-- client/shaders/blur_v/opengl_fragment.glsl | 12 +++++-- client/shaders/extract_bloom/opengl_fragment.glsl | 14 +++++--- client/shaders/second_stage/opengl_fragment.glsl | 11 +++---- 8 files changed, 128 insertions(+), 15 deletions(-) create mode 100644 client/shaders/bloom_downsample/opengl_fragment.glsl create mode 100644 client/shaders/bloom_downsample/opengl_vertex.glsl create mode 100644 client/shaders/bloom_upsample/opengl_fragment.glsl create mode 100644 client/shaders/bloom_upsample/opengl_vertex.glsl (limited to 'client') diff --git a/client/shaders/bloom_downsample/opengl_fragment.glsl b/client/shaders/bloom_downsample/opengl_fragment.glsl new file mode 100644 index 000000000..a1ff271a9 --- /dev/null +++ b/client/shaders/bloom_downsample/opengl_fragment.glsl @@ -0,0 +1,37 @@ +// based on Phys.Bloom OpenGL tutorial https://learnopengl.com/Guest-Articles/2022/Phys.-Based-Bloom +// and ACM Siggraph talk in 2014 by Jorge Jimenez for Call of Duty: Advanced Warfare. +#define rendered texture0 + +uniform sampler2D rendered; +uniform vec2 texelSize0; + +#ifdef GL_ES +varying mediump vec2 varTexCoord; +#else +centroid varying vec2 varTexCoord; +#endif + +void main(void) +{ + vec2 tx = 2.0 * texelSize0; + vec3 a = texture2D(rendered, varTexCoord.st + vec2(-1., -1.) * tx).rgb; + vec3 b = texture2D(rendered, varTexCoord.st + vec2(0., -1.) * tx).rgb; + vec3 c = texture2D(rendered, varTexCoord.st + vec2(1., -1.) * tx).rgb; + vec3 d = texture2D(rendered, varTexCoord.st + vec2(-1., 0.) * tx).rgb; + vec3 e = texture2D(rendered, varTexCoord.st + vec2(0., 0.) * tx).rgb; + vec3 f = texture2D(rendered, varTexCoord.st + vec2(1., 0.) * tx).rgb; + vec3 g = texture2D(rendered, varTexCoord.st + vec2(-1., 1.) * tx).rgb; + vec3 h = texture2D(rendered, varTexCoord.st + vec2(0., 1.) * tx).rgb; + vec3 i = texture2D(rendered, varTexCoord.st + vec2(1., 1.) * tx).rgb; + vec3 j = texture2D(rendered, varTexCoord.st + vec2(-0.5, -0.5) * tx).rgb; + vec3 k = texture2D(rendered, varTexCoord.st + vec2(0.5, -0.5) * tx).rgb; + vec3 l = texture2D(rendered, varTexCoord.st + vec2(-0.5, 0.5) * tx).rgb; + vec3 m = texture2D(rendered, varTexCoord.st + vec2(-0.5, 0.5) * tx).rgb; + + vec3 color = + (a + c + g + i) * 0.03125 + + (b + d + f + h) * 0.0625 + + (e + j + k + l + m) * 0.125; + + gl_FragColor = max(vec4(color, 1.0), 1e-4); +} diff --git a/client/shaders/bloom_downsample/opengl_vertex.glsl b/client/shaders/bloom_downsample/opengl_vertex.glsl new file mode 100644 index 000000000..12692c296 --- /dev/null +++ b/client/shaders/bloom_downsample/opengl_vertex.glsl @@ -0,0 +1,11 @@ +#ifdef GL_ES +varying mediump vec2 varTexCoord; +#else +centroid varying vec2 varTexCoord; +#endif + +void main(void) +{ + varTexCoord.st = inTexCoord0.st; + gl_Position = inVertexPosition; +} diff --git a/client/shaders/bloom_upsample/opengl_fragment.glsl b/client/shaders/bloom_upsample/opengl_fragment.glsl new file mode 100644 index 000000000..99ec8e205 --- /dev/null +++ b/client/shaders/bloom_upsample/opengl_fragment.glsl @@ -0,0 +1,35 @@ +#define current texture0 +#define previous texture1 + +uniform sampler2D current; +uniform sampler2D previous; +uniform vec2 texelSize0; +uniform mediump float bloomRadius; + +#ifdef GL_ES +varying mediump vec2 varTexCoord; +#else +centroid varying vec2 varTexCoord; +#endif + +void main(void) +{ + vec2 offset = bloomRadius * texelSize0; + + vec3 a = texture2D(previous, varTexCoord.st + vec2(-1., -1.) * offset).rgb; + vec3 b = texture2D(previous, varTexCoord.st + vec2(0., -1.) * offset).rgb; + vec3 c = texture2D(previous, varTexCoord.st + vec2(1., -1.) * offset).rgb; + vec3 d = texture2D(previous, varTexCoord.st + vec2(-1., 0.) * offset).rgb; + vec3 e = texture2D(previous, varTexCoord.st + vec2(0., 0.) * offset).rgb; + vec3 f = texture2D(previous, varTexCoord.st + vec2(1., 0.) * offset).rgb; + vec3 g = texture2D(previous, varTexCoord.st + vec2(-1., 1.) * offset).rgb; + vec3 h = texture2D(previous, varTexCoord.st + vec2(0., 1.) * offset).rgb; + vec3 i = texture2D(previous, varTexCoord.st + vec2(1., 1.) * offset).rgb; + + vec3 base = texture2D(current, varTexCoord.st).rgb; + + gl_FragColor = max(vec4(base + + (a + c + g + i) * 0.0625 + + (b + d + f + h) * 0.125 + + e * 0.25, 1.), 1e-4); +} diff --git a/client/shaders/bloom_upsample/opengl_vertex.glsl b/client/shaders/bloom_upsample/opengl_vertex.glsl new file mode 100644 index 000000000..12692c296 --- /dev/null +++ b/client/shaders/bloom_upsample/opengl_vertex.glsl @@ -0,0 +1,11 @@ +#ifdef GL_ES +varying mediump vec2 varTexCoord; +#else +centroid varying vec2 varTexCoord; +#endif + +void main(void) +{ + varTexCoord.st = inTexCoord0.st; + gl_Position = inVertexPosition; +} diff --git a/client/shaders/blur_h/opengl_fragment.glsl b/client/shaders/blur_h/opengl_fragment.glsl index 9aeecad1c..72d71dc07 100644 --- a/client/shaders/blur_h/opengl_fragment.glsl +++ b/client/shaders/blur_h/opengl_fragment.glsl @@ -3,6 +3,7 @@ uniform sampler2D rendered; uniform vec2 texelSize0; uniform mediump float bloomRadius; +uniform mat3 bloomBlurWeights; #ifdef GL_ES varying mediump vec2 varTexCoord; @@ -10,6 +11,13 @@ varying mediump vec2 varTexCoord; centroid varying vec2 varTexCoord; #endif +// smoothstep - squared +float smstsq(float f) +{ + f = f * f * (3 - 2 * f); + return f; +} + void main(void) { // kernel distance and linear size @@ -19,8 +27,8 @@ void main(void) vec4 color = vec4(0.); mediump float sum = 0.; for (mediump float i = 0.; i < n; i++) { - mediump float weight = pow(1. - (abs(i / bloomRadius - 1.)), 1.3); - color += texture2D(rendered, uv).rgba * weight; + mediump float weight = smstsq(1. - (abs(i / bloomRadius - 1.))); + color.rgb += texture2D(rendered, uv).rgb * weight; sum += weight; uv += vec2(texelSize0.x, 0.); } diff --git a/client/shaders/blur_v/opengl_fragment.glsl b/client/shaders/blur_v/opengl_fragment.glsl index 5974adf88..05575a967 100644 --- a/client/shaders/blur_v/opengl_fragment.glsl +++ b/client/shaders/blur_v/opengl_fragment.glsl @@ -3,6 +3,7 @@ uniform sampler2D rendered; uniform vec2 texelSize0; uniform mediump float bloomRadius; +uniform mat3 bloomBlurWeights; #ifdef GL_ES varying mediump vec2 varTexCoord; @@ -10,6 +11,13 @@ varying mediump vec2 varTexCoord; centroid varying vec2 varTexCoord; #endif +// smoothstep - squared +float smstsq(float f) +{ + f = f * f * (3 - 2 * f); + return f; +} + void main(void) { // kernel distance and linear size @@ -19,8 +27,8 @@ void main(void) vec4 color = vec4(0.); mediump float sum = 0.; for (mediump float i = 0.; i < n; i++) { - mediump float weight = pow(1. - (abs(i / bloomRadius - 1.)), 1.3); - color += texture2D(rendered, uv).rgba * weight; + mediump float weight = smstsq(1. - (abs(i / bloomRadius - 1.))); + color.rgb += texture2D(rendered, uv).rgb * weight; sum += weight; uv += vec2(0., texelSize0.y); } diff --git a/client/shaders/extract_bloom/opengl_fragment.glsl b/client/shaders/extract_bloom/opengl_fragment.glsl index 7d18ec26f..af320f9ab 100644 --- a/client/shaders/extract_bloom/opengl_fragment.glsl +++ b/client/shaders/extract_bloom/opengl_fragment.glsl @@ -2,7 +2,7 @@ uniform sampler2D rendered; uniform mediump float exposureFactor; -uniform float bloomLuminanceThreshold; +uniform mediump float bloomStrength; #ifdef GL_ES varying mediump vec2 varTexCoord; @@ -14,8 +14,14 @@ centroid varying vec2 varTexCoord; void main(void) { vec2 uv = varTexCoord.st; - vec4 color = texture2D(rendered, uv).rgba; + vec3 color = texture2D(rendered, uv).rgb; // translate to linear colorspace (approximate) - color.rgb = pow(color.rgb, vec3(2.2)) * exposureFactor; - gl_FragColor = vec4(color.rgb, 1.0); // force full alpha to avoid holes in the image. + color = pow(color, vec3(2.2)); + + // Scale colors by luminance to amplify bright colors + // in SDR textures. + float luminance = dot(color, vec3(0.213, 0.515, 0.072)); + luminance *= luminance; + color *= luminance * exposureFactor * bloomStrength; + gl_FragColor = vec4(color, 1.0); // force full alpha to avoid holes in the image. } diff --git a/client/shaders/second_stage/opengl_fragment.glsl b/client/shaders/second_stage/opengl_fragment.glsl index 290caf8e3..c48359e37 100644 --- a/client/shaders/second_stage/opengl_fragment.glsl +++ b/client/shaders/second_stage/opengl_fragment.glsl @@ -16,15 +16,14 @@ centroid varying vec2 varTexCoord; vec4 applyBloom(vec4 color, vec2 uv) { - float bias = bloomIntensity; - vec4 bloom = texture2D(bloom, uv); + vec3 light = texture2D(bloom, uv).rgb; #ifdef ENABLE_BLOOM_DEBUG if (uv.x > 0.5 && uv.y < 0.5) - return vec4(bloom.rgb, color.a); + return vec4(light, color.a); if (uv.x < 0.5) - return color; + return light; #endif - color.rgb = mix(color.rgb, bloom.rgb, bias); + color.rgb = mix(color.rgb, light, bloomIntensity); return color; } @@ -86,8 +85,6 @@ void main(void) { #if ENABLE_TONE_MAPPING color = applyToneMapping(color); -#else - color.rgb /= 2.5; // default exposure factor, see also RenderingEngine::DEFAULT_EXPOSURE_FACTOR; #endif } -- cgit v1.2.3