mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-12 19:47:43 +00:00
Refactor color blending in MixedFilament: Replace legacy RYB blending with FilamentMixer for improved accuracy. Update blend_color method to utilize new lerp functionality and enhance display color computation. Retain legacy RYB conversion functions for reference.
This commit is contained in:
@@ -25,12 +25,12 @@ struct RGBf {
|
|||||||
float r = 0.f, g = 0.f, b = 0.f;
|
float r = 0.f, g = 0.f, b = 0.f;
|
||||||
};
|
};
|
||||||
|
|
||||||
static float clamp01(float v)
|
[[maybe_unused]] static float clamp01(float v)
|
||||||
{
|
{
|
||||||
return std::max(0.f, std::min(1.f, v));
|
return std::max(0.f, std::min(1.f, v));
|
||||||
}
|
}
|
||||||
|
|
||||||
static RGBf to_rgbf(const RGB &c)
|
[[maybe_unused]] static RGBf to_rgbf(const RGB &c)
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
clamp01(static_cast<float>(c.r) / 255.f),
|
clamp01(static_cast<float>(c.r) / 255.f),
|
||||||
@@ -39,7 +39,7 @@ static RGBf to_rgbf(const RGB &c)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static RGB to_rgb8(const RGBf &c)
|
[[maybe_unused]] static RGB to_rgb8(const RGBf &c)
|
||||||
{
|
{
|
||||||
auto to_u8 = [](float v) -> int {
|
auto to_u8 = [](float v) -> int {
|
||||||
return std::clamp(static_cast<int>(std::round(clamp01(v) * 255.f)), 0, 255);
|
return std::clamp(static_cast<int>(std::round(clamp01(v) * 255.f)), 0, 255);
|
||||||
@@ -47,10 +47,14 @@ static RGB to_rgb8(const RGBf &c)
|
|||||||
return { to_u8(c.r), to_u8(c.g), to_u8(c.b) };
|
return { to_u8(c.r), to_u8(c.g), to_u8(c.b) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Convert RGB to an artist-pigment style RYB space.
|
// Convert RGB to an artist-pigment style RYB space.
|
||||||
// This is an approximation, but it gives expected pair mixes:
|
// This is an approximation, but it gives expected pair mixes:
|
||||||
// Red + Blue -> Purple, Blue + Yellow -> Green, Red + Yellow -> Orange.
|
// Red + Blue -> Purple, Blue + Yellow -> Green, Red + Yellow -> Orange.
|
||||||
static RGBf rgb_to_ryb(RGBf in)
|
|
||||||
|
// Legacy RYB conversion helpers kept for reference.
|
||||||
|
// Active code paths use FilamentMixer.
|
||||||
|
[[maybe_unused]] static RGBf rgb_to_ryb(RGBf in)
|
||||||
{
|
{
|
||||||
float r = clamp01(in.r);
|
float r = clamp01(in.r);
|
||||||
float g = clamp01(in.g);
|
float g = clamp01(in.g);
|
||||||
@@ -89,7 +93,7 @@ static RGBf rgb_to_ryb(RGBf in)
|
|||||||
return { clamp01(r), clamp01(y), clamp01(b) };
|
return { clamp01(r), clamp01(y), clamp01(b) };
|
||||||
}
|
}
|
||||||
|
|
||||||
static RGBf ryb_to_rgb(RGBf in)
|
[[maybe_unused]] static RGBf ryb_to_rgb(RGBf in)
|
||||||
{
|
{
|
||||||
float r = clamp01(in.r);
|
float r = clamp01(in.r);
|
||||||
float y = clamp01(in.g);
|
float y = clamp01(in.g);
|
||||||
@@ -151,6 +155,41 @@ static std::string rgb_to_hex(const RGB &c)
|
|||||||
return std::string(buf);
|
return std::string(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[maybe_unused]] static std::string blend_color_ryb_legacy(const RGB &rgb_a,
|
||||||
|
const RGB &rgb_b,
|
||||||
|
int ratio_a,
|
||||||
|
int ratio_b)
|
||||||
|
{
|
||||||
|
const int safe_a = std::max(0, ratio_a);
|
||||||
|
const int safe_b = std::max(0, ratio_b);
|
||||||
|
const float total = static_cast<float>(safe_a + safe_b);
|
||||||
|
const float wa = (total > 0.f) ? static_cast<float>(safe_a) / total : 0.5f;
|
||||||
|
const float wb = 1.f - wa;
|
||||||
|
|
||||||
|
const RGBf color_a = to_rgbf(rgb_a);
|
||||||
|
const RGBf color_b = to_rgbf(rgb_b);
|
||||||
|
const RGBf ryb_a = rgb_to_ryb(color_a);
|
||||||
|
const RGBf ryb_b = rgb_to_ryb(color_b);
|
||||||
|
|
||||||
|
RGBf ryb_out;
|
||||||
|
ryb_out.r = wa * ryb_a.r + wb * ryb_b.r;
|
||||||
|
ryb_out.g = wa * ryb_a.g + wb * ryb_b.g;
|
||||||
|
ryb_out.b = wa * ryb_a.b + wb * ryb_b.b;
|
||||||
|
|
||||||
|
RGBf rgb_out = ryb_to_rgb(ryb_out);
|
||||||
|
const float v_out = std::max({ rgb_out.r, rgb_out.g, rgb_out.b });
|
||||||
|
const float v_tgt = wa * std::max({ color_a.r, color_a.g, color_a.b }) +
|
||||||
|
wb * std::max({ color_b.r, color_b.g, color_b.b });
|
||||||
|
if (v_out > 1e-6f && v_tgt > 0.f) {
|
||||||
|
const float scale = v_tgt / v_out;
|
||||||
|
rgb_out.r = clamp01(rgb_out.r * scale);
|
||||||
|
rgb_out.g = clamp01(rgb_out.g * scale);
|
||||||
|
rgb_out.b = clamp01(rgb_out.b * scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rgb_to_hex(to_rgb8(rgb_out));
|
||||||
|
}
|
||||||
|
|
||||||
static int clamp_int(int v, int lo, int hi)
|
static int clamp_int(int v, int lo, int hi)
|
||||||
{
|
{
|
||||||
return std::max(lo, std::min(hi, v));
|
return std::max(lo, std::min(hi, v));
|
||||||
@@ -1036,32 +1075,24 @@ std::string MixedFilamentManager::blend_color(const std::string &color_a,
|
|||||||
{
|
{
|
||||||
const int safe_a = std::max(0, ratio_a);
|
const int safe_a = std::max(0, ratio_a);
|
||||||
const int safe_b = std::max(0, ratio_b);
|
const int safe_b = std::max(0, ratio_b);
|
||||||
const float total = static_cast<float>(safe_a + safe_b);
|
const int total = safe_a + safe_b;
|
||||||
const float wa = (total > 0.f) ? static_cast<float>(safe_a) / total : 0.5f;
|
const float t = (total > 0) ? (static_cast<float>(safe_b) / static_cast<float>(total)) : 0.5f;
|
||||||
const float wb = 1.f - wa;
|
|
||||||
|
|
||||||
const RGBf rgb_a = to_rgbf(parse_hex_color(color_a));
|
const RGB rgb_a = parse_hex_color(color_a);
|
||||||
const RGBf rgb_b = to_rgbf(parse_hex_color(color_b));
|
const RGB rgb_b = parse_hex_color(color_b);
|
||||||
const RGBf ryb_a = rgb_to_ryb(rgb_a);
|
|
||||||
const RGBf ryb_b = rgb_to_ryb(rgb_b);
|
|
||||||
|
|
||||||
RGBf ryb_out;
|
unsigned char out_r = static_cast<unsigned char>(rgb_a.r);
|
||||||
ryb_out.r = wa * ryb_a.r + wb * ryb_b.r;
|
unsigned char out_g = static_cast<unsigned char>(rgb_a.g);
|
||||||
ryb_out.g = wa * ryb_a.g + wb * ryb_b.g;
|
unsigned char out_b = static_cast<unsigned char>(rgb_a.b);
|
||||||
ryb_out.b = wa * ryb_a.b + wb * ryb_b.b;
|
filament_mixer_lerp(static_cast<unsigned char>(rgb_a.r),
|
||||||
|
static_cast<unsigned char>(rgb_a.g),
|
||||||
|
static_cast<unsigned char>(rgb_a.b),
|
||||||
|
static_cast<unsigned char>(rgb_b.r),
|
||||||
|
static_cast<unsigned char>(rgb_b.g),
|
||||||
|
static_cast<unsigned char>(rgb_b.b),
|
||||||
|
t, &out_r, &out_g, &out_b);
|
||||||
|
|
||||||
RGBf rgb_out = ryb_to_rgb(ryb_out);
|
return rgb_to_hex({int(out_r), int(out_g), int(out_b)});
|
||||||
const float v_out = std::max({ rgb_out.r, rgb_out.g, rgb_out.b });
|
|
||||||
const float v_tgt = wa * std::max({ rgb_a.r, rgb_a.g, rgb_a.b }) +
|
|
||||||
wb * std::max({ rgb_b.r, rgb_b.g, rgb_b.b });
|
|
||||||
if (v_out > 1e-6f && v_tgt > 0.f) {
|
|
||||||
const float scale = v_tgt / v_out;
|
|
||||||
rgb_out.r = clamp01(rgb_out.r * scale);
|
|
||||||
rgb_out.g = clamp01(rgb_out.g * scale);
|
|
||||||
rgb_out.b = clamp01(rgb_out.b * scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
return rgb_to_hex(to_rgb8(rgb_out));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MixedFilamentManager::refresh_display_colors(const std::vector<std::string> &filament_colours)
|
void MixedFilamentManager::refresh_display_colors(const std::vector<std::string> &filament_colours)
|
||||||
|
|||||||
@@ -10,10 +10,11 @@
|
|||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
// Represents a virtual "mixed" filament created from physical filaments
|
// Represents a virtual "mixed" filament created from physical filaments
|
||||||
// (layer cadence and/or same-layer interleaved stripe distribution). The display
|
// (layer cadence and/or same-layer interleaved stripe distribution). Display
|
||||||
// colour uses a FilamentMixer-based multi-color blend (and RYB pair blend) so
|
// colour blending uses FilamentMixer so pair previews better
|
||||||
// pair previews better match expected print mixing (for example Blue+Yellow
|
// match expected print mixing
|
||||||
// -> Green, Red+Yellow -> Orange, Red+Blue -> Purple).
|
// (for example Blue+Yellow -> Green, Red+Yellow -> Orange, Red+Blue -> Purple).
|
||||||
|
// Legacy RYB code is retained in source for reference only.
|
||||||
struct MixedFilament
|
struct MixedFilament
|
||||||
{
|
{
|
||||||
enum DistributionMode : uint8_t {
|
enum DistributionMode : uint8_t {
|
||||||
@@ -160,7 +161,7 @@ public:
|
|||||||
|
|
||||||
const MixedFilament *mixed_filament_from_id(unsigned int filament_id, size_t num_physical) const;
|
const MixedFilament *mixed_filament_from_id(unsigned int filament_id, size_t num_physical) const;
|
||||||
|
|
||||||
// Compute a display colour by blending in RYB pigment space.
|
// Compute a display colour by blending two colours with FilamentMixer.
|
||||||
static std::string blend_color(const std::string &color_a,
|
static std::string blend_color(const std::string &color_a,
|
||||||
const std::string &color_b,
|
const std::string &color_b,
|
||||||
int ratio_a, int ratio_b);
|
int ratio_a, int ratio_b);
|
||||||
|
|||||||
Reference in New Issue
Block a user