h1

Photoshop math with GLSL shaders

January 5, 2009

I usualy play with Photoshop to try post-processing effects on photos or game screenshots, it’s a lot faster than coding directly anything in shaders, but at the end I wanted to see my effects running in real-time. So I adapted a big part of the C-like code from this famous Photoshop blending mode math page + missing blending modes to GLSL (and now HLSL!) code and I added a few other useful things from Photoshop, such as Hue/Saturation/Luminance conversion, desaturation, contrast.

For example, I tried combining a few things in my Editor:

photoshopmath_tn

photoshopmath_editor_tn

Translating Photoshop operations on layers gives this kind of code:

uniform sampler2D Tex;
uniform sampler1D GradientMap;
uniform sampler1D GradientGround;

varying vec2 uv;

void main()
{

vec3 color = texture2D(Tex, uv).xyz;

// Split-tone
vec4 colorDesat = Desaturate(color, 1.0);
vec3 splitColor = texture1D(GradientMap, colorDesat.r).rgb;
vec3 pass1 = BlendColor(color, splitColor);

// Vertical gradient
vec4 verticalGradientColor = texture1D(GradientGround, uv.y);
vec3 pass2 = mix(pass1, BlendColor(pass1, verticalGradientColor.rgb), verticalGradientColor.a);

// Luminosity
vec3 pass3 = mix(pass2, BlendLuminosity(pass2, color + vec3(0.08)), 0.5);

// Linear light at 40%
vec3 pass4 = mix(pass3, BlendLinearLight(pass3, color), 0.4);

// Final
gl_FragColor = vec4(pass4, 1.0);

}

Here is the list of blending modes and functions I got:

Blending modes:

  • Normal
  • Lighten
  • Darken
  • Multiply
  • Average
  • Add
  • Substract
  • Difference
  • Negation
  • Exclusion
  • Screen
  • Overlay
  • SoftLight
  • HardLight
  • ColorDodge
  • ColorBurn
  • LinearDodge
  • LinearBurn
  • LinearLight
  • VividLight
  • PinLight
  • HardMix
  • Reflect
  • Glow
  • Phoenix
  • Hue
  • Saturation
  • Color
  • Luminosity

Functions:

  • Desaturation
  • RGBToHSL (RGB to Hue/Saturation/Luminance)
  • HSLToRGB (Hue/Saturation/Luminance to RGB)
  • Contrast

Here is my GLSL code, almost all the blending modes are macros and some do per-channel operation so it could run faster using vector operations with masks (to take into account the values per component), but still I guess it could help :)

Download PhotoshopMath.glsl

Update:

Oh and by the way you noticed the Split-Tone pass in my example:

// Split-tone
vec4 colorDesat = Desaturate(color, 1.0);
vec3 splitColor = texture1D(GradientMap, colorDesat.r).rgb;
vec3 result = BlendColor(color, splitColor);

It’s just the same thing than the Gradient Map… of the Create new fill or adjustment layer in Photoshop but blended in Color mode, which reminds me Color Temperature and Cross-Processing effects :)

Update:

I updated the .glsl file, because I forgot a line in the ContrastSaturationBrightness() function and I had some issues on specific hardware due to conditional returns, so now it’s fixed.

And now, here is the HLSL version :)

Download PhotoshopMath.hlsl

About these ads

30 comments

  1. Great post! Implemented many of the photoshop blend modes in HLSL myself a while ago, but not as many as you’ve done here.


  2. [...] I added the code in my Photoshop Math (GLSL/HLSL) shaders. [...]


  3. Hello, and thanks for your webside and sorry my bad english.

    I will like to know how I change in the fragment shader the HUE of a texture . and not modify the saturation and brithness

    Thanks for all


  4. You can use my code and do:
    vec3 hsl = RGBToHSL(texture2d(yourTexture, yourUV).rgb);
    hsl.x = whateverYouWant; // .x is hue, .y is saturation, .z is brightness
    vec3 color = HSLToRGB(hsl);


  5. Thanks very much.Works well.
    I will see you web page to knews comments.

    Thanks for all.


  6. Hi, I’ve been beating my brains out trying to blend two layers in case both are semitransparent. My results slightly differ from photoshop.

    I write this shader (for ex., for difference):

    // Performs “over”-type blending (colors must be premultiplied by alpha)
    float4 blend(float4 overlying, float4 underlying)
    {
    float3 blended = overlying.rgb + ((1-overlying.a)*underlying.rgb);
    float alpha = underlying.a + (1-underlying.a)*overlying.a;
    return float4(blended, alpha);
    }

    // Performs advanced “over”-type blending
    // (newcolor is the result of advanced blending (for ex, overlying.rgb * underlying.rgb))
    float4 blend(float3 newcolor, float4 overlying, float4 underlying)
    {
    // Here the problem! (I think…)
    float alpha = overlying.a * underlying.a;
    float3 blended = newcolor*alpha + ((1-alpha)*overlying.rgb);

    return blend(float4(blended, overlying.a), underlying);
    }

    // Input images
    sampler2D underlyingSampler : register(s0);
    sampler2D overlyingSampler : register(s1);
    // Opacity of source image
    float opacity : register(c0);

    float4 main(float2 uv : TEXCOORD) : COLOR
    {
    float4 overlying = tex2D(overlyingSampler, uv);
    float4 underlying = tex2D(underlyingSampler, uv);
    overlying.a *= opacity;
    overlying.rgb *= overlying.a;
    underlying.rgb *= underlying.a;

    float4 result = blend(abs(overlying.rgb – underlying.rgb), overlying, underlying);
    return float4(result.rgb/result.a, result.a);
    }


  7. [...] wasn’t working. I tried to figure out what was wrong with it, but eventually I ran into another post that had a different way of expressing the math … it was in HLSL! Plugging in this HLSL worked! [...]


  8. I don’t know If I said it already but …This blog rocks! I gotta say, that I read a lot of blogs on a daily basis and for the most part, people lack substance but, I just wanted to make a quick comment to say I’m glad I found your blog. Thanks, :)

    A definite great read….


  9. In photoshop there are some additional bleding mode that missing here
    1) Darker Color:
    Get the color of color with min luminosity
    float bgLuminosity = 0.3 * bg.Red + 0.59 * bg.Green + 0.11 * bg.Blue;
    float fgLuminosity = 0.3 * fg.Red + 0.59 * fg.Green + 0.11 * fg.Blue;
    if (bgLuminosity fgLuminosity)
    result = bg;
    else
    result = fg;
    2) The second mode is Lighter color:
    Get the color of color with max luminosity
    float bgLuminosity = 0.3 * bg.Red + 0.59 * bg.Green + 0.11 * bg.Blue;
    float fgLuminosity = 0.3 * fg.Red + 0.59 * fg.Green + 0.11 * fg.Blue;
    if (bgLuminosity > fgLuminosity)
    result = bg;
    else
    result = fg;


  10. Just a question.. what license are you releasing this under ?
    Can it be used in a commercial project free of charge ?


  11. The Luminance blend mode seems incorrect, at least if Photoshop CS4 is any sort of reference.

    Photoshop’s Luminance is calculated as:

    Luminance = 0.30R + 0.59G + 0.11B

    You can verify this by placing any image in Luminance blend mode over any grayscale image. Compare the result to taking the original image and using the Channel Mixer (monochrome output) with settings 30, 59 and 11.

    HSL Lightness (L) is calculated as:

    L = (max(R, G, B) – min(R, G, B)) / 2

    This is from your own algorithms. The two formulas are clearly not the same.

    Using U for Luminance, I don’t know what the RGB2HSU formula is (although I could guess) nor what the HSU2RGB formula is. I would love to find out.


  12. [...] Photoshop effects Possibly related posts: (automatically generated)Scenarios for jscJSC Ultra Application to Support [...]


  13. Thanks for this excellent post.
    Will soon be integrated in my soft !


  14. With the HLSL I was able to achieve significantly better performance when using these blending functions without the ‘if’ conditionals. Instead I use the following macro to create an interpolation factor for a lerp:

    #define HardFactor(factor) max(sign(##factor – 0.5), 0)

    That macro results in 0 for values less than 0.5 or 1 for values greater than 0.5. Nice little trick to keep around as long as you use it wisely.


  15. Any chance in these being ported to GLSL ES2?


  16. Xn had a very good question… Can this be used in a commercial application?
    BTW, great blog, very helpful.
    Thanks!


  17. You can use it for a commercial application.
    If you have credits in your game/app, you can have a special thanks for me (Romain Dura), or if you have a blog with screenshots or whatever you can link to this page when you post something using my code.
    And you can reply here with a link to your application/website so we can see what you guys did.
    Whatever you think is right.


  18. Do you think it would be possible to post process the effects achieved using normal maps (bump, parallax), so that you could use deferred shading and not have to push through or use normal maps? Probably you would need some map to encode surface irregularity which if it ended up on the first render would kick the post processor to emulate whatever the encode proposed.


  19. Hi Romain,

    I’m quite new to all the shader stuff and would like some help if possible.

    My goal is to get a photoshop plugin for Mac which will enable to filter a layer and get a CRT like render.

    I get the code for the effect wanted here: http://filespart.com/go/74a8a3f6eedc84b1122a8ce9193c0bf8.html

    Now what could I do with it please?

    I use photoshop CS5 on a Mac with Intel CPU and a GMA 950.

    Thanks in advance.


  20. Hi guys did any know how to compile a hlsl version?
    It seems multiple macro does not supported – like
    #define Blend(base, blend, funcf) float3(funcf(base.r, blend.r), funcf(base.g, blend.g), funcf(base.b, blend.b))

    #define BlendScreen(base, blend) Blend(base, blend, BlendScreenf)

    But when we write it directly in PS : like Blend(float3(), float3(), BlendScreenf) -then it works? Any opinion on such behavior?


  21. compile params i’ve used: fxc /T fx_2_0 /Fo *.fxo *.fx
    the PhotoshopMathFX.hlsl included in the effect file with techniques


  22. [...] the overlay is the Photoshop Overlay Blending Mode. I am using the formulas from this classic post http://mouaif.wordpress.com/2009/01/05/photoshop-math-with-glsl-shaders/. The naïve implementation of the Overlay blending requires one branch for each of the RGB [...]


  23. [...] So these macros make it quite easy to increase or reduce contrast, shift and clip tonal range, lighten or darken shadows and highlights. I added the (GLSL / HLSL) code to the Photoshop Math shaders. [...]


  24. [...] blog Computer graphics, shaders, generative coding « Photoshop math with GLSL shaders Photoshop gamma correction shader » Photoshop math with HLSL shaders January 8, [...]


  25. you saved me a big pile of work. I LOVE YOU. thanks!


  26. [...] o overlay é o Photoshop Overlay Blending Mode, onde as fórmulas consegui nesse post clássico http://mouaif.wordpress.com/2009/01/05/photoshop-math-with-glsl-shaders/. A implementação padrão do overlay requer um condicional para cada um dos canais RGB. [...]


  27. Wow, this is awesome. Thanks for sharing your hard work, you just made my day!


  28. Undeniably consider that which you said. Your favorite justification seemed to be
    on the web the easiest thing to consider of.
    I say to you, I certainly get irked even as other
    folks think about issues that they just don’t know about.
    You managed to hit the nail upon the highest as smartly as defined out the whole thing without
    having side-effects , people can take a signal.

    Will probably be again to get more. Thank you


  29. Generally I do not read post on blogs, but I would like to say that this write-up very
    forced me to try and do it! Your writing taste has been surprised me.
    Thanks, quite great article.



Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: