## HSV colour transitions

luminosity
Prole
Posts: 34
Joined: Fri Sep 24, 2010 5:46 am

### HSV colour transitions

Something I did for my game recently was a small colour module to allow me to calculate transitions between two colours using the hsv colour space. This means I can make a gradient from one colour to another, without getting muddy-looking colours in the middle, which transitioning through RGB gets you. For instance, I use it to calculate what colour to draw a hit point bar, from red at 20% or below, to green at 80% or above.

The code is fairly game neutral so I thought people here might potentially find it useful, and it's nice to give back. Consider it public domain.

Code: Select all

local function smallColorRange(largeColor)
return largeColor / 255
end

local function largeColorRange(smallColor)
return math.floor(smallColor * 255 + 0.5)
end

local function pack(...)
return arg
end

local function rgbToHsv(r, g, b)
-- convert rgb from 0-255, to 0-1
r = smallColorRange(r)
g = smallColorRange(g)
b = smallColorRange(b)
local h, s, v
local min = math.min(r, g, b)
local max  = math.max(r, g, b)
local delta = max - min
-- value
v = max
-- saturation
if delta ~= 0 then -- we know max won't be zero, as min can't be less than zero and the difference is not 0
s = delta / max
else
h = -1
s = 0
return h, s, v
end
-- hue
if r == max then -- yellow <-> magenta
h = (g - b) / delta
elseif g == max then -- cyan <-> yellow
h = 2 + (b - r) / delta
else -- magenta <-> cyan
h = 4 + (r - g) / delta
end
h = h * 60 -- 60 degrees
if h < 0 then
h = h + 360
end
return h, s, v
end

local function hsvToRgb(h, s, v)
local r, g, b
if s == 0 then -- monochromatic
-- restore colors from 0-1, to 0-255
r = largeColorRange(v)
g = largeColorRange(v)
b = largeColorRange(v)
return r, g, b
end

h = h / 60 -- sector of wheel
local i = math.floor(h)
local f = h - i -- factorial part of h
local p = v * (1 - s)
local q = v * (1 - s * f)
local t = v * (1 - s * (1 - f))

if i == 0 then
r = v
g = t
b = p
elseif i == 1 then
r = q
g = v
b = p
elseif i == 2 then
r = p
g = v
b = t
elseif i == 3 then
r = p
g = q
b = v
elseif i == 4 then
r = t
g = p
b = v
else
r = v
g = p
b = q
end

r = largeColorRange(r)
g = largeColorRange(g)
b = largeColorRange(b)

return r, g, b
end

if proportion < 0 or proportion > 1 then
error("Gradient proportion must be between 0 and 1.")
end

local h1, s1, v1 = rgbToHsv(unpack(color1))
local h2, s2, v2 = rgbToHsv(unpack(color2))
-- find difference between two values, and advance proportion of that difference from value 1
local hDiff = (h2 - h1) * proportion
local sDiff = (s2 - s1) * proportion
local vDiff = (v2 - v1) * proportion

local gradH = hDiff + h1
local gradS = sDiff + s1
local gradV = vDiff + v1

end

return {
rgbToHsv=rgbToHsv,
hsvToRgb=hsvToRgb,
}

So to use it I'd say

Code: Select all

local Color = require('color')

-- randomly picked probably ugly colours
local red = {200, 20, 20}
local green = {30, 200, 10}
local hpBarColor = Color.gradientColor(red, green, curHP / totalHP)


TechnoCat
Inner party member
Posts: 1611
Joined: Thu Jul 30, 2009 12:31 am
Location: Denver, CO
Contact:

### Re: HSV colour transitions

Oh my, HSV is very yummy.
Colorful Cake.
800px-HSV_color_solid_cylinder_alpha_lowgamma.png (253.63 KiB) Viewed 772 times
The hue saturation approach to color is very useful indeed. Thank you for the contribution.

Taehl
Dreaming in associative arrays
Posts: 1024
Joined: Mon Jan 11, 2010 5:07 am
Location: CA, USA
Contact:

### Re: HSV colour transitions

I, personally, prefer HSL, Photoshop be damned. I've put my conversion function on the wiki, in case anyone wants it.
Earliest Love2D supporter who can't Love anymore. Let me disable pixel shaders if I don't use them, dammit!
Lenovo Thinkpad X60 Tablet, built like a tank. But not fancy enough for Love2D 0.10.0+.

### Who is online

Users browsing this forum: No registered users and 51 guests