This series illustrate my shaders on Shadertoy.com, which renders Instagram filters in real time.
Brannan Filter
Brannan filter emphasizes the grey and green colors, and paints a metallic tint upon the photos.
Click the mouse for comparison.
I write this shader to stylize your photos in batch on my own ShaderToy renderer 🙂 (To be open-sourced soon…)
Steps
- Overlay the greyscale image upon the original image
- Emphasize the red & green colors
- Multiply by a metallic tint
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
/** * Brannan Filter by Ruofei Du (DuRuofei.com) * Demo: https://www.shadertoy.com/view/4lSyDK * starea @ ShaderToy,License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. * https://creativecommons.org/licenses/by-nc-sa/3.0/ * * Reference: * [1] Overlay function forked from ben's https://www.shadertoy.com/view/XdS3RW * [2] starea's Dotted Drawing / Sketch Effect: https://www.shadertoy.com/view/ldSyzV * [3] starea's BrightnessContrastSaturationHue: https://www.shadertoy.com/view/MdjBRy * * Write-ups: * [1] http://blog.ruofeidu.com/implementing-instagram-filters/ **/ float overlay(in float s, in float d ) { return (d < 0.5) ? 2.0 * s * d : 1.0 - 2.0 * (1.0 - s) * (1.0 - d); } vec3 overlay(in vec3 s, in vec3 d ) { vec3 c; c.x = overlay(s.x,d.x); c.y = overlay(s.y,d.y); c.z = overlay(s.z,d.z); return c; } float greyScale(in vec3 col) { return dot(col, vec3(0.3, 0.59, 0.11)); } mat3 saturationMatrix( float saturation ) { vec3 luminance = vec3( 0.3086, 0.6094, 0.0820 ); float oneMinusSat = 1.0 - saturation; vec3 red = vec3( luminance.x * oneMinusSat ); red.r += saturation; vec3 green = vec3( luminance.y * oneMinusSat ); green.g += saturation; vec3 blue = vec3( luminance.z * oneMinusSat ); blue.b += saturation; return mat3(red, green, blue); } void levels(inout vec3 col, in vec3 inleft, in vec3 inright, in vec3 outleft, in vec3 outright) { col = clamp(col, inleft, inright); col = (col - inleft) / (inright - inleft); col = outleft + col * (outright - outleft); } void brightnessAdjust( inout vec3 color, in float b) { color += b; } void contrastAdjust( inout vec3 color, in float c) { float t = 0.5 - c * 0.5; color = color * c + t; } void mainImage( out vec4 fragColor, in vec2 fragCoord ) { vec2 uv = fragCoord.xy / iResolution.xy; vec3 col = texture(iChannel0, uv).rgb; if (iMouse.z > 0.5) { fragColor = vec4(col, 1.0); return; } vec3 grey = vec3(greyScale(col)); col = saturationMatrix(0.7) * col; grey = overlay(grey, col); col = mix(grey, col, 0.63); levels(col, vec3(0., 0., 0.) / 255., vec3(228., 255., 239.) / 255., vec3(23., 3., 12.) / 255., vec3(255.) / 255.); brightnessAdjust(col, -0.1); contrastAdjust(col, 1.05); vec3 tint = vec3(255., 248., 242.) / 255.; levels(col, vec3(0., 0., 0.) / 255., vec3(255., 224., 255.) / 255., vec3(9., 20., 18.) / 255., vec3(255.) / 255.); col = pow(col, vec3(0.91, 0.91, 0.91*0.94)); brightnessAdjust(col, -0.04); contrastAdjust(col, 1.14); col = tint * col; fragColor = vec4(col, 1.0); } |
Earlybird Filter
The Earlybird filter assigns the photo with a dated appearance. It uses sepia tint and faded colors as masks to render a Polaroid feeling.
I write this shader to stylize photos in batch on my own ShaderToy renderer 🙂
Click the mouse to compare.
Steps
- Lower the saturation
- Increase contrast
- Multiply by a gradient tint mask
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
/** * Earlybird Filter by Ruofei Du (DuRuofei.com) * Demo: https://www.shadertoy.com/view/4lSyDK * starea @ ShaderToy,License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. * https://creativecommons.org/licenses/by-nc-sa/3.0/ * * Reference: * [1] colorBurn function forked from ben's https://www.shadertoy.com/view/XdS3RW * [2] starea's Dotted Drawing / Sketch Effect: https://www.shadertoy.com/view/ldSyzV * [3] starea's BrightnessContrastSaturationHue: https://www.shadertoy.com/view/MdjBRy * * Write-ups: * [1] http://blog.ruofeidu.com/implementing-instagram-filters/ **/ float greyScale(in vec3 col) { return dot(col, vec3(0.3, 0.59, 0.11)); } mat3 saturationMatrix( float saturation ) { vec3 luminance = vec3( 0.3086, 0.6094, 0.0820 ); float oneMinusSat = 1.0 - saturation; vec3 red = vec3( luminance.x * oneMinusSat ); red.r += saturation; vec3 green = vec3( luminance.y * oneMinusSat ); green.g += saturation; vec3 blue = vec3( luminance.z * oneMinusSat ); blue.b += saturation; return mat3(red, green, blue); } void levels(inout vec3 col, in vec3 inleft, in vec3 inright, in vec3 outleft, in vec3 outright) { col = clamp(col, inleft, inright); col = (col - inleft) / (inright - inleft); col = outleft + col * (outright - outleft); } void brightnessAdjust( inout vec3 color, in float b) { color += b; } void contrastAdjust( inout vec3 color, in float c) { float t = 0.5 - c * 0.5; color = color * c + t; } vec3 colorBurn(in vec3 s, in vec3 d ) { return 1.0 - (1.0 - d) / s; } void mainImage( out vec4 fragColor, in vec2 fragCoord ) { vec2 uv = fragCoord.xy / iResolution.xy; vec3 col = texture(iChannel0, uv).rgb; if (iMouse.z > 0.5) { fragColor = vec4(col, 1.0); return; } vec2 coord = ( fragCoord.xy + fragCoord.xy - iResolution.xy ) / iResolution.y; vec3 gradient = vec3(pow(1.0 - length(coord * 0.4), 0.6) * 1.2); vec3 grey = vec3(184./255.); vec3 tint = vec3(252., 243., 213.) / 255.; col = saturationMatrix(0.68) * col; levels(col, vec3(0.), vec3(1.0), vec3(27.,0.,0.) / 255., vec3(255.) / 255.); col = pow(col, vec3(1.19)); brightnessAdjust(col, 0.13); contrastAdjust(col, 1.05); col = saturationMatrix(0.85) * col; levels(col, vec3(0.), vec3(235./255.), vec3(0.,0.,0.) / 255., vec3(255.) / 255.); col = mix(tint * col, col, gradient); col = colorBurn(grey, col); //col *= 0.8; fragColor = vec4(col, 1.0); } |
Starea Filter
The Starea filter renders the buffer with a blue atmosphere. It uses sepia tint and emphasize the blue part.
Click the mouse to compare.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
/** * Starea Filter by Ruofei Du (DuRuofei.com) * Demo: https://www.shadertoy.com/view/MtjyDK * starea @ ShaderToy,License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. * https://creativecommons.org/licenses/by-nc-sa/3.0/ * * Reference: * [1] colorBurn function forked from ben's https://www.shadertoy.com/view/XdS3RW * [2] starea's Dotted Drawing / Sketch Effect: https://www.shadertoy.com/view/ldSyzV * [3] starea's BrightnessContrastSaturationHue: https://www.shadertoy.com/view/MdjBRy * * Series: * [1] Brannan Filter: https://www.shadertoy.com/view/4lSyDK * [2] Earlybird Filter: https://www.shadertoy.com/view/XlSyWV * [3] Starea Filter: https://www.shadertoy.com/view/MtjyDK * * Write-ups: * [1] http://blog.ruofeidu.com/implementing-instagram-filters-brannan/ **/ float greyScale(in vec3 col) { return dot(col, vec3(0.3, 0.59, 0.11)); } mat3 saturationMatrix( float saturation ) { vec3 luminance = vec3( 0.3086, 0.6094, 0.0820 ); float oneMinusSat = 1.0 - saturation; vec3 red = vec3( luminance.x * oneMinusSat ); red.r += saturation; vec3 green = vec3( luminance.y * oneMinusSat ); green.g += saturation; vec3 blue = vec3( luminance.z * oneMinusSat ); blue.b += saturation; return mat3(red, green, blue); } void levels(inout vec3 col, in vec3 inleft, in vec3 inright, in vec3 outleft, in vec3 outright) { col = clamp(col, inleft, inright); col = (col - inleft) / (inright - inleft); col = outleft + col * (outright - outleft); } void levelsGamma(inout vec3 col, in vec3 inleft, in vec3 inright, in vec3 outleft, in vec3 outright, in vec3 gamma1, in vec3 gamma2) { col = clamp(col, inleft, inright); col = (col - inleft) / (inright - inleft); col = pow(col, gamma2); col = outleft + col * (outright - outleft); col = pow(col, gamma1); } void levelsGamma2(inout vec3 col, in vec3 inleft, in vec3 inright, in vec3 outleft, in vec3 outright, in vec3 gamma1, in vec3 gamma2, in float ileft, in float iright, in float oleft, in float oright) { col = clamp(col, inleft, inright); col = (col - inleft) / (inright - inleft); col = pow(col, gamma2); col = outleft + col * (outright - outleft); col = (col - vec3(ileft)) / vec3(iright - ileft); col = pow(col, gamma1); col = vec3(oleft) + col * (oright - oleft); } void brightnessAdjust( inout vec3 color, in float b) { color += b; } void contrastAdjust( inout vec3 color, in float c) { float t = 0.5 - c * 0.5; color = color * c + t; } vec3 colorBurn(in vec3 s, in vec3 d ) { return 1.0 - (1.0 - d) / s; } void mainImage( out vec4 fragColor, in vec2 fragCoord ) { vec2 uv = fragCoord.xy / iResolution.xy; vec3 col = texture(iChannel0, uv).rgb; if (iMouse.z > 0.5) { fragColor = vec4(col, 1.0); return; } vec3 tint = vec3(252., 255., 235.) / 255.; levelsGamma(col, vec3(28., 0., 0.) / 255., vec3(1.0), vec3(0., 0., 45.) / 255., vec3(1.0), vec3(1.2), vec3(0.91, 0.94, 0.85) ); brightnessAdjust(col, 0.05); contrastAdjust(col, 1.1); levelsGamma2(col, vec3(45., 0., 0.) / 255., vec3(255.,255.,255.) / 255., vec3(11., 0., 56.) / 255., vec3(232.,250.,238.) / 255., vec3(1.3), vec3(0.45, 0.8, 1.4), 15./255., 243./255., 0./255., 238./255.); contrastAdjust(col, 1.2); levels(col, vec3(0., 0., 0.) / 255., vec3(240.,255.,255.) / 255., vec3(0., 0., 14.) / 255., vec3(255.,255.,241.) / 255.); col = col * tint; fragColor = vec4(col, 1.0); } |