A while ago I asked for some examples of the effect, while I was pointed to some online articles, the results were really underwhelming. I have since constructed my own effect which at least reacts as it should and is fully configurable.
What this effect does:
It can isolate certain colors (hue's) and desaturate everything around it (scroll down for a screenshot). You can create SinCity like looks or, for example only leave the red channel open instead. You can select this in the GUI and set the range to which the effect should take place around that hue (including surrounding hue's, or not). You can use this effect for various other purposes related to color when you combine it, be creative, it's pretty powerful.
Hue color goes like this where the left represents the value 0.0 and right 1.0. The GUI element to set this is called 'Hue Middle'. The variable 'Hue Range' will tell how much has to be displayed of the colors directly to the left and right of whatever you have selected as Hue Middle.
Nice Hue Middle values to try, but feel free to use whatever you like
Red: 0.0
Yellow: 0.167
Green: 0.333
Cyan: 0.5 (Skyrim sky color is somewhere around 0.55)
Blue: 0.667
Magenta: 0.833
Ie. If I want my picture to contain mainly blue's and green's I would select hue middle: 0.5 and set range 0.333, then I will get blue and green represented at 50% their normal saturation since the max value of hue range is the value at which it becomes greyscale. With the same logic; if I want only reds and exclude everything else I would set hue middle at 0.0 and range at 0.167 (or maybe even smaller if I absolutely don't want to see orange and purple hue's, like 0.083).
Version 1.1
- Modified code a little (cleaner)
- Extended Hue Range from 0.5 max to 1.0 max. At 1.0 max you can use the inverted effect so instead of filtering everything out except a certain color, you can now filter out a certain color and leave everything else in place as well.
Version 1.2
- Bugfix in higher hue ranges, they should react normal now (pink, purples and reds)
- Code changes, other method to calculate Hue and Saturation which is more efficient on GPU
- Can't see any more problems with it, so should be final
Version 1.3
- Added HSL controls on request, need to replace entire code
Version 1.4
- Reworked code to be cleaner and more efficient
Use as you see fit, credits would be appreciated.
GUI elements
Code: Select all
float3 ccFilterLuma <string UIName="Color Filter: Luma"; string UIWidget="Color"; > = {0.2125, 0.7154, 0.0721};
float hueMid < string UIName="Color Filter: Hue Middle"; string UIWidget="Spinner"; float UIMin=0.0; float UIMax=1.0; float UIStep=0.001; > = {0.0};
float hueRange < string UIName="Color Filter: Hue Range"; string UIWidget="Spinner"; float UIMin=0.0; float UIMax=0.9; float UIStep=0.001; > = {0.2};
float satLimit < string UIName="Color Filter: Saturation Limit"; string UIWidget="Spinner"; float UIMin=0.0; float UIMax=1.0; float UIStep=0.001; > = {1.0};
float fxcolorMix < string UIName="Color Filter: Effect Strength"; string UIWidget="Spinner"; float UIMin=0.0; float UIMax=1.0; float UIStep=0.001; > = {1.0};
float HueShiftD < string UIName="Day HSL: Hue Shift"; string UIWidget="Spinner"; float UIMin=0.0; float UIMax=1.0; float UIStep=0.001; > = {0.0};
float SaturationD < string UIName="Day HSL: Saturation"; string UIWidget="Spinner"; float UIMin=0.0; float UIMax=1.0; float UIStep=0.001; > = {0.0};
float LightnessD < string UIName="Day HSL: Highlights"; string UIWidget="Spinner"; float UIMin=0.0; float UIMax=1.0; float UIStep=0.001; > = {0.0};
float ShadowsD < string UIName="Day HSL: Shadows"; string UIWidget="Spinner"; float UIMin=0.0; float UIMax=1.0; float UIStep=0.001; > = {0.0};
float HueShiftN < string UIName="Night HSL: Hue Shift"; string UIWidget="Spinner"; float UIMin=0.0; float UIMax=1.0; float UIStep=0.001; > = {0.0};
float SaturationN < string UIName="Night HSL: Saturation"; string UIWidget="Spinner"; float UIMin=0.0; float UIMax=1.0; float UIStep=0.001; > = {0.0};
float LightnessN < string UIName="Night HSL: Highlights"; string UIWidget="Spinner"; float UIMin=0.0; float UIMax=1.0; float UIStep=0.001; > = {0.0};
float ShadowsN < string UIName="Night HSL: Shadows"; string UIWidget="Spinner"; float UIMin=0.0; float UIMax=1.0; float UIStep=0.001; > = {0.0};
float HueShiftI < string UIName="Interior HSL: Hue Shift"; string UIWidget="Spinner"; float UIMin=0.0; float UIMax=1.0; float UIStep=0.001; > = {0.0};
float SaturationI < string UIName="Interior HSL: Saturation"; string UIWidget="Spinner"; float UIMin=0.0; float UIMax=1.0; float UIStep=0.001; > = {0.0};
float LightnessI < string UIName="Interior HSL: Highlights"; string UIWidget="Spinner"; float UIMin=0.0; float UIMax=1.0; float UIStep=0.001; > = {0.0};
float ShadowsI < string UIName="Interior HSL: Shadows"; string UIWidget="Spinner"; float UIMin=0.0; float UIMax=1.0; float UIStep=0.001; > = {0.0};
Code: Select all
float smootherstep(float edge0, float edge1, float x)
{
x = clamp((x - edge0)/(edge1 - edge0), 0.0, 1.0);
return x*x*x*(x*(x*6 - 15) + 10);
}
float3 HUEToRGB(in float H)
{
float R = abs(H * 6 - 3) - 1;
float G = 2 - abs(H * 6 - 2);
float B = 2 - abs(H * 6 - 4);
return saturate(float3(R,G,B));
}
float Epsilon = 1e-10;
float3 RGBToHCV(in float3 RGB)
{
// Based on work by Sam Hocevar and Emil Persson
float4 P = (RGB.g < RGB.b) ? float4(RGB.bg, -1.0, 2.0/3.0) : float4(RGB.gb, 0.0, -1.0/3.0);
float4 Q = (RGB.r < P.x) ? float4(P.xyw, RGB.r) : float4(RGB.r, P.yzx);
float C = Q.x - min(Q.w, Q.y);
float H = abs((Q.w - Q.y) / (6 * C + Epsilon) + Q.z);
return float3(H, C, Q.x);
}
float3 RGBToHSL(in float3 RGB)
{
float3 HCV = RGBToHCV(RGB);
float L = HCV.z - HCV.y * 0.5;
float S = HCV.y / (1 - abs(L * 2 - 1) + Epsilon);
return float3(HCV.x, S, L);
}
float3 HSLToRGB(in float3 HSL)
{
float3 RGB = HUEToRGB(HSL.x);
float C = (1 - abs(2 * HSL.z - 1)) * HSL.y;
return (RGB - 0.5) * C + HSL.z;
}
HSL Filter will work with curves and not plain adding/subtracting stuff because that's better left to Level controls.
Code: Select all
//COLOR ISOLATION FILTER
float4 r0; float r1; float2 r2;
r0.xyz=saturate(color.xyz);
r0.w=dot(r0.xyz, ccFilterLuma.xyz/dot(ccFilterLuma.xyz, 1));
r1.x=RGBToHSL(r0.xyz).x;
r2.xy=float2(hueMid-hueRange, hueMid+hueRange);
if(r2.y>1 && r1.x<r2.y-1)
r1.x+=1;
if(r2.x<0 && r1.x>r2.x+1)
r1.x-=1;
if(r1.x<hueMid)
r0.xyz=lerp(r0.w, r0.xyz, smootherstep(r2.x, hueMid, r1.x)*satLimit);
if(r1.x>=hueMid)
r0.xyz=lerp(r0.w, r0.xyz, (1-smootherstep(hueMid, r2.y, r1.x))*satLimit);
color.xyz=lerp(color.xyz, r0.xyz, fxcolorMix);
//HSL EFFECTS
r0.xyzw=lerp(lerp(float4(HueShiftN, SaturationN, LightnessN, ShadowsN), float4(HueShiftD, SaturationD, LightnessD, ShadowsD), ENightDayFactor), float4(HueShiftI, SaturationI, LightnessI, ShadowsI), EInteriorFactor);
color.xyz=RGBToHSL(saturate(color.xyz));
color.x=color.x+color.x-step(1, color.x+r0.x);
color.y=color.y+((1-color.y)*(r0.y*color.y));
color.z=color.z+((1-color.z)*(r0.z*color.z));
color.z=color.z+((1-color.z)*(r0.w*(1-color.z)));
color.xyz=HSLToRGB(saturate(color.xyz));
I hope you enjoy :mrgreen:
Cheers.