
Fast HSV to RGB Conversion - herbstein
http://www.vagrearg.org/content/hsvrgb
======
seph-reed
If you're ever working with colors and have the cpu time available, I highly
recommend working with luminosity. The gist is, full-bright yellow is brighter
than full-bright purple, they have different luminosities. Anything with a
luminosity of 100% is white.

CIELAB is worth looking into for the color space which best defines how humans
see
([https://en.wikipedia.org/wiki/CIELAB_color_space#RGB_and_CMY...](https://en.wikipedia.org/wiki/CIELAB_color_space#RGB_and_CMYK_conversions)).

Here's some of the relevant code, copied from the private repo I have for this
(legally).

[https://gist.github.com/SephReed/8c762f3434d683c66339f63342e...](https://gist.github.com/SephReed/8c762f3434d683c66339f63342e8ae4b)

~~~
mark-r
That's not universal advice, it depends on the problem domain. Since people
are used to yellow being brighter than purple, if you try to maintain the same
luminosity you can make things totally messed up. If you're trying to recolor
a purple object to yellow, you're unlikely to get a satisfactory result unless
you keep the original intensity - keeping a constant luminosity will give a
too dark result that doesn't even look yellow.

~~~
seph-reed
True. In my scenario I was dealing with procedurally generated UIs based off a
custom color palette. In order to keep things readable, there has to be a
certain level of contrast between text and background. This contrast is based
off perceived brightness (lums) rather than rgb diffs.

I've also used it for LED projects, and it helps a lot with that obnoxious
brighter/darker wave that you get when rotating through hues.

The reason I brought it up in this thread in particular is because it's about
HSV. Anytime I've dealt with HSV, it's because there's some hue rotation going
on. I think HS Lum creates a more intuitive color rotation aesthetic for
things with less saturation. It maintains shading rather than colorfulness.

------
loufe
I just completed a project using wS2811 lights using the FastLED library of
functions. The library was built for effectively the same reason, that the
base functions for converting between different colour sets were inefficient.
I'm curious if some of what was done in Vagrearg is already a part of FastLED.

------
jokoon
To visualize data on a color scale, I just sample the hue with this, I guess
you can also use this to calculate other things.

    
    
        vec3 coolhue(float h){
            if (h == 1.f) return vec3(1.f,0,0);
            h *= 6.0f;
            if(h<1.f) {           return vec3(0, 1.f, h);          } // +blue
            if(h<2.f) { h -= 1.f; return vec3(0, 1.f - h, 1.f);  } // -green
            if(h<3.f) { h -= 2.f; return vec3(h, 0, 1.f);          } // +red
            if(h<4.f) { h -= 3.f; return vec3(1.f, 0, 1.f - h);  } // -blue
            if(h<5.f) { h -= 4.f; return vec3(1.f, h, 0);          } // +green
            if(h<6.f) { h -= 5.f; return vec3(1.f - h, 1.f, 0);  } // -red
            return vec3(1,1,1);
        }
    

This is for GLSL shaders, since shaders don't allow switch()

~~~
contravariant
For shaders you're probably faster off if you use the expression

    
    
        #define saturate(x) clamp(x,0,1)
        rgb = saturate(vec3(abs(hue-180)/60 - 1, 2 - abs(hue-120)/60, 2 - abs(hue-240)/60))
    

Since it avoids the if/then. Although I'm not too sure if it will work well in
GLSL as HLSL has better support for the saturate function (it can usually be
merged with some other operator).

~~~
kaoD
Works fine in GLSL
([https://www.shadertoy.com/view/tdV3DW](https://www.shadertoy.com/view/tdV3DW))

Starting on green and mapped to [0, 1] like op's:

    
    
        vec3 coolhue2(float h){
            float h6 = 6.*h;
    
            return saturate(
                vec3(
                    2. - abs(h6 - 4.),
                    abs(h6 - 3.) - 1.,
                    2. - abs(h6 - 2.)
            ));
        }

