Blend Modes: Hue, Saturation, Color, and Luminosity with WPF 4.0

I’ve been toying with and working on this blend mode library of mine for some time now (see posts 1, 2, 3, 4, 5). However, it is now only with WPF 4.0 (currently Beta 2) … that I can actually implement all the blend modes.

Hue, Saturation, Color, and Luminosity: Where Are You?

If you were watching closely, you will have noticed that I have not (to date) implemented the Hue, Saturation, Color, and Luminosity blend mode effects.

Why is that? Whenever fxc.exe would compile the .fx file (through the Shader Effects BuildTask and Templates), it would give me the following two errors:

  • error X5608: Compiled shader code uses too many arithmetic instruction slots (100). Max. allowed by target (ps_2_0) is 64.
  • error X5609: Compiled shader code uses too many instruction slots (102). Max. allowed by the target (ps_2_0) is 96.

Those errors mean that you’ve exceeded the limitations of Pixel Shader 2.0 … which is what WPF 3.5 SP1 targets for pixel shader effects.

So, what can you do about this? You could optimize the HLSL so that your effect code goes under the limits … but if you notice in the errors above (these particular errors are for the Saturation effect) … you will see that I am significantly above the number of allowed arithmetic instruction slots (100 versus 64). I would have to optimize significantly.

WPF 4.0 to the Rescue

Another option is to utilize WPF 4.0!

WPF 4.0 increases what you can do with effects because it now allows you to target Pixel Shader 3.0. This wikipedia article has a great chart on the differences between the different shader models. With PS 3.0, we shouldn’t hit any limits.

Realizing this, as soon as Visual Studio 2010 and .NET 4 Beta 2 came out (PS 3.0 is only available in Beta 2), I installed it and gave it a whirl. There was really only one gotcha in getting this to work. The Shader Effects BuildTask only compiles to PS 2.0 … and there is no option to toggle between PS 2.0 and PS 3.0.

This means that, for now, probably until release, you will have to manually run fxc.exe (targeting ps_3_0) and add the compiled shader output file (the .ps file) to the project as a Resource.

Caveats

There are some caveats to using PS 3.0 in WPF 4.0. Most notably, there is no software fallback if your hardware or situation (remote desktop, forced software rendering) don’t support it. This means that your effect code will simply not run and not appear.

Some good news is that Microsoft has extended the RenderCapability API so that you can determine what level of pixel shader support is currently available. They’ve updated the RenderCapability.IsPixelShaderVersionSupported method and have added two additional methods: RenderCapability.IsPixelShaderVersionSupportedInSoftware and RenderCapability.MaxPixelShaderInstructionSlots.

(The above information and more is available in David Teitlebaum’s PDC09 session titled Mastering WPF Graphics and Beyond. Jamie Rodriguez also has some great posts covering what’s new in WPF 4.0 (Beta 1, Beta 2).)

Another caveat that bears mentioning is that Silverlight (both 3.0 and 4.0) only support PS 2.0. So, if you are creating and using effects across both technologies, you will not be able to use PS 3.0. This also means that the Hue, Saturation, Color, and Luminosity blend modes (and the attached code) are WPF only blend modes. Sorry Silverlight! I love you, but that’s how the chips fall.

Hue, Saturation, Color, and Luminosity: Here They Are!

Alright … enough with the caveats! Let’s see the effects!

First, let me refer you back to Angie Bowen’s post where she covers what each blend mode does … including the Hue, Saturation, Color and Luminosity effects.

To show off what each effect does, I’m going to go ahead and use her reference images … first showing how they blend out of Photoshop … and then showing how they blend with my library … for comparison purposes. Why? Well, it seems as if my blend mode library does not always match what is coming out of Photoshop … sometimes it’s pretty darn close and at other times it’s more than just a little bit off.

I have been through and through the math (and HLSL) for these effects and I honestly can’t find anything wrong there. If I could speculate what is going on, I would say that I’m bumping up against some float versus double precision issues (where Photoshop is using doubles for greater precision) during the conversion from RGB to HSL and back. If you can figure out what I’ve done wrong (if anything) please let me know.

However, for the most part, they work great!

Hue Blend Mode

The result is the hue of the blend layer and the saturation and luminance of the base layer.

Photoshop

HuePhotoshop

My Blend Mode Library

Hue

Photoshop

Hue2Photoshop

My Blend Mode Library

Hue2

Saturation Blend Mode

The result is the saturation of the blend layer and the hue and luminance of the base layer.

Photoshop

SaturationPhotoshop

My Blend Mode Library

Saturation

Photoshop

Saturation2Photoshop

My Blend Mode Library

Saturation2

Color Blend Mode

The result is luminance of the base layer and the hue and the saturation of the blend layer.

Photoshop

ColorPhotoshop

My Blend Mode Library

Color

Photoshop

Color2Photoshop

My Blend Mode Library

Color2

Luminosity Blend Mode

The result is hue and the saturation of the base layer and the luminosity of the blend layer.

Photoshop

LuminosityPhotoshop

My Blend Mode Library

Luminosity

Photoshop

Luminosity2Photoshop

My Blend Mode Library

Luminosity2

The Binaries and the Source Code

Here is the source code for the library and here is the assembly.

Again, remember that this is a WPF-only release as Silverlight does not yet have support for Pixel Shader 3.0.

Also, all of these new blend modes are opacity aware … meaning that you can pull the opacity out of the upper layer to lessen the effect of the blend mode (see my last post on the matter).

Enjoy!

p.s.

At one point, I thought that the Shader Effects BuildTask and Templates was built into Visual Studio 2010. It appears I was mistaken about that. I have updated this post to indicate that.

5 thoughts on “Blend Modes: Hue, Saturation, Color, and Luminosity with WPF 4.0”

  1. I have a line of code that may help. Sorry, I have not tested it with your solution as I don’t have .NET 4.

    In float3 RGBToHSL(float3 color), change the last if statement:

    if (hsl.x < 0.0)
    {
        // hsl.x += 1.0;
        hsl.x = 0 - hsl.x;
    }
    

    I think there was a problem when hue wraps round.

    Hope it helps – David

  2. Just tried it David … unfortunately, it doesn’t help. 🙁

    Thanks for leaving a comment though! I’m willing to try anything.

    Another fellow contacted me via email and said that the differences are a result of Photoshop using a completely different model for computing what it calls hue/saturation/luminosity than what I am using. In this diagram, I am using the bottom middle … and Photoshop is using the bottom right.

    If he ever drafts the math to convert back and forth between that HSL model and RGB, I’ll integrate it in … and see if it matches!

  3. Hello Cory,

    I have very little experience with HLSL so I’m asking for some assistance in understanding. All of the shaders you provided are good-to-go but I wanted to know if there is a way to control the output of some of them with a 0.0 to 1.0 valued variable. For example, with the saturation effect, it would be nice to have a constant that I can change in .NET from 0 (which gives the normal color saturation), and change it to 1 (which means no color saturation at all).

    – Rashad Rivera

  4. @Rashad:
    I’m not quite sure what you are asking, but I have implemented these blend modes so that the Opacity of the upper layer (B) can be modified to lessen the effect of blending (by changing the Opacity to a value less than 1.0).

    It sounds like you are asking how to create an effect which doesn’t blend two layers together but simply takes the Saturation out of whatever you are applying the effect to. If so, then you can use the the RGB to HSL conversion methods that are included in the effects above (Hue, Saturation, Luminosity, and Color) to do that.

    Also, are you using WPF 3.5? If so, you might run into the PS 2.0 shader boundary (number of instructions). If you use WPF 4.0 and take advantage of PS 3.0 … then realize that the software renderer in WPF 4.0 doesn’t handle PS 3.0 shaders (meaning that if the video card doesn’t support PS 3.0 … WPF will do nothing).

    Hope that helps.

    Hmmm. I could quite easily write that Saturation effect. It
    would be kind of a nice effect to disable a control … without making it transparent. Let me know if you want me to give it a whirl.

Leave a Reply