Fusion
Fusion copied to clipboard
sRGB Transformations
PR resolves #257. My goal is to start off by implementing the basic sRGB transfers. I think more discussion is needed to determine how to allow users to choose their own gamut.
This should be accounted for, at minimum the sRGB transfer functions could be added
My understanding of this is practically wrapping the Oklab to/from methods with sRGB conversions:
-- Converts a Color3 in RGB space to a Vector3 in Oklab space.
function Oklab.to(srgb: Color3): Vector3
-- Now assume that the input Color3 is part of sRGB, so convert it to
-- linear before operating on it
local rgb = sRGB.toLinear(srgb)
local l = rgb.R * 0.4122214708 + rgb.G * 0.5363325363 + rgb.B * 0.0514459929
local m = rgb.R * 0.2119034982 + rgb.G * 0.6806995451 + rgb.B * 0.1073969566
local s = rgb.R * 0.0883024619 + rgb.G * 0.2817188376 + rgb.B * 0.6299787005
local lRoot = l ^ (1/3)
local mRoot = m ^ (1/3)
local sRoot = s ^ (1/3)
return Vector3.new(
lRoot * 0.2104542553 + mRoot * 0.7936177850 - sRoot * 0.0040720468,
lRoot * 1.9779984951 - mRoot * 2.4285922050 + sRoot * 0.4505937099,
lRoot * 0.0259040371 + mRoot * 0.7827717662 - sRoot * 0.8086757660
)
end
-- Converts a Vector3 in CIELAB space to a Color3 in RGB space.
-- The Color3 will be clamped by default unless specified otherwise.
function Oklab.from(lab: Vector3, unclamped: boolean?): Color3
local lRoot = lab.X + lab.Y * 0.3963377774 + lab.Z * 0.2158037573
local mRoot = lab.X - lab.Y * 0.1055613458 - lab.Z * 0.0638541728
local sRoot = lab.X - lab.Y * 0.0894841775 - lab.Z * 1.2914855480
local l = lRoot ^ 3
local m = mRoot ^ 3
local s = sRoot ^ 3
local red = l * 4.0767416621 - m * 3.3077115913 + s * 0.2309699292
local green = l * -1.2684380046 + m * 2.6097574011 - s * 0.3413193965
local blue = l * -0.0041960863 - m * 0.7034186147 + s * 1.7076147010
if not unclamped then
red = math.clamp(red, 0, 1)
green = math.clamp(green, 0, 1)
blue = math.clamp(blue, 0, 1)
end
-- Perform the conversion back into sRGB before returning
return sRGB.fromLinear(Color3.new(red, green, blue))
end
Currently I'm aiming for this sort of syntax:
local Oklab = Fusion.Oklab
local bgColour = Spring(Computed(function(use)
return if use(isRed) then Oklab.new(0.600, 0.483, 0.128) else Oklab.new(0.600, −0.100, −0.490)
end), 20, 0.5)
local frame = New "Frame" {
BackgroundColor3 = Computed(function(use) return use(bgColour):toSRGB() end)
}
New syntax for colour manipulation is outside the scope of the linked issue and should really be discussed elsewhere, please stick to the existing API surface for now. This is an internal bug where our existing contract with the user isn't being upheld - fixing this does not require changing the contract, it only requires changing our internal code to conform to it as we originally promised to users.
Other than that, I'd be happy to accept a simpler version that implements the appropriate conversions to ensure Color3 is interpreted as sRGB rather than linear RGB.
Okay I've reverted back to a simpler implementation that focuses on the srgb <-> oklab conversion.