Hue, saturation, brightness, contrast effect in hlsl

Posted by Vibhore Tanwer on Game Development See other posts from Game Development or by Vibhore Tanwer
Published on 2012-05-08T10:27:41Z Indexed on 2012/06/02 4:50 UTC
Read the original article Hit count: 2230

Filed under:
|

I am new to pixel shader, and I am trying to write a simple brightness, contrast, hue, saturation effect. I have written a shader for it but I doubt that my shader is not providing me correct result, Brightness, contrast, saturation is working fine, problem is with hue. if I apply hue between -1 to 1, it seems to be working fine, but to make things more sharp, I need to apply hue value between -180 and 180, like we can apply hue in Paint.NET.

Here is my code.

// Amount to shift the Hue, range 0 to 6
float Hue;
float Brightness;
float Contrast;
float Saturation;
float Alpha;

sampler Samp : register(S0);

// Converts the rgb value to hsv, where H's range is -1 to 5
float3 rgb_to_hsv(float3 RGB)
{
    float r = RGB.x;
    float g = RGB.y;
    float b = RGB.z;

    float minChannel = min(r, min(g, b));
    float maxChannel = max(r, max(g, b));

    float h = 0;
    float s = 0;
    float v = maxChannel;

    float delta = maxChannel - minChannel;

    if (delta != 0)
    {
        s = delta / v;

        if (r == v) h = (g - b) / delta;
        else if (g == v) h = 2 + (b - r) / delta;
        else if (b == v) h = 4 + (r - g) / delta;
    }

    return float3(h, s, v);
}

float3 hsv_to_rgb(float3 HSV)
{
    float3 RGB = HSV.z;

    float h = HSV.x;
    float s = HSV.y;
    float v = HSV.z;

    float i = floor(h);
    float f = h - i;

    float p = (1.0 - s);
    float q = (1.0 - s * f);
    float t = (1.0 - s * (1 - f));

    if (i == 0) { RGB = float3(1, t, p); }
    else if (i == 1) { RGB = float3(q, 1, p); }
    else if (i == 2) { RGB = float3(p, 1, t); }
    else if (i == 3) { RGB = float3(p, q, 1); }
    else if (i == 4) { RGB = float3(t, p, 1); }
    else /* i == -1 */ { RGB = float3(1, p, q); }

    RGB *= v;

    return RGB;
}

float4 mainPS(float2 uv : TEXCOORD) : COLOR
{
    float4 col = tex2D(Samp, uv);

    float3 hsv = rgb_to_hsv(col.xyz);

    hsv.x += Hue;
    // Put the hue back to the -1 to 5 range
    //if (hsv.x > 5) { hsv.x -= 6.0; }
    hsv = hsv_to_rgb(hsv);
    float4 newColor = float4(hsv,col.w);

    float4 colorWithBrightnessAndContrast = newColor;

    colorWithBrightnessAndContrast.rgb /= colorWithBrightnessAndContrast.a;
    colorWithBrightnessAndContrast.rgb = colorWithBrightnessAndContrast.rgb + Brightness;
    colorWithBrightnessAndContrast.rgb = ((colorWithBrightnessAndContrast.rgb - 0.5f) * max(Contrast + 1.0, 0)) + 0.5f;  
    colorWithBrightnessAndContrast.rgb *= colorWithBrightnessAndContrast.a;

    float greyscale = dot(colorWithBrightnessAndContrast.rgb, float3(0.3, 0.59, 0.11)); 
    colorWithBrightnessAndContrast.rgb = lerp(greyscale, colorWithBrightnessAndContrast.rgb, col.a * (Saturation + 1.0));       
    return colorWithBrightnessAndContrast;
}

technique TransformTexture {
    pass p0 {
        PixelShader = compile ps_2_0 mainPS();
    }
}

Please If anyone can help me learning what am I doing wrong or any suggestions? Any help will be of great value.

EDIT: Images of the effect at hue 180:

effect On the left hand side, the effect I got with @teodron answer. On the right hand side, The effect Paint.NET gives and I'm trying to reproduce.

© Game Development or respective owner

Related posts about hlsl

Related posts about pixel-shader