Tuesday, September 14, 2010

color theory Part I : The tech

The first time you look at something like this

255, 94, 0

your like whaa?? But once you figure out what it is and you use it a while you start seeing it more like this







Or at least hopefully you do. Those three numbers separated by comas, is the RGB that describes a color to the computer. The first one is red, followed by green then blue. You combine those three colors and you will get the color your looking for.

Natively.

Theres another way for the computer to use those numbers. instead of "RGB" the alternative way is "HSL". (well to be honest the computer can do ANYTHING it wants with those numbers. But I really want to talk about HSL cause its fun.)

-The 'H' stands for "hue", which basically defines the color.
-The 'S' stands for "saturation", which basically means all white or all hue. or anywhere in between.
-The 'L' stands for "lightness", which also basically means all black or all hue. or (again) anywhere in between.

This is cool because using RGB can be very difficult if you, say, want to take a color and just make it darker. or would like to cycle through colors to create one of those psychedelic Jeff Minter style things. if you had the color defined as HSL you could just change the H "hue", and you got a different color with the same brightness and saturation. This is how i did the rainbow level in Cygnus.

Now, I know what your saying, Tony!, this sounds AWESOME but how do I convert to and from RGB and HSL? Well I found this c# code online a while ago,


And I converted it to c++ and using openFrameworks(OF is awesome!). This bit will take an RGB color and convert it to HSL...

// Given a Color (RGB Struct) in range of 0-255
// Return H,S,L in range of 0-1
static ofColor twRGB2HSL (ofColor rgb)
{
float r = rgb.r / 255.0f;
float g = rgb.g / 255.0f;
float b = rgb.b / 255.0f;
float v;
float m;
float vm;
float r2, g2, b2;

float h = 0; // default to black
float s = 0;
float l = 0;
v = max(r,g);
v = max(v,b);
m = min(r,g);
m = min(m,b);
l = (m + v) / 2.0;
if (l <= 0.0)
{
ofColor hsl;
hsl.r = h;
hsl.g = s;
hsl.b = l;
return hsl;
}
vm = v - m;
s = vm;
if (s > 0.0)
{
s /= (l <= 0.5) ? (v + m ) : (2.0 - v - m) ;
}
else
{
ofColor hsl;
hsl.r = h;
hsl.g = s;
hsl.b = l;
return hsl;
}
r2 = (v - r) / vm;
g2 = (v - g) / vm;
b2 = (v - b) / vm;
if (r == v)
{
h = (g == m ? 5.0 + b2 : 1.0 - g2);
}
else if (g == v)
{
h = (b == m ? 1.0 + r2 : 3.0 - b2);
}
else
{
h = (r == m ? 3.0 + g2 : 5.0 - r2);
}
h /= 6.0;

ofColor hsl;
hsl.r = h;
hsl.g = s;
hsl.b = l;
return hsl;
}



And this next bit will convert from HSL back to RGB...


// Given H,S,L in range of 0-1
// Returns a Color (RGB struct) in range of 0-255
static ofColor twHSL2RGB(float h, float sl, float l)
{
float v;
float r,g,b;

r = l; // default to gray
g = l;
b = l;
v = (l <= 0.5) ? (l * (1.0 + sl)) : (l + sl - l * sl);
if (v > 0)
{
float m;
float sv;
int sextant;
float fract, vsf, mid1, mid2;

m = l + l - v;
sv = (v - m ) / v;
h *= 6.0;
sextant = (int)h;
fract = h - sextant;
vsf = v * sv * fract;
mid1 = m + vsf;
mid2 = v - vsf;
switch (sextant)
{
case 0:
r = v;
g = mid1;
b = m;
break;
case 1:
r = mid2;
g = v;
b = m;
break;
case 2:
r = m;
g = v;
b = mid1;
break;
case 3:
r = m;
g = mid2;
b = v;
break;
case 4:
r = mid1;
g = m;
b = v;
break;
case 5:
r = v;
g = m;
b = mid2;
break;
}
}
ofColor rgb;
rgb.r = r * 255.0f;
rgb.g = g * 255.0f;
rgb.b = b * 255.0f;
return rgb;
}


The code isn't formatted very well here, but i'm lazy so I don't care.

Coming...(maybe)... color theory part II : The theory