redcodefinal
redcodefinal

Reputation: 909

HSV to RGB Stops at yellow C#

I'm writing an HSVtoRGB method for my game framework, and when going through the hues, this happens -> http://youtu.be/ACBwR_0iMWE.

Here is the code.

public static Color HSVtoRGB(float hue, float saturation, float value, float alpha)
    {
        if(hue > 1 || saturation > 1  || value > 1) throw new Exception("values cannot be more than 1!");
        if (hue < 0 || saturation < 0|| value < 0) throw new Exception("values cannot be less than 0!");

        Color output = new Color();
        if (Math.Abs(saturation) < 0.001)
        {
            output.R = (byte) (value*byte.MaxValue);
            output.G = (byte) (value*byte.MaxValue);
            output.B = (byte) (value*byte.MaxValue);
        }
        else
        {
            hue = hue/60f;
            float f = hue - (int)hue;
            float p = value*(1f - saturation);
            float q = value*(1f - saturation*f);
            float t = value*(1f - saturation*(1f - f));
            switch ((int)hue)
            {
                case (0) :
                    output = new Color(value * 255, t * 255, p * 255, alpha);
                    break;
                case (1):
                    output = new Color(q * 255, value * 255, p * 255, alpha);
                    break;
                case (2):
                    output = new Color(p * 255, value * 255, t * 255, alpha);
                    break;
                case (3):
                    output = new Color(p * 255, q * 255, value * 255, alpha);
                    break;
                case (4):
                    output = new Color(t * 255, p * 255, value * 255, alpha);
                    break;
                case (5):
                    output = new Color(value * 255, p * 255, q * 255, alpha);
                    break;
                default :
                    throw new Exception("RGB color unknown!");
            }

        }
        return output;
    }

When adding .001f to the hue, it cause it to go from red to yellow but then sticks at yellow until it rolls back over to 0. Please note I am using Microsoft.Xna.Framework.Color not System.Drawing.Color.

For reference, here is the HSVtoRGB method of Flixel Power Tools, basically what I am trying to copy.

        public static function HSVtoRGB(h:Number, s:Number, v:Number, alpha:uint = 255):uint
    {
        var result:uint;

        if (s == 0.0)
        {
            result = getColor32(alpha, v * 255, v * 255, v * 255);
        }
        else
        {
            h = h / 60.0;
            var f:Number = h - int(h);
            var p:Number = v * (1.0 - s);
            var q:Number = v * (1.0 - s * f);
            var t:Number = v * (1.0 - s * (1.0 - f));

            switch (int(h))
            {
                case 0:
                    result = getColor32(alpha, v * 255, t * 255, p * 255);
                    break;

                case 1:
                    result = getColor32(alpha, q * 255, v * 255, p * 255);
                    break;

                case 2:
                    result = getColor32(alpha, p * 255, v * 255, t * 255);
                    break;

                case 3:
                    result = getColor32(alpha, p * 255, q * 255, v * 255);
                    break;

                case 4:
                    result = getColor32(alpha, t * 255, p * 255, v * 255);
                    break;

                case 5:
                    result = getColor32(alpha, v * 255, p * 255, q * 255);
                    break;

                default:
                    FlxG.log("FlxColor Error: HSVtoRGB : Unknown color");
            }
        }

        return result;
    }

Upvotes: 2

Views: 6574

Answers (2)

mcmonkey4eva
mcmonkey4eva

Reputation: 1377

I wrote up my own HSV->RGB converter based on your code...

(And also your link to http://www.easyrgb.com/index.php?X=MATH&H=21#text21 )

The code is:

    public static Color HSVtoRGB(float hue, float saturation, float value, float alpha)
    {
        while (hue > 1f) { hue -= 1f; }
        while (hue < 0f) { hue += 1f; }
        while (saturation > 1f) { saturation -= 1f; }
        while (saturation < 0f) { saturation += 1f; }
        while (value > 1f) { value -= 1f; }
        while (value < 0f) { value += 1f; }
        if (hue > 0.999f) { hue = 0.999f; }
        if (hue < 0.001f) { hue = 0.001f; }
        if (saturation > 0.999f) { saturation = 0.999f; }
        if (saturation < 0.001f) { return new Color(value * 255f, value * 255f, value * 255f); }
        if (value > 0.999f) { value = 0.999f; }
        if (value < 0.001f) { value = 0.001f; }

        float h6 = hue * 6f;
        if (h6 == 6f) { h6 = 0f; }
        int ihue = (int)(h6);
        float p = value * (1f - saturation);
        float q = value * (1f - (saturation * (h6 - (float)ihue)));
        float t = value * (1f - (saturation * (1f - (h6 - (float)ihue))));
        switch (ihue)
        {
            case 0:
                return new Color(value, t, p, alpha);
            case 1:
                return new Color(q, value, p, alpha);
            case 2:
                return new Color(p, value, t, alpha);
            case 3:
                return new Color(p, q, value, alpha);
            case 4:
                return new Color(t, p, value, alpha);
            default:
                return new Color(value, p, q, alpha);
        }
    }

With it, I rendered this: Screenshot

A few things worth noting:

  • new Color(...) takes input from 0 to 1, not 0 to 255.
  • Ensure the difference between ints and floats is always clear
  • Don't throw an exception every time the situation is less than perfect. Try to adapt where possible.
  • When you have borrowed code from some other program, and also a perfect mathematical reference... try to copy the mathematical site before the borrowed code - who knows what sort of weird situation-specific modifications were made from the proper math?

Upvotes: 2

gareththegeek
gareththegeek

Reputation: 2418

At the start of the method Hue is restricted to 0.0f .. 1.0f It is then divied by 60f so it is now in the range 0.0f .. 1/60.0f

Then you are switching on (int)hue which will always be zero.

I don't think the other branches of your switch will ever execute.

Upvotes: 2

Related Questions