Skip to content

Commit

Permalink
✨ Replace CIELAB with Oklab
Browse files Browse the repository at this point in the history
  • Loading branch information
JulesFouchy committed Oct 9, 2023
1 parent 614207b commit dbefa60
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 70 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ To create a widget that changes the interpolation mode, use:
ImGG::interpolation_mode_widget("Interpolation Mode", &widget.gradient().interpolation_mode());
```

> NB: Our linear interpolation is done in the CIELAB color space, which gives more accurate results. We also use premultiplied alpha during the interpolation for the same reason.
> NB: Our linear interpolation is done in the [Oklab](https://bottosson.github.io/posts/oklab/) color space, which gives more accurate results. We also use premultiplied alpha during the interpolation for the same reason.
> BUT the colors we output are all in sRGB space with straight alpha, for ease of use.
### Settings
Expand Down
6 changes: 3 additions & 3 deletions src/Gradient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,9 @@ static auto interpolate(const Mark& lower, const Mark& upper, const RelativePosi
const float mix_factor = (position.get() - lower.position.get())
/ (upper.position.get() - lower.position.get());
// Do the interpolation in Lab space with premultiplied alpha because it looks much better.
return internal::sRGB_Straight_from_CIELAB_Premultiplied(ImLerp(
internal::CIELAB_Premultiplied_from_sRGB_Straight(lower.color),
internal::CIELAB_Premultiplied_from_sRGB_Straight(upper.color),
return internal::sRGB_Straight_from_Oklab_Premultiplied(ImLerp(
internal::Oklab_Premultiplied_from_sRGB_Straight(lower.color),
internal::Oklab_Premultiplied_from_sRGB_Straight(upper.color),
mix_factor
));
}
Expand Down
86 changes: 25 additions & 61 deletions src/color_conversions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,83 +69,47 @@ static auto sRGB_from_LinearRGB(Vec3 rgb) -> Vec3
}
// End of [Block1]

// Start of [Block2]
// From http://www.easyrgb.com/en/math.php
// Start of [Block2]// From https://bottosson.github.io/posts/oklab/

static auto XYZ_from_LinearRGB(Vec3 const& c) -> Vec3
static auto Oklab_from_LinearRGB(Vec3 c) -> Vec3
{
return {
c.x * 0.4124f + c.y * 0.3576f + c.z * 0.1805f,
c.x * 0.2126f + c.y * 0.7152f + c.z * 0.0722f,
c.x * 0.0193f + c.y * 0.1192f + c.z * 0.9505f,
};
}
float l = 0.4122214708f * c.x + 0.5363325363f * c.y + 0.0514459929f * c.z;
float m = 0.2119034982f * c.x + 0.6806995451f * c.y + 0.1073969566f * c.z;
float s = 0.0883024619f * c.x + 0.2817188376f * c.y + 0.6299787005f * c.z;

static auto XYZ_from_sRGB(Vec3 const& c) -> Vec3
{
return XYZ_from_LinearRGB(LinearRGB_from_sRGB(c));
}
float l_ = cbrtf(l);
float m_ = cbrtf(m);
float s_ = cbrtf(s);

static auto CIELAB_from_XYZ(Vec3 const& c) -> Vec3
{
auto const n = Vec3{c.x / 0.95047f, c.y, c.z / 1.08883f};
Vec3 const v{
(n.x > 0.008856) ? std::pow(n.x, 1.f / 3.f) : (7.787f * n.x) + (16.f / 116.f),
(n.y > 0.008856) ? std::pow(n.y, 1.f / 3.f) : (7.787f * n.y) + (16.f / 116.f),
(n.z > 0.008856) ? std::pow(n.z, 1.f / 3.f) : (7.787f * n.z) + (16.f / 116.f),
};
return {
(1.16f * v.y) - 0.16f,
5.f * (v.x - v.y),
2.f * (v.y - v.z),
0.2104542553f * l_ + 0.7936177850f * m_ - 0.0040720468f * s_,
1.9779984951f * l_ - 2.4285922050f * m_ + 0.4505937099f * s_,
0.0259040371f * l_ + 0.7827717662f * m_ - 0.8086757660f * s_,
};
}

static auto CIELAB_from_sRGB(Vec3 const& c) -> Vec3
{
return CIELAB_from_XYZ(XYZ_from_sRGB(c));
}

static auto XYZ_from_CIELAB(Vec3 const& c) -> Vec3
static auto LinearRGB_from_Oklab(Vec3 c) -> Vec3
{
float const fy = (c.x + 0.16f) / 1.16f;
float const fx = c.y / 5.f + fy;
float const fz = fy - c.z / 2.f;
float l_ = c.x + 0.3963377774f * c.y + 0.2158037573f * c.z;
float m_ = c.x - 0.1055613458f * c.y - 0.0638541728f * c.z;
float s_ = c.x - 0.0894841775f * c.y - 1.2914855480f * c.z;

float const fx3 = fx * fx * fx;
float const fy3 = fy * fy * fy;
float const fz3 = fz * fz * fz;
return {
0.95047f * ((fx3 > 0.008856f) ? fx3 : (fx - 16.f / 116.f) / 7.787f),
1.00000f * ((fy3 > 0.008856f) ? fy3 : (fy - 16.f / 116.f) / 7.787f),
1.08883f * ((fz3 > 0.008856f) ? fz3 : (fz - 16.f / 116.f) / 7.787f),
};
}
float l = l_ * l_ * l_;
float m = m_ * m_ * m_;
float s = s_ * s_ * s_;

static auto LinearRGB_from_XYZ(Vec3 const& c) -> Vec3
{
return {
c.x * 3.2406f + c.y * -1.5372f + c.z * -0.4986f,
c.x * -0.9689f + c.y * 1.8758f + c.z * 0.0415f,
c.x * 0.0557f + c.y * -0.2040f + c.z * 1.0570f,
+4.0767416621f * l - 3.3077115913f * m + 0.2309699292f * s,
-1.2684380046f * l + 2.6097574011f * m - 0.3413193965f * s,
-0.0041960863f * l - 0.7034186147f * m + 1.7076147010f * s,
};
}

static auto sRGB_from_XYZ(Vec3 const& c) -> Vec3
{
return sRGB_from_LinearRGB(LinearRGB_from_XYZ(c));
}

static auto sRGB_from_CIELAB(Vec3 const& c) -> Vec3
{
return sRGB_from_XYZ(XYZ_from_CIELAB(c));
}

// End of [Block2]

auto CIELAB_Premultiplied_from_sRGB_Straight(ColorRGBA const& col) -> ImVec4
auto Oklab_Premultiplied_from_sRGB_Straight(ColorRGBA const& col) -> ImVec4
{
auto const lab = CIELAB_from_sRGB({col.x, col.y, col.z});
auto const lab = Oklab_from_LinearRGB(LinearRGB_from_sRGB({col.x, col.y, col.z}));
return {
lab.x * col.w,
lab.y * col.w,
Expand All @@ -154,9 +118,9 @@ auto CIELAB_Premultiplied_from_sRGB_Straight(ColorRGBA const& col) -> ImVec4
};
}

auto sRGB_Straight_from_CIELAB_Premultiplied(ImVec4 const& col) -> ColorRGBA
auto sRGB_Straight_from_Oklab_Premultiplied(ImVec4 const& col) -> ColorRGBA
{
auto const srgb = sRGB_from_CIELAB({col.x / col.w, col.y / col.w, col.z / col.w});
auto const srgb = sRGB_from_LinearRGB(LinearRGB_from_Oklab({col.x / col.w, col.y / col.w, col.z / col.w}));
return {
srgb.x,
srgb.y,
Expand Down
4 changes: 2 additions & 2 deletions src/color_conversions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace ImGG { namespace internal {

auto CIELAB_Premultiplied_from_sRGB_Straight(ColorRGBA const&) -> ImVec4;
auto sRGB_Straight_from_CIELAB_Premultiplied(ImVec4 const&) -> ColorRGBA;
auto Oklab_Premultiplied_from_sRGB_Straight(ColorRGBA const&) -> ImVec4;
auto sRGB_Straight_from_Oklab_Premultiplied(ImVec4 const&) -> ColorRGBA;

}} // namespace ImGG::internal
6 changes: 3 additions & 3 deletions src/imgui_draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ static void draw_gradient_between_two_colors(
ImVec4 const& color_left, ImVec4 const& color_right
)
{
auto const color_middle = internal::sRGB_Straight_from_CIELAB_Premultiplied(
auto const color_middle = internal::sRGB_Straight_from_Oklab_Premultiplied(
(
internal::CIELAB_Premultiplied_from_sRGB_Straight(color_left)
+ internal::CIELAB_Premultiplied_from_sRGB_Straight(color_right)
internal::Oklab_Premultiplied_from_sRGB_Straight(color_left)
+ internal::Oklab_Premultiplied_from_sRGB_Straight(color_right)
)
* ImVec4{0.5f, 0.5f, 0.5f, 0.5f}
);
Expand Down

0 comments on commit dbefa60

Please sign in to comment.