I’m trying to write a simple shader to hue shift sprites by converting from RGB to HSV, adjusting hue, then shifting back. I’ve tried to adapt the formula’s found at this website (http://www.easyrgb.com/en/math.php) but when I convert from RGB to HSV then back without hue shifting I’m still getting the hue changed.
Here are the shader functions
float3 RGBtoHSV(in float3 rgb)
{
//R, G and B input range = 0 ÷ 255
//H, S and V output range = 0 ÷ 1.0
float H;
float S;
float V;
float R = (rgb[0] / 255);
float G = (rgb[1] / 255);
float B = (rgb[2] / 255);
float cMin = min(min(R, G), B);
float cMax = max(max(R, G), B);
float delta = cMax - cMin;
V = cMax;
if (cMax == 0)
{
H = 0;
S = 0;
}
else
{
S = delta / cMax;
float del_R = (((cMax - R) / 6) + (delta / 2)) / delta;
float del_G = (((cMax - G) / 6) + (delta / 2)) / delta;
float del_B = (((cMax - B) / 6) + (delta/ 2)) / delta;
if (R == cMax) H = del_B - del_G;
else if (G == cMax) H = (1 / 3) + del_R - del_B;
else if (B == cMax) H = (2 / 3) + del_G - del_R;
H = H % 1.0;
}
return float3(H, S, V);
}
float3 HSVtoRGB(in float3 hsv)
{
//H, S and V input range = 0 ÷ 1.0
//R, G and B output range = 0 ÷ 255
float H = hsv[0];
float S = hsv[1];
float V = hsv[2];
float R;
float G;
float B;
float var_r;
float var_g;
float var_b;
if (S == 0)
{
R = V * 255;
G = V * 255;
B = V * 255;
}
else
{
float var_h = H * 6;
if (var_h == 6) var_h = 0; //H must be < 1
float var_i = floor(var_h); //Or ... var_i = floor( var_h )
float var_1 = V * (1 - S);
float var_2 = V * (1 - S * (var_h - var_i));
float var_3 = V * (1 - S * (1 - (var_h - var_i)));
if (var_i == 0) { var_r = V; var_g = var_3; var_b = var_1; }
else if (var_i == 1) { var_r = var_2; var_g = V; var_b = var_1; }
else if (var_i == 2) { var_r = var_1; var_g = V; var_b = var_3; }
else if (var_i == 3) { var_r = var_1; var_g = var_2; var_b = V; }
else if (var_i == 4) { var_r = var_3; var_g = var_1; var_b = V; }
else { var_r = V; var_g = var_1; var_b = var_2; }
R = var_r * 255;
G = var_g * 255;
B = var_b * 255;
}
return float3(R, G, B);
}
float4 MainPS(VertexShaderOutput input) : COLOR
{
// get sprite color
float4 color = tex2D(s0, input.TextureCoordinates);
// Convert to HSV
float3 hsv = RGBtoHSV(float3(color.r, color.g, color.b));
// Convert back to RGB
float3 newColor = HSVtoRGB(hsv);
// Set new color
color = float4(newColor[0], newColor[1], newColor[2], color.a);
return color;
}
The texture I’m passing in looks like this
And the image out I’m getting looks like this
When I compare the HSV values of the result vs the original image, it seems that saturation and value are both being computed correctly but the hue is off. For instance sampling 3 different pixels I found
(original → result): 0 → 60, 116 → 303, 336 → 60.
This relation doesn’t seem linear so I don’t think I can just do a simple adjustment in the code to fix it.
Does anybody have any ideas about what is going wrong here? Or some resources/existing shaders for RGB → HSV and back?