Saturday, 3 October 2015

RGB/HSV in HLSL 7

I got a very kind email from David Schaeffer yesterday with some bug fixes for the shader code I wrote for converting RGB to the HCY colour space.

My original implementation was

  float3 RGBtoHCY(in float3 RGB)
  {
    float3 HCV = RGBtoHCV(RGB);
    float Y = dot(RGB, HCYwts);
    if (HCV.y != 0)
    {
      float Z = dot(HUEtoRGB(HCV.x), HCYwts);
      if (Y > Z)
      {
        Y = 1 - Y;
        Z = 1 - Z;
      }
      HCV.y *= Z / Y;
    }
    return float3(HCV.x, HCV.y, Y);
  }

As he points out:
It seems to me that you have an error in your RGB to HCY code, though.  I was having some pixels always saturate to white, and after looking at Kuzma Shapran's original code I don't think the value of Y should actually be changed, only using the adjusted value of Y to calculate HCV.y.  Additionally I think the check for 0 in the original code was meant to prevent divide by 0 errors, so should be using Y instead of HCV.y.
I'll have to bow to David's superior knowledge on HCY usage as I've never actually used it in anger. So here's his improved version:

  float3 RGBtoHCY(in float3 RGB)
  {
    float3 HCV = RGBtoHCV(RGB);
    float Y = dot(RGB, HCYwts);
    float Z = dot(HUEtoRGB(HCV.x), HCYwts);
    if (Y < Z)
    {
      HCV.y *= Z / (Epsilon + Y);
    }
    else
    {
      HCV.y *= (1 - Z) / (Epsilon + 1 - Y);
    }
    return float3(HCV.x, HCV.y, Y);
  }

I've updated the snippets page accordingly.

No comments:

Post a Comment