Posts Tagged ‘photoshop’


Levels control shader

January 28, 2009

A little piece of code to reproduce the Levels control of Photoshop…


Input levels:

I already talked about the gamma correction (mid-tone slider), and I won’t explain what the shadows and highlights (black/white points) sliders are doing (excellent article here) but basically these can be used to remap the tonal range of the image. Here is how it’s calculated:

#define GammaCorrection(color, gamma)  pow(color, vec3(1.0 / gamma))
#define LevelsControlInputRange(color, minInput, maxInput) min(max(color – vec3(minInput), vec3(0.0)) / (vec3(maxInput) – vec3(minInput)), vec3(1.0))
#define LevelsControlInput(color, minInput, gamma, maxInput) GammaCorrection(LevelsControlInputRange(color, minInput, maxInput), gamma)

Example with values from the 1st screenshot (blackpoint = 90/255, gamma = 4, whitepoint = 150/255), red: original color, green: blackpoint & whitepoint modified, blue: same with gamma:


Output levels:

This is useful to shorten the tonal range meaning compressing it to reduce contrast and shift it, details here.

#define LevelsControlOutputRange(color, minOutput, maxOutput) mix(vec3(minOutput), vec3(maxOutput), color)

Example with values from the 1st screenshot (min output = 40/255, max output = 180/255), red: original color, green: output levels applied:


Putting it all together:

#define LevelsControl(color, minInput, gamma, maxInput, minOutput, maxOutput) LevelsControlOutputRange(LevelsControlInput(color, minInput, gamma, maxInput), minOutput, maxOutput)

Same example but both input and output levels taken into account, red: original color, green: final result:


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.


Photoshop gamma correction shader

January 22, 2009

After reproducing contrast, hue, saturation, brightness controls of Photoshop in pixel shaders, here is the gamma correction filter 🙂



There are 2 ways of changing gamma in Photoshop:

  • Image | Adjustments | Exposure…
  • Image | Adjustments | Levels… (or CTRL+L) and then move the midtone slider.

Gamma correction is not the same thing than Brightness at all, even if it can give the impression it is. For example here is the histogram of my original image:


Then after setting the gamma to 0.5 (it compresses the highlights and stretches the shadows):


And here it is after lowering the brightness (Image | Adjustments | Brightness/Contrast…):


Here you can see it clipped the values after some threshold in the shadows (and also in the highlights) and you’re loosing a lot of lighting information in this case. That’s actually why I wanted to have also a gamma control in my post-processing effects.


A little macro:

// Gamma from 9.99 to 0.1
#define GammaCorrection(color, gamma)   pow(color, 1.0 / (gamma))

color = GammaCorrection(color, 0.1);

Here are the curves it produces with extreme values (limits of Photoshop [9.99, 0.1]):


So you see it stays in the same range and give a non-linear luminance (if correction value is different than 1). By the way I used this awesome web function grapher here.

By zooming and taking a very close look I noticed a few tiny differences with Photoshop in the shadows (seriously you need to toggle screenshot from shader and photoshopped image quickly and scan the image to see where it’s not the same). Photoshop on the left, shader version on the right (gamma = 0.1).


I also saw that the gamma in Photoshop (on the left) produced some banding artefacts somewhere, and it didn’t in my shader (on the right),  well.. :):


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


Photoshop math with HLSL shaders

January 8, 2009

See my original post about Photoshop math in GLSL (blending modes, contrast, desaturation, RGB to HSL). Now it’s also in HLSL!

Download PhotoshopMath.hlsl


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:



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


  • 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


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 🙂


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