From 41e38a5467560a07dde2b4f180950479e3d76c8d Mon Sep 17 00:00:00 2001 From: Jeremy Behreandt Date: Mon, 8 Nov 2021 09:22:31 -0600 Subject: [PATCH] Use Luminance In Desaturate Shader Updated desaturate shader to use perceptual luminance instead of HSV. --- src/Shaders/Desaturate.shader | 81 +++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 37 deletions(-) diff --git a/src/Shaders/Desaturate.shader b/src/Shaders/Desaturate.shader index 9dc246a74f51..d7f5e0435534 100644 --- a/src/Shaders/Desaturate.shader +++ b/src/Shaders/Desaturate.shader @@ -9,54 +9,61 @@ uniform sampler2D selection; uniform bool affect_selection; uniform bool has_selection; -vec3 rgb2hsb(vec3 c){ - vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); - vec4 p = mix(vec4(c.bg, K.wz), - vec4(c.gb, K.xy), - step(c.b, c.g)); - vec4 q = mix(vec4(p.xyw, c.r), - vec4(c.r, p.yzx), - step(p.x, c.r)); - float d = q.x - min(q.w, q.y); - float e = 1.0e-10; - return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), - d / (q.x + e), - q.x); +float stolChannel(float x) { + return (x < 0.04045) ? (x / 12.92) : pow((x + 0.055) / 1.055, 2.4); } -vec3 hsb2rgb(vec3 c){ - vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0), - 6.0)-3.0)-1.0, - 0.0, - 1.0 ); - rgb = rgb*rgb*(3.0-2.0*rgb); - return c.z * mix(vec3(1.0), rgb, c.y); +vec3 standardToLinear(vec3 c) { + return vec3( + stolChannel(c.r), + stolChannel(c.g), + stolChannel(c.b)); } +float ltosChannel(float x) { + return (x > 0.0031308) ? (pow(x, 1.0 / 2.4) * 1.055 - 0.055) : (x * 12.92); +} + +vec3 linearToStandard(vec3 c) { + return vec3( + ltosChannel(c.r), + ltosChannel(c.g), + ltosChannel(c.b)); +} + +float luminance(vec3 lin) { + return 0.21264935 * lin.r + + 0.71516913 * lin.g + + 0.07218152 * lin.b; +} void fragment() { // Get color from the sprite texture at the current pixel we are rendering vec4 original_color = texture(TEXTURE, UV); vec4 selection_color = texture(selection, UV); - vec3 col = original_color.rgb; - vec3 hsb = rgb2hsb(col); - float gray = hsb.z; - if (red) - col.x = gray; - if (green) - col.y = gray; - if (blue) - col.z = gray; + // Transform from standard RGB to linear RGB. + vec3 std = original_color.rgb; + vec3 lin = standardToLinear(std); + + // Find the y component of linear RGB to XYZ transformation. + float lum = luminance(lin); + vec3 des = vec3( + red ? lum : lin.r, + green ? lum : lin.g, + blue ? lum : lin.b); + vec3 stdPrime = linearToStandard(des); vec3 output; - if(affect_selection && has_selection) - output = mix(original_color.rgb, col, selection_color.a); - else - output = col; - if (alpha) - COLOR = vec4(output.rgb, gray); - else - COLOR = vec4(output.rgb, original_color.a); + if(affect_selection && has_selection) { + output = mix(original_color.rgb, stdPrime, selection_color.a); + } else { + output = stdPrime; + } + if (alpha) { + COLOR = vec4(output.rgb, ltosChannel(lum)); + } else { + COLOR = vec4(output.rgb, original_color.a); + } } \ No newline at end of file