* @filter Hue / Saturation * @description Provides rotational hue and multiplicative saturation control. RGB color space * can be imagined as a cube where the axes are the red, green, and blue color * values. Hue changing works by rotating the co
(hue, saturation)
| 11 | * @param saturation -1 to 1 (-1 is solid gray, 0 is no change, and 1 is maximum contrast) |
| 12 | */ |
| 13 | function hueSaturation(hue, saturation) { |
| 14 | gl.hueSaturation = gl.hueSaturation || new Shader(null, '\ |
| 15 | uniform sampler2D texture;\ |
| 16 | uniform float hue;\ |
| 17 | uniform float saturation;\ |
| 18 | varying vec2 texCoord;\ |
| 19 | void main() {\ |
| 20 | vec4 color = texture2D(texture, texCoord);\ |
| 21 | \ |
| 22 | /* hue adjustment, wolfram alpha: RotationTransform[angle, {1, 1, 1}][{x, y, z}] */\ |
| 23 | float angle = hue * 3.14159265;\ |
| 24 | float s = sin(angle), c = cos(angle);\ |
| 25 | vec3 weights = (vec3(2.0 * c, -sqrt(3.0) * s - c, sqrt(3.0) * s - c) + 1.0) / 3.0;\ |
| 26 | float len = length(color.rgb);\ |
| 27 | color.rgb = vec3(\ |
| 28 | dot(color.rgb, weights.xyz),\ |
| 29 | dot(color.rgb, weights.zxy),\ |
| 30 | dot(color.rgb, weights.yzx)\ |
| 31 | );\ |
| 32 | \ |
| 33 | /* saturation adjustment */\ |
| 34 | float average = (color.r + color.g + color.b) / 3.0;\ |
| 35 | if (saturation > 0.0) {\ |
| 36 | color.rgb += (average - color.rgb) * (1.0 - 1.0 / (1.001 - saturation));\ |
| 37 | } else {\ |
| 38 | color.rgb += (average - color.rgb) * (-saturation);\ |
| 39 | }\ |
| 40 | \ |
| 41 | gl_FragColor = color;\ |
| 42 | }\ |
| 43 | '); |
| 44 | |
| 45 | simpleShader.call(this, gl.hueSaturation, { |
| 46 | hue: clamp(-1, hue, 1), |
| 47 | saturation: clamp(-1, saturation, 1) |
| 48 | }); |
| 49 | |
| 50 | return this; |
| 51 | } |