float HCLgamma = 3;
float HCLy0 = 100;
float HCLmaxL = 0.530454533953517; // == exp(HCLgamma / HCLy0) - 0.5
float PI = 3.1415926536;
float3 HCLtoRGB(in float3 HCL)
{
float3 RGB = 0;
if (HCL.z != 0)
{
float H = HCL.x;
float C = HCL.y;
float L = HCL.z * HCLmaxL;
float Q = exp((1 - C / (2 * L)) * (HCLgamma / HCLy0));
float U = (2 * L - C) / (2 * Q - 1);
float V = C / Q;
// PROBLEM HERE...
float T = tan((H + min(frac(2 * H) / 4, frac(-2 * H) / 8)) * PI * 2);
H *= 6;
if (H <= 1)
{
RGB.r = 1;
RGB.g = T / (1 + T);
}
else if (H <= 2)
{
RGB.r = (1 + T) / T;
RGB.g = 1;
}
else if (H <= 3)
{
RGB.g = 1;
RGB.b = 1 + T;
}
else if (H <= 4)
{
RGB.g = 1 / (1 + T);
RGB.b = 1;
}
else if (H <= 5)
{
RGB.r = -1 / T;
RGB.b = 1;
}
else
{
RGB.r = 1;
RGB.b = -T;
}
RGB = RGB * V + U;
}
return RGB;
}
|
Note the calculation of 'T'. Let's split that expression in two:
float A = H + min(frac(2 * H) / 4, frac(-2 * H) / 8);
float T = tan(A * PI * 2);
|
We can see that 'T' will tend to infinity when 'A' approaches 0.25 or 0.75. A bit of careful graphing of 'H' against 'A' suggests that this only occurs when the input hue approaches 1/6 or 2/3 respectively, so we can put extra checks in the sextant clauses:
float A = (H + min(frac(2 * H) / 4, frac(-2 * H) / 8)) * PI * 2;
float T;
H *= 6;
if (H <= 0.999)
{
T = tan(A);
RGB.r = 1;
RGB.g = T / (1 + T);
}
else if (H <= 1.001)
{
RGB.r = 1;
RGB.g = 1;
}
else if (H <= 2)
{
T = tan(A);
RGB.r = (1 + T) / T;
RGB.g = 1;
}
else if (H <= 3)
{
T = tan(A);
RGB.g = 1;
RGB.b = 1 + T;
}
else if (H <= 3.999)
{
T = tan(A);
RGB.g = 1 / (1 + T);
RGB.b = 1;
}
else if (H <= 4.001)
{
RGB.g = 0;
RGB.b = 1;
}
else if (H <= 5)
{
T = tan(A);
RGB.r = -1 / T;
RGB.b = 1;
}
else
{
T = tan(A);
RGB.r = 1;
RGB.b = -T;
}
|
Of course, if you're confident that your platform won't throw too much of a wobbly when computing 'tan' of half pi et al, you can hoist the calculation of 'T' to its declaration before the 'if' clauses. You never know your luck: your shader compiler might to that for you!
Having said all that, the more I read about the HCL colour space, the less I'm convinced it's actually worthwhile.