Open Artoria2e5 opened 3 years ago
Thanks for the suggestion, I will see if I manage to implement this in my code. Another commenter suggested I use HSLuv, maybe it does something similar.
hsluv is a variant of lchuv that changes chroma from an absolute value to one relative to sRGB’s capacities. I am not a fan of that sort of colorspace (the value becomes meaningless to human perception), but it’s true that we can’t ever expect to use saturation/chroma for much anyways, and just targeting the max chroma possible would make a lot of sense.
The linked post should provide most of the math needed for oklab itself. The extra dependencies would be that of sRGB gamma and the cylindrical transform, namely:
inline float srgb_encode(float u) {
/* The 2.2 approximation. Not far off the longer stuff. */
return powf(u, 1 / 2.2);
}
inline float srgb_decode(float u) {
return powf(u, 2.2);
}
#define DEGREE (M_PI / 180)
inline void ch_to_ab(float c, float h, float ab[2]){
ab[0] = c * cosf(h * DEGREE);
ab[1] = c * sinf(h * DEGREE);
}
Now for knowing the max chroma at a point, assume we have the code at https://bottosson.github.io/posts/gamutclipping/ and:
/* S is defined similarly to HSLuv: ratio to maximum chroma. In most cases
* always set it to 1, since values between 0 and 1 don't mean much, and 0 is
* just grey. */
inline void lsh_to_rgb(float L, float s, float h, float rgb[3]) {
float fake_ab[2];
ch_to_ab(1.0, h, fake_ab);
LC cusp = find_cusp(fake_ab[0], fake_ab[1]);
float c_max;
/* Do linear approximation -- assume the slice is only a triangle. */
if (L < cusp.L)
c_max = L / cusp.L * cusp.C;
else
c_max = (L - cusp.L) / (1 - cusp.L) * cusp.C;
float ab[2];
ch_to_ab(c_max * s, h, ab);
RGB out = oklab_to_linear_srgb(L, ab[0], ab[1]);
rgb[0] = srgb_encode(out.r);
rgb[1] = srgb_encode(out.g);
rgb[2] = srgb_encode(out.b);
}
(All that should definitely go into a shared header.)
Okay, thanks - I hope to post the code for the Schrödinger simulations real soon, and you will be very welcome to look at it. I will try to improve the color scheme in later versions.
I now uploaded the Schrödinger code (as well as updated versions of the others). Feel free to have a look.
Here's two other options:
https://github.com/adammaj1/1D-RGB-color-gradient
https://github.com/adammaj1/hsluv-color-gradient
I don't think the concerns about HSLuv you've voiced would apply to those @Artoria2e5, however, they'll only help for 1D cases (i.e. many of the other videos made), but for that specific video it wouldn't help since we have 2 parameters, not just one. I however assume there'd also exist higher dimensional than 1D perceptually uniform color map implementations for C however, but I didn't find any ad hoc
Oklab seems like a better approach than hsluv or static color maps, but a lack of a C library doesn't make this very helpful here (which isn't to say its unhelpful!). For more 1D color maps (of somewhat limited precision), see here, particularly the New Laguna colormap: http://inversed.ru/Blog_2.htm
As a first step, I have now included the option to use the color palette from HSLuv in the wave simulations. To do this, set constant COLOR_PALETTE to 1.
lack of a C library doesn't make this very helpful her
eh, I did say "assume the functions from the blog post". These C++ stuff in the reference are pretty much C.
@nilsberglund-orleans https://gist.github.com/mikhailov-work/6a308c20e494d9e0ccc29036b28faa7a, via https://ai.googleblog.com/2019/08/turbo-improved-rainbow-colormap-for.html
That should work.
Awesome, I will try that, thanks!
The phase emulation at videos such as https://www.youtube.com/watch?v=4lj3gQLwa1s appears to use the lightness for magnitude and hue for phase. An issue with these videos is that the HSL color space used to define the two parameters cause variations in perceived lightness even when only hue is changed. I believe that the visual result will be improved with oklab; the rainbow gradient on the linked page is a good example of what it may look like.
Oklab will be a bit harder than
hsl_to_rgb
, but I don't really expect that to be a major overhead. (The formula has noif
s, for a start.) With extra human effort, all colorscheme handling can be moved to a shader.(The standard rainbow-as-magnitude schemes can similarly use a change in color scheme. I recommend going over to https://hclwizard.org/ for a background on why HSL is getting out of use. The "HCL" (Lch[uv]) they use is not quite as good as cylindrical oklab [oklch], but it suffices to say it is much better than HSL.)