From 186c4a7724b82efe469417e7feecc4d45454b7f7 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sun, 12 Oct 2025 15:18:48 +0200 Subject: [PATCH] fix low brightness gradient "jumpyness" during testing at low brightness I noticed that gradients can be "jumping" in colors quite wildly, turning a smooth gradient into a flickering mess. This is due to the color hue preservation being inaccurate and a bit too aggressive. This can be seen for example using a gradient palette and "Running" FX. Removing the hue preservation completely fixes it but leaves color artefacts for example visible in PS Fire at very low brightness: the bright part of the flames gets a pink hue. This change is a compromise to fix both problems to a "good enough" state --- wled00/colors.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 612b3310..6ada4f1f 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -72,11 +72,10 @@ uint32_t IRAM_ATTR color_fade(uint32_t c1, uint8_t amount, bool video) { // video scaling: make sure colors do not dim to zero if they started non-zero unless they distort the hue uint8_t r = byte(c1>>16), g = byte(c1>>8), b = byte(c1), w = byte(c1>>24); // extract r, g, b, w channels uint8_t maxc = (r > g) ? ((r > b) ? r : b) : ((g > b) ? g : b); // determine dominant channel for hue preservation - uint8_t quarterMax = maxc >> 2; // note: using half of max results in color artefacts - addRemains = r && r > quarterMax ? 0x00010000 : 0; - addRemains |= g && g > quarterMax ? 0x00000100 : 0; - addRemains |= b && b > quarterMax ? 0x00000001 : 0; - addRemains |= w ? 0x01000000 : 0; + addRemains = r && (r<<5) > maxc ? 0x00010000 : 0; // note: setting color preservation threshold too high results in flickering and + addRemains |= g && (g<<5) > maxc ? 0x00000100 : 0; // jumping colors in low brightness gradients. Multiplying the color preserves + addRemains |= b && (b<<5) > maxc ? 0x00000001 : 0; // better accuracy than dividing the maxc. Shifting by 5 is a good compromise + addRemains |= w ? 0x01000000 : 0; // i.e. remove color channel if <13% of max } const uint32_t TWO_CHANNEL_MASK = 0x00FF00FF; uint32_t rb = (((c1 & TWO_CHANNEL_MASK) * amount) >> 8) & TWO_CHANNEL_MASK; // scale red and blue