Re: HSV to RGB solution
Posted: Wed Mar 09, 2022 8:22 pm
yeah, I have no idea what could be the cause of that. But, I hacked together this little vision representation of what I'm trying to accomplish here.pgimeno wrote: ↑Wed Mar 09, 2022 12:14 pm Good, but there are still problems. A blue hue is supposed to be at 240°; however, if you look at the image obtained with the main.lua program above, you'll see that primary colours invade the neighbouring secondary colour's hue, forming triangles, instead of being uniformly changing vertical bars. As a result, at s=0.5 and v=1, any hue between 210 and 270 yields the same bright blue colour:And the shorter the saturation, the more each primary colour invades the secondary colour's region (at v=1).Code: Select all
print(HSV(210, 1, 1)) -- prints 0, 0.5, 1 (ok) print(HSV(240, 1, 1)) -- prints 0, 0, 1 (ok) print(HSV(270, 1, 1)) -- prints 0.5, 0, 1 (ok) print(HSV(210, 0.5, 1)) -- prints 0.5, 0.5, 1 (?????) print(HSV(240, 0.5, 1)) -- prints 0.5, 0.5, 1 (ok) print(HSV(270, 0.5, 1)) -- prints 0.5, 0.5, 1 (?????)
As for the clamp() function, I've made a benchmark and in my computer, with 100,000,000 iterations and random inputs, the `max/min` version takes 3.1 seconds while the `if` version takes 3.9 seconds. That's in the ballpark of what I expected.
The dot following the circle represents H and the dot following the triangle represents the 'ratio' between whichever to colors it falls between, or how far along each line segment it lies on. Because I'm basically trying to use that ratio to convert to RGB.
Code: Select all
love.graphics.setDefaultFilter("nearest", "nearest")
local rad = 100
local angle = 0
local ceil = math.ceil
local abs = math.abs
-- hsv alg
local function clamp(v, min, max)
if v < min then return min end
if v > max then return max end
return v
end
function HSV(h, s, v)
v = v or 1; s = ((1 - s) * v) or 0
local vert = clamp(ceil(h / 120), 1, 3)
local rat = abs((h / 60) - 2 * vert)
love.graphics.print(vert)
-- arc to vertex ratios along with extra channel
local r, g = clamp(rat, s, v), clamp((2 - rat), s, v)
-- vertex shift
if vert == 1 then return r, g, s end
if vert == 2 then return s, r, g end
return g, s, r
end
-- visualization
local c = {
rad, 0,
rad * math.cos(2 * math.pi / 3), rad * math.sin(2 * math.pi / 3),
rad * math.cos(4 * math.pi / 3), rad * math.sin(4 * math.pi / 3)
}
local tsize = 24
local a, b = c[3] - c[5], c[4] - c[6]
local l = math.sqrt((a * a) + (b * b)) / 2
local function getCoords(h)
local index = clamp(ceil(h / 120), 1, 3)
local rat = abs((h / 60) - 2 * index)
local dx, dy, x, y
if index == 1 then
dx, dy = c[1] - c[3], c[2] - c[4]
local a = math.atan(dy / dx)
x, y = rat * l * math.cos(a) + c[3], rat * l * math.sin(a) + c[4]
elseif index == 2 then
dx, dy = c[3] - c[5], c[4] - c[6]
local a = math.atan(dy / dx)
x, y = rat * l * math.cos(a) + c[3], rat * l * math.sin(a) - c[4]
else
dx, dy = c[5] - c[1], c[6] - c[2]
local a = math.atan(dy / dx)
x, y = (2 - rat) * l * math.cos(a) + c[5], (2 - rat) * l * math.sin(a) + c[6]
end
return x, y
end
function love.update(dt)
angle = angle + 0.6
if angle >= 359 then
angle = 0
end
end
function love.draw()
love.graphics.setBackgroundColor(0.2, 0.2, 0.2)
love.graphics.translate(love.graphics.getWidth() / 2, love.graphics.getHeight() / 2)
love.graphics.setLineWidth(3)
local h, s, v = HSV(angle, 1, 1)
local x, y = getCoords(angle)
love.graphics.setColor(h, s, v)
love.graphics.polygon("fill", c)
love.graphics.setColor(1, 1, 1)
love.graphics.circle("fill", math.cos(angle * math.pi / 180) * rad, math.sin(angle * math.pi / 180) * rad, 5)
love.graphics.circle("line", 0, 0, rad)
love.graphics.circle("fill", x, y, 5)
love.graphics.polygon("line", c)
love.graphics.setColor(1, 0, 0, 1)
love.graphics.print("R", c[1], c[2] - tsize / 2, 0, 2, 2)
love.graphics.setColor(0, 1, 0, 1)
love.graphics.print("G", c[3] - tsize / 2, c[4], 0, 2, 2)
love.graphics.setColor(0, 0, 1, 1)
love.graphics.print("B", c[5] - tsize / 2, c[6] - tsize, 0, 2, 2)
end