Sosasees ¿what are these differences that i missed?

It's not differences. It's that the functions are completely different. Totally different names, logic, code.

    xyz Try to disable sRGB flag in texture's import options.

    ¿do you mean "HDR as sRGB"?
    it was disabled, and enabling it did not make the colors look better:
    lightness is more consistent but not by much — chroma is too desaturated and sometimes the hue becomes wrong
    (i did not take a photo, i was too busy fixing the colors)

    cybereality Your issue is that the code in GDScript and the code in the shader is using completely different functions.

    Sosasees ¿what are these differences that i missed?

    cybereality It's not differences. It's that the functions are completely different. Totally different names, logic, code.

    now that i have the right result, i know that the strange result was from not understanding shader language good enough.
    in my second attempt i rewrote the shader from scratch, doing the same thing i did in my first attempt — copying the logic from the GDScript.

    rgb-as-oklch.zip
    2MB

    xyz A bit offtopic. I didn't know about OKLCH. It sounds great. I do a lot of stuff with procedurally generated palettes where perceptual uniformity is of utmost importance. The best results I had with radial CIELAB (LCH) but stumbled upon the exact issues Bjorn is mentioning in the article (problems with hue wonkiness). Had an idea to deduce a better perceptual remap from observational data, but figured it'd be too much work. Bjorn did exactly that and it looks like a success.

    You should perhaps "officially" release a GDScript conversion library if you have it implemented. I'd most certainly use it.

    this sounds great.
    i think that the best implementation of a Godot OKLCH library would be an add-on with these things, please correct me:

    • OklchConverter node (autoload)
      can convert colors between sRGB and OKLCH
    • ColorOklch custom resource type
      for storing 1 OKLCH color, just like Color stores 1 RGB color
      (i don't know anything about custom resources yet, but i just feel like this is right)

      Sosasees It doesn't need to be a resource. It can be a regular class/object or even just conversion functions that take/return LCH values in an array.

        xyz ¿which is the best way? please only answer this if you know.

        • xyz replied to this.

          Sosasees There's no best way 🙂
          I'd start with just making static conversion functions in a regular script file. If file is added to the project the functions become available everywhere in the project.

          class_name LCH
          
          static func to_rgb(lch: Array) -> Color:
          	# code here
          	
          static func from_rgb(rgb: Color) -> Array:
          	# code here

          The usage would then be:

          LCH.to_rgb([1.0, 1.0, 1.0])
          LCH.from_rgb(Color(1.0, 1.0, 1.0))

          I'd also maybe add a convenience function to blend/interpolate two LCH colors. So:

          static func blend(lch1: Array, lch2: Array, factor: float) -> Array

          Just to add some more thoughts on the topic. CIELAB in great for two-color blending. The gradients it produces all look perceptually "natural". However, in procedural generation there is a lot of need for intuitive color shifts - i.e. changing the value of one of the luma/chroma/hue components but keeping other two components perceptually the same. This is problematic in all CIEXYZ based spaces including LAB. Hue shifts in particular can give unpredictable results. Not as bad as HSL/HSV but still not ideal.

          I even think that ensuring both - perceptually uniform blending and perceptually uniform shifts - is not entirely possible inside a single space. At least not without some transformation black magic. But that then is equivalent of using an alternate space. It'd be good to see some tests on how OKLCH does with shifts.

          Ideally I'd like to have a library that lets you do perceptually uniform blends/shifts, but uses rgb at input/output. It can internally convert to whatever space is best for a particular operation. The library user need not care about it. So interface might look something like this:

          class_name Perceptual
          func blend(rgb1: Color, rgb2: Color, factor: float) -> Color
          func shift_hue(rgb: Color, shift: float) -> Color
          func shift_luma(rgb: Color, shift: float) -> Color
          func shift_chroma(rgb: Color, shift: float) -> Color

          now i'm only a licensing away from releasing an OKLCH addon as an open-source project.

          rgb-as-oklch.zip
          2MB

          my original plan was to have 2 things in this addon:

          Sosasees

          • OklchConverter node (autoload)
            can convert colors between sRGB and OKLCH
          • ColorOklch custom resource type
            for storing 1 OKLCH color, just like Color stores 1 RGB color
            (i don't know anything about custom resources yet, but i just feel like this is right)

          in the real addon, i have 2 other things:

          • ColorOKLCH custom resource type
            • stores a color in OKLCH format
            • can convert a color from OKLCH to sRGB
            • can convert a color from sRGB to OKLCH
          • sRGB as OKLCH shader, also known as OKLCH color profile shader
            • interprets the sRGB pixels as OKLCH and converts them back to sRGB

          i'm thinking about which license to choose. if i choose GPL,
          ¿will other projects have to open-source the whole project before using the addon, or just the addon (and of course other GPL and similar licensed parts)?

          GPL would definitely be problematic, I want to say LGPL might be less so, but at that point a fair question might be why not Apache public license?

            GPL is actually really bad for plug-ins or add-ons. It makes sense for self contained applications, but for add-on things (like libraries) it's better to use permissive licensing like MIT, BSD, or Apache.

              No, Apache doesn't require the changes be contributed back, but it does require changes to be stated. Basically a name and shame clause in a sense. Honestly this addon would be of such nature not contributing changes back wouldn't even make sense.

                Megalomaniak this addon would be of such nature not contributing changes back wouldn't even make sense.

                ¿even if that change is adding a color picker with graphs? (like this one)

                Not contributing back would mean having to maintain the code themselves, so more technical debt to the forker.

                I'd see someone making the decision not to contribute back, if they choose to make a commercial offshoot, but this addon would be such a small thing I don't see someone successfully monetizing it anyways.

                  Not sure why your class inherits Resource though. I'd say that's too heavyweight for this almost atomic type. Are you sure you need resource functionality with this? I mean it holds path and name strings as well as local to scene flag (and associated duplication behavior).

                  I'd go as basic as possible and inherit RefCounted instead (or its equivalent Reference in v3.x)

                  As for licensing, I think you're overthinking it. It's a very short snippet of easily implementable code. Why not just put it in public domain, with basic usage conditions/disclaimers in the comments. If it grows into a bigger library/plugin you can then think about more involved licensing modalities.