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


Real-Time Peter de Jong Attractors

December 15, 2008

A simple B&W version. Again, everything is done on the CPU, running at 80fps on my single core 3500+. 10000 iterations per frame. Random but still a bit too cyclic due to my way of changing the attractor’s parameters (almost same frequency and amplitude a bit too extreme causing these empty frames). It also does produce blank frames with specific parameter values (not necessarily extremes), wonder if that’s the same with Clifford attractors.


Attractors & Quartz Composer

November 11, 2008

I’ve been playing a bit more with NodeBox the other day, trying to render Peter De Jong attractors. Something I already tried in my (unnamed) Editor with Ogre. Here is a video my first real-time experiment with Ogre (30FPS on a 3500+, don’t care about the GPU since the attractors iterations run on the CPU):

Actually I accelerated the video 3x the normal speed.

So, I tried to do it another way with NodeBox and I started from this little code (thanks btw) and made things animated and exported to a movie (things like this go very slow in real-time with this tool):

And then during a right click / Open with … I just remembered I had Quartz Composer. I had no idea how it works but this is actually the kind of tool I was looking for lately 🙂 Here are 2 quick tests I made from my previous B&W video:

A few simple image operators and blending patches and we’re done.



Experimenting NodeBox

June 13, 2008

Heya! I recently discovered NodeBox, amazing software dedicated to computational art / creative & generative programming. I’m not gonna (re-)present anything about it, but here are some videos of my first two attempts with this fantastic tool.

Just changed 1 or 2 things from this little tutorial. If you keep looking at the center point, after watching the video, you’ll see the stopped image rotating in the inverse direction, heh.

The next one is another variation with some colors and cubes, and just a different way to rotate some objects.


CrossProcessing shader

June 11, 2008

Hi ! I’m doing a lot of image processing at work since a few weeks, and there a lots of things I wanna try, from post processes to dynamic geometry, but I would need another life for that. After having watched some (really nice) super cars videos (just check at the first one showing the Corvette to see what I mean), I’ve been talking with Nico about the Cross Processing effect, also called xpro, used in photography, and probably in the Corvette video.

corvette cross processing

corvette cross processing

corvette cross processing

corvette cross processing

After a quick talk (thanks) I made a simple pixel shader that post process a given scene with this nice effect 🙂

I followed this Photoshop tutorial to make it, here are the steps to work with the shader:

  • Make a black-to-white gradient
  • Add a New fill or adjustment layer, select Curves, and set the curves just like in the tutorial

cross processing curves gradient

  • Save the 1D image, it’ll be used in the pixel shader just like a curve modifier
  • Modify the final color of your pixels with this (GLSL) code:

vec3 curvesColor;

curvesColor.r = texture1D(curveTex, pixelColor.r ).r;
curvesColor.g = texture1D(curveTex, pixelColor.g).g;
curvesColor.b = texture1D(curveTex, pixelColor.b).b;

gl_FragColor.rgb = curvesColor;

And voila ! Here are some screenshots I took in Reverse (my end of studies project [team of 6 students]), maybe not the best example for this kind of effect but anyway:

reverse no cross processing shader

reverse no cross processing shader

reverse no cross processing shader

reverse no cross processing shader

reverse no cross processing shader

reverse no cross processing shader

In fact it makes me think about color temperature again, but this time the color is modifyed per channel and is dependent to the color components themselves instead of the luminance component of the pixel.

One more screen with all the effects combined during turbo (dolly zoom, desaturation, radial motion blur):

reverse no cross processing shader

Well, I guess these are the first public screenshots of the final version of the game 🙂

Oh and by the way


Kinda color temperature

May 6, 2008

Hi all, I’m not dead.

I saw an interesting image the other day, that directly made me think about the color temperature concept. It comes from the game Fallen Empire: Legions, upcoming Tribes clone running in a web browser on instantaction.com. It produces another interesting effect, because it seems to use another color palette and still link it to the luminance of the object’s pixels.

legions color temperature

Maybe they’re not doing anything like this to get this particular lighting and they are using multiple lights or even any photoshop treatment, but it could be and that’s the way I interpreted it 🙂