SliiX wrote: ↑Mon Mar 07, 2022 10:40 pm
pgimeno wrote: ↑Sat Mar 05, 2022 5:20 pm
Did you measure using LuaJIT? Can you show your benchmark?
I've found two major problems with your formulation. First, when h = 0 it returns no results. This is bad; h = 0 should be a valid input. Second, v is not working as it should: you always get one component equal to 1, so you can never produce black with that function.
for the bench mark I just wrote a quick function recording the time before and after executing it "n" amount of times.
Did you test using Lua or LuaJIT/Löve? Lua does not compile anything to native code. On SSE2, min and max compile to single machine code instructions without the branch misprediction problems of conditional comparisons. Maybe you didn't test on a machine with SSE2?
SliiX wrote: ↑Mon Mar 07, 2022 10:40 pm
As for the issue with value, if you look later on, I posted an updated version fixing that, for I had forgotten to implement it. and h = 0 should work?
Oh right, I missed that post. Yes, with the final IF removed, it works when h = 0. For that variation, the select line would look like:
Code: Select all
r, g, s = select(3 - vert % 3, s, r, g, s, r)
return r, g, s
but I still recommend against it when using LuaJIT/Löve.
I've made a more thorough test of your revised function, and it's weird. For example, with h=0, s=0, v=0.5 I would expect to get 50% grey (due to the saturation being at 0), but I get bright red (#FF8080). To get 50% grey you have to use a hue of 60, 180 or 300, which isn't what I'd expect.
Here's a test program comparing your code to a known good implementation taken from
https://github.com/EmmanuelOga/columns/ ... r.lua#L113 and slightly modified to return values in the 0..1 range:
Code: Select all
local HSV
------------------------- begin literal snippet -----------------------
local ceil = math.ceil
local abs = math.abs
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 = ceil(h / 120)
local rat = abs((h / 60) - 2 * vert)
-- arc to vertex ratios along with extra channel
local r, g = clamp(rat * v, s, 1), clamp((2 - rat) * v, s, 1)
-- 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
------------------------- end literal snippet -------------------------
local formula = 1
local imgd = love.image.newImageData(360, 360)
local img = love.graphics.newImage(imgd)
local
--[[
* Converts an HSV color value to RGB. Conversion formula
* adapted from http://en.wikipedia.org/wiki/HSV_color_space.
* Assumes h, s, and v are contained in the set [0, 1] and
* returns r, g, and b in the set [0, 1].
*
* @param Number h The hue
* @param Number s The saturation
* @param Number v The value
* @return Array The RGB representation
]]
function hsvToRgb(h, s, v)
local r, g, b
local i = math.floor(h * 6);
local f = h * 6 - i;
local p = v * (1 - s);
local q = v * (1 - f * s);
local t = v * (1 - (1 - f) * s);
i = i % 6
if i == 0 then r, g, b = v, t, p
elseif i == 1 then r, g, b = q, v, p
elseif i == 2 then r, g, b = p, v, t
elseif i == 3 then r, g, b = p, q, v
elseif i == 4 then r, g, b = t, p, v
elseif i == 5 then r, g, b = v, p, q
end
return r, g, b
end
local function updateImage(v)
if formula == 1 then
imgd:mapPixel(function(x, y)
return HSV(x, 1 - y/359, v)
end)
elseif formula == 2 then
imgd:mapPixel(function(x, y)
return hsvToRgb(x/360, 1 - y/359, v)
end)
else
error("Unknown formula")
end
img:replacePixels(imgd)
end
love.window.setMode(360, 360)
updateImage(1)
function love.draw()
love.graphics.draw(img)
end
function love.mousemoved(mx, my)
updateImage(mx/359)
end
function love.mousepressed(mx, my, mb)
if mb == 1 then
formula = formula + 1
if formula > 2 then formula = 1 end
updateImage(mx/359)
end
end
function love.keypressed(k) return k == "escape" and love.event.quit() end
Move cursor left and right to adjust V; click to switch between implementations