Skip to content

Commit 8b65d87

Browse files
authored
fix particle brightness distribution with new gamma correction (#4710)
Particle System depends on linear brightness distribution, gamma corrected values are non-linear. - added invers gamma table - reversing gamma after brightness distribution makes it linear once again
1 parent a87b562 commit 8b65d87

File tree

5 files changed

+28
-6
lines changed

5 files changed

+28
-6
lines changed

wled00/FXparticleSystem.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -584,7 +584,7 @@ void ParticleSystem2D::render() {
584584
continue;
585585
// generate RGB values for particle
586586
if (fireIntesity) { // fire mode
587-
brightness = (uint32_t)particles[i].ttl * (3 + (fireIntesity >> 5)) + 20;
587+
brightness = (uint32_t)particles[i].ttl * (3 + (fireIntesity >> 5)) + 5;
588588
brightness = min(brightness, (uint32_t)255);
589589
baseRGB = ColorFromPaletteWLED(SEGPALETTE, brightness, 255, LINEARBLEND_NOWRAP);
590590
}
@@ -600,6 +600,7 @@ void ParticleSystem2D::render() {
600600
baseRGB = (CRGB)tempcolor;
601601
}
602602
}
603+
brightness = gamma8(brightness); // apply gamma correction, used for gamma-inverted brightness distribution
603604
renderParticle(i, brightness, baseRGB, particlesettings.wrapX, particlesettings.wrapY);
604605
}
605606

@@ -676,6 +677,14 @@ __attribute__((optimize("O2"))) void ParticleSystem2D::renderParticle(const uint
676677
pxlbrightness[1] = (dx * precal2) >> PS_P_SURFACE; // bottom right value equal to (dx * (PS_P_RADIUS-dy) * brightness) >> PS_P_SURFACE
677678
pxlbrightness[2] = (dx * precal3) >> PS_P_SURFACE; // top right value equal to (dx * dy * brightness) >> PS_P_SURFACE
678679
pxlbrightness[3] = (precal1 * precal3) >> PS_P_SURFACE; // top left value equal to ((PS_P_RADIUS-dx) * dy * brightness) >> PS_P_SURFACE
680+
// adjust brightness such that distribution is linear after gamma correction:
681+
// - scale brigthness with gamma correction (done in render())
682+
// - apply inverse gamma correction to brightness values
683+
// - gamma is applied again in show() -> the resulting brightness distribution is linear but gamma corrected in total
684+
pxlbrightness[0] = gamma8inv(pxlbrightness[0]); // use look-up-table for invers gamma
685+
pxlbrightness[1] = gamma8inv(pxlbrightness[1]);
686+
pxlbrightness[2] = gamma8inv(pxlbrightness[2]);
687+
pxlbrightness[3] = gamma8inv(pxlbrightness[3]);
679688

680689
if (advPartProps && advPartProps[particleindex].size > 1) { //render particle to a bigger size
681690
CRGB renderbuffer[100]; // 10x10 pixel buffer
@@ -1467,6 +1476,7 @@ void ParticleSystem1D::render() {
14671476
baseRGB = (CRGB)tempcolor;
14681477
}
14691478
}
1479+
brightness = gamma8(brightness); // apply gamma correction, used for gamma-inverted brightness distribution
14701480
renderParticle(i, brightness, baseRGB, particlesettings.wrap);
14711481
}
14721482
// apply smear-blur to rendered frame
@@ -1534,6 +1544,12 @@ __attribute__((optimize("O2"))) void ParticleSystem1D::renderParticle(const uint
15341544
//calculate the brightness values for both pixels using linear interpolation (note: in standard rendering out of frame pixels could be skipped but if checks add more clock cycles over all)
15351545
pxlbrightness[0] = (((int32_t)PS_P_RADIUS_1D - dx) * brightness) >> PS_P_SURFACE_1D;
15361546
pxlbrightness[1] = (dx * brightness) >> PS_P_SURFACE_1D;
1547+
// adjust brightness such that distribution is linear after gamma correction:
1548+
// - scale brigthness with gamma correction (done in render())
1549+
// - apply inverse gamma correction to brightness values
1550+
// - gamma is applied again in show() -> the resulting brightness distribution is linear but gamma corrected in total
1551+
pxlbrightness[0] = gamma8inv(pxlbrightness[0]); // use look-up-table for invers gamma
1552+
pxlbrightness[1] = gamma8inv(pxlbrightness[1]);
15371553

15381554
// check if particle has advanced size properties and buffer is available
15391555
if (advPartProps && advPartProps[particleindex].size > 1) {

wled00/cfg.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
532532
gammaCorrectBri = false;
533533
gammaCorrectCol = false;
534534
}
535-
NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up table
535+
NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up tables
536536

537537
JsonObject light_tr = light["tr"];
538538
int tdd = light_tr["dur"] | -1;

wled00/colors.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -564,14 +564,17 @@ uint16_t approximateKelvinFromRGB(uint32_t rgb) {
564564
}
565565
}
566566

567-
// gamma lookup table used for color correction (filled on 1st use (cfg.cpp & set.cpp))
567+
// gamma lookup tables used for color correction (filled on 1st use (cfg.cpp & set.cpp))
568568
uint8_t NeoGammaWLEDMethod::gammaT[256];
569+
uint8_t NeoGammaWLEDMethod::gammaT_inv[256];
569570

570-
// re-calculates & fills gamma table
571+
// re-calculates & fills gamma tables
571572
void NeoGammaWLEDMethod::calcGammaTable(float gamma)
572573
{
574+
float gamma_inv = 1.0f / gamma; // inverse gamma
573575
for (size_t i = 0; i < 256; i++) {
574576
gammaT[i] = (int)(powf((float)i / 255.0f, gamma) * 255.0f + 0.5f);
577+
gammaT_inv[i] = (int)(powf((float)i / 255.0f, gamma_inv) * 255.0f + 0.5f);
575578
}
576579
}
577580

wled00/fcn_declare.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,16 @@ class NeoGammaWLEDMethod {
158158
public:
159159
[[gnu::hot]] static uint8_t Correct(uint8_t value); // apply Gamma to single channel
160160
[[gnu::hot]] static uint32_t Correct32(uint32_t color); // apply Gamma to RGBW32 color (WLED specific, not used by NPB)
161-
static void calcGammaTable(float gamma); // re-calculates & fills gamma table
161+
static void calcGammaTable(float gamma); // re-calculates & fills gamma tables
162162
static inline uint8_t rawGamma8(uint8_t val) { return gammaT[val]; } // get value from Gamma table (WLED specific, not used by NPB)
163+
static inline uint8_t rawInverseGamma8(uint8_t val) { return gammaT_inv[val]; } // get value from inverse Gamma table (WLED specific, not used by NPB)
163164
private:
164165
static uint8_t gammaT[];
166+
static uint8_t gammaT_inv[];
165167
};
166168
#define gamma32(c) NeoGammaWLEDMethod::Correct32(c)
167169
#define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c)
170+
#define gamma8inv(c) NeoGammaWLEDMethod::rawInverseGamma8(c)
168171
[[gnu::hot, gnu::pure]] uint32_t color_blend(uint32_t c1, uint32_t c2 , uint8_t blend);
169172
inline uint32_t color_blend16(uint32_t c1, uint32_t c2, uint16_t b) { return color_blend(c1, c2, b >> 8); };
170173
[[gnu::hot, gnu::pure]] uint32_t color_add(uint32_t, uint32_t, bool preserveCR = false);

wled00/set.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
341341
gammaCorrectBri = false;
342342
gammaCorrectCol = false;
343343
}
344-
NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up table
344+
NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up tables
345345

346346
t = request->arg(F("TD")).toInt();
347347
if (t >= 0) transitionDelayDefault = t;

0 commit comments

Comments
 (0)