func gen_palette(hue: Color, shades: int) -> Array[Vector4]:
var palette: Array[Vector4] = []
# Convert palette hue to CIELAB
var lab_hue = rgb_to_lab(hue.r, hue.g, hue.b)
# Iterate over number of palette shades
for i in range(0, shades + 1):
# Select RGB colors from the same a* and b* evenly spaced through luminance-space
var shade = lab_to_rgb((i * (1/float(shades))) * 100., lab_hue.y, lab_hue.z)
# Append color and luminance to shader buffer
palette.append(Vector4(shade.x, shade.y, shade.z, i * (1/float(shades))))
return palette
# Converts from linear RGB -> XYZ -> CIELAB per http://www.easyrgb.com/en/math.php
# CIE 1931 D65 XYZ references in use
func rgb_to_lab(r: float, g: float, b: float) -> Vector3:
r *= 100.
g *= 100.
b *= 100.
var x = r * 0.4124 + g * 0.3576 + b * 0.1805
var y = r * 0.2126 + g * 0.7152 + b * 0.0722
var z = r * 0.0193 + g * 0.1192 + b * 0.9505
x = x / 95.047
y = y / 100.
z = z / 108.883
x = pow(x, 1./3.) if x > 0.008856 else (7.787 * x) + (16. / 116.)
y = pow(y, 1./3.) if y > 0.008856 else (7.787 * y) + (16. / 116.)
z = pow(z, 1./3.) if z > 0.008856 else (7.787 * z) + (16. / 116.)
var lu = (116. * y) - 16.
var al = 500. * (x - y)
var be = 200. * (y - z)
return Vector3(lu, al, be)
# Converts from CIELAB -> XYZ -> linear RGB per http://www.easyrgb.com/en/math.php
# CIE 1931 D65 XYZ references in use
func lab_to_rgb(l: float, a: float, b: float) -> Vector3:
var y = (l + 16.) / 116.
var x = a / 500. + y
var z = y - b / 200.
y = pow(y, 3.) if (pow(y, 3.) > 0.008856) else (y - 16. / 116.) / 7.787
x = pow(x, 3.) if (pow(x, 3.) > 0.008856) else (x - 16. / 116.) / 7.787
z = pow(z, 3.) if (pow(z, 3.) > 0.008856) else (z - 16. / 116.) / 7.787
x *= 95.047
y *= 100.
z *= 108.883
x /= 100.
y /= 100.
z /= 100.
var re = x * 3.2406 + y * -1.5372 + z * -0.4986
var gr = x * -0.9689 + y * 1.8758 + z * 0.0415
var bl = x * 0.0557 + y * -0.204 + z * 1.057
return Vector3(clamp(re, 0.0, 1.0), clamp(gr, 0.0, 1.0), clamp(bl, 0.0, 1.0))