using System; using UnityEngine; using UnityEngine.UIElements; /// /// class to handle the oklch colour picker ui /// public class OklchColourPickerUI : MonoBehaviour { /// /// perceptual lightness value of the colour (0-100) /// public double lightness; /// /// chroma value of the colour (0-0.5) /// public double chroma; /// /// hue value of the colour (0-360) /// public double hue; /// /// slider for the chroma value /// private Slider _chromaSlider; /// /// slider for the hue value /// private Slider _hueSlider; /// /// slider for the lightness value /// private Slider _lightnessSlider; /// /// visual element for the response colour preview /// private VisualElement _responseColour; /// /// function to set the initial values of the sliders /// private void Start() { _lightnessSlider.value = 74.61f; _chromaSlider.value = 0.0868f; _hueSlider.value = 335.72f; } /// /// function to subscribe slider events to their respective functions /// public void OnEnable() { var ui = GetComponent().rootVisualElement; _lightnessSlider = ui.Q("ResponseLightnessSlider"); _lightnessSlider.RegisterCallback>(OnLightnessChange); _chromaSlider = ui.Q("ResponseChromaSlider"); _chromaSlider.RegisterCallback>(OnChromaChange); _hueSlider = ui.Q("ResponseHueSlider"); _hueSlider.RegisterCallback>(OnHueChange); _responseColour = ui.Q("ResponseColour"); } /// /// handle lightness slider change /// /// change event private void OnLightnessChange(ChangeEvent evt) { lightness = Math.Clamp(evt.newValue, 0d, 100d); _responseColour.style.backgroundColor = ToColor(); } /// /// handle chroma slider change /// /// change event private void OnChromaChange(ChangeEvent evt) { chroma = Math.Clamp(evt.newValue, 0d, 0.5d); _responseColour.style.backgroundColor = ToColor(); } /// /// handle hue slider change /// /// change event private void OnHueChange(ChangeEvent evt) { hue = Math.Clamp(evt.newValue, 0d, 360d); _responseColour.style.backgroundColor = ToColor(); } /// /// convert the oklch colour to a unity rgba colour object /// /// a unity rgba color object private Color ToColor() { // clamp values var cL = Math.Clamp(lightness / 100.0d, 0d, 1d); var cC = Math.Clamp(chroma, 0d, 0.5d); var cH = Math.Clamp(hue, 0d, 360d); // convert [OKL]Ch to [OKL]ab var hueRadians = cH * Math.PI / 180.0d; var a = cC * Math.Cos(hueRadians); var b = cC * Math.Sin(hueRadians); // bring it to linear sRGB, clip it, then bring it back to non-linear sRGB var lsrgb = Colorimetry.oklab_to_linear_srgb(new Colorimetry.Lab((float)cL, (float)a, (float)b)); var clippedLsrgb = Colorimetry.gamut_clip_preserve_chroma(lsrgb); var srgb = new Color( Math.Clamp((float)Colorimetry.srgb_nonlinear_transform_f(clippedLsrgb.r), 0.0f, 1.0f), Math.Clamp((float)Colorimetry.srgb_nonlinear_transform_f(clippedLsrgb.g), 0.0f, 1.0f), Math.Clamp((float)Colorimetry.srgb_nonlinear_transform_f(clippedLsrgb.b), 0.0f, 1.0f)); return srgb; } }