mirror of
https://github.com/wled/WLED.git
synced 2025-07-19 08:46:34 +00:00
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
This commit is contained in:
parent
a87b562bc2
commit
8b65d873b3
@ -584,7 +584,7 @@ void ParticleSystem2D::render() {
|
|||||||
continue;
|
continue;
|
||||||
// generate RGB values for particle
|
// generate RGB values for particle
|
||||||
if (fireIntesity) { // fire mode
|
if (fireIntesity) { // fire mode
|
||||||
brightness = (uint32_t)particles[i].ttl * (3 + (fireIntesity >> 5)) + 20;
|
brightness = (uint32_t)particles[i].ttl * (3 + (fireIntesity >> 5)) + 5;
|
||||||
brightness = min(brightness, (uint32_t)255);
|
brightness = min(brightness, (uint32_t)255);
|
||||||
baseRGB = ColorFromPaletteWLED(SEGPALETTE, brightness, 255, LINEARBLEND_NOWRAP);
|
baseRGB = ColorFromPaletteWLED(SEGPALETTE, brightness, 255, LINEARBLEND_NOWRAP);
|
||||||
}
|
}
|
||||||
@ -600,6 +600,7 @@ void ParticleSystem2D::render() {
|
|||||||
baseRGB = (CRGB)tempcolor;
|
baseRGB = (CRGB)tempcolor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
brightness = gamma8(brightness); // apply gamma correction, used for gamma-inverted brightness distribution
|
||||||
renderParticle(i, brightness, baseRGB, particlesettings.wrapX, particlesettings.wrapY);
|
renderParticle(i, brightness, baseRGB, particlesettings.wrapX, particlesettings.wrapY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -676,6 +677,14 @@ __attribute__((optimize("O2"))) void ParticleSystem2D::renderParticle(const uint
|
|||||||
pxlbrightness[1] = (dx * precal2) >> PS_P_SURFACE; // bottom right value equal to (dx * (PS_P_RADIUS-dy) * brightness) >> PS_P_SURFACE
|
pxlbrightness[1] = (dx * precal2) >> PS_P_SURFACE; // bottom right value equal to (dx * (PS_P_RADIUS-dy) * brightness) >> PS_P_SURFACE
|
||||||
pxlbrightness[2] = (dx * precal3) >> PS_P_SURFACE; // top right value equal to (dx * dy * brightness) >> PS_P_SURFACE
|
pxlbrightness[2] = (dx * precal3) >> PS_P_SURFACE; // top right value equal to (dx * dy * brightness) >> PS_P_SURFACE
|
||||||
pxlbrightness[3] = (precal1 * precal3) >> PS_P_SURFACE; // top left value equal to ((PS_P_RADIUS-dx) * dy * brightness) >> PS_P_SURFACE
|
pxlbrightness[3] = (precal1 * precal3) >> PS_P_SURFACE; // top left value equal to ((PS_P_RADIUS-dx) * dy * brightness) >> PS_P_SURFACE
|
||||||
|
// adjust brightness such that distribution is linear after gamma correction:
|
||||||
|
// - scale brigthness with gamma correction (done in render())
|
||||||
|
// - apply inverse gamma correction to brightness values
|
||||||
|
// - gamma is applied again in show() -> the resulting brightness distribution is linear but gamma corrected in total
|
||||||
|
pxlbrightness[0] = gamma8inv(pxlbrightness[0]); // use look-up-table for invers gamma
|
||||||
|
pxlbrightness[1] = gamma8inv(pxlbrightness[1]);
|
||||||
|
pxlbrightness[2] = gamma8inv(pxlbrightness[2]);
|
||||||
|
pxlbrightness[3] = gamma8inv(pxlbrightness[3]);
|
||||||
|
|
||||||
if (advPartProps && advPartProps[particleindex].size > 1) { //render particle to a bigger size
|
if (advPartProps && advPartProps[particleindex].size > 1) { //render particle to a bigger size
|
||||||
CRGB renderbuffer[100]; // 10x10 pixel buffer
|
CRGB renderbuffer[100]; // 10x10 pixel buffer
|
||||||
@ -1467,6 +1476,7 @@ void ParticleSystem1D::render() {
|
|||||||
baseRGB = (CRGB)tempcolor;
|
baseRGB = (CRGB)tempcolor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
brightness = gamma8(brightness); // apply gamma correction, used for gamma-inverted brightness distribution
|
||||||
renderParticle(i, brightness, baseRGB, particlesettings.wrap);
|
renderParticle(i, brightness, baseRGB, particlesettings.wrap);
|
||||||
}
|
}
|
||||||
// apply smear-blur to rendered frame
|
// apply smear-blur to rendered frame
|
||||||
@ -1534,6 +1544,12 @@ __attribute__((optimize("O2"))) void ParticleSystem1D::renderParticle(const uint
|
|||||||
//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)
|
//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)
|
||||||
pxlbrightness[0] = (((int32_t)PS_P_RADIUS_1D - dx) * brightness) >> PS_P_SURFACE_1D;
|
pxlbrightness[0] = (((int32_t)PS_P_RADIUS_1D - dx) * brightness) >> PS_P_SURFACE_1D;
|
||||||
pxlbrightness[1] = (dx * brightness) >> PS_P_SURFACE_1D;
|
pxlbrightness[1] = (dx * brightness) >> PS_P_SURFACE_1D;
|
||||||
|
// adjust brightness such that distribution is linear after gamma correction:
|
||||||
|
// - scale brigthness with gamma correction (done in render())
|
||||||
|
// - apply inverse gamma correction to brightness values
|
||||||
|
// - gamma is applied again in show() -> the resulting brightness distribution is linear but gamma corrected in total
|
||||||
|
pxlbrightness[0] = gamma8inv(pxlbrightness[0]); // use look-up-table for invers gamma
|
||||||
|
pxlbrightness[1] = gamma8inv(pxlbrightness[1]);
|
||||||
|
|
||||||
// check if particle has advanced size properties and buffer is available
|
// check if particle has advanced size properties and buffer is available
|
||||||
if (advPartProps && advPartProps[particleindex].size > 1) {
|
if (advPartProps && advPartProps[particleindex].size > 1) {
|
||||||
|
@ -532,7 +532,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
gammaCorrectBri = false;
|
gammaCorrectBri = false;
|
||||||
gammaCorrectCol = false;
|
gammaCorrectCol = false;
|
||||||
}
|
}
|
||||||
NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up table
|
NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up tables
|
||||||
|
|
||||||
JsonObject light_tr = light["tr"];
|
JsonObject light_tr = light["tr"];
|
||||||
int tdd = light_tr["dur"] | -1;
|
int tdd = light_tr["dur"] | -1;
|
||||||
|
@ -564,14 +564,17 @@ uint16_t approximateKelvinFromRGB(uint32_t rgb) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// gamma lookup table used for color correction (filled on 1st use (cfg.cpp & set.cpp))
|
// gamma lookup tables used for color correction (filled on 1st use (cfg.cpp & set.cpp))
|
||||||
uint8_t NeoGammaWLEDMethod::gammaT[256];
|
uint8_t NeoGammaWLEDMethod::gammaT[256];
|
||||||
|
uint8_t NeoGammaWLEDMethod::gammaT_inv[256];
|
||||||
|
|
||||||
// re-calculates & fills gamma table
|
// re-calculates & fills gamma tables
|
||||||
void NeoGammaWLEDMethod::calcGammaTable(float gamma)
|
void NeoGammaWLEDMethod::calcGammaTable(float gamma)
|
||||||
{
|
{
|
||||||
|
float gamma_inv = 1.0f / gamma; // inverse gamma
|
||||||
for (size_t i = 0; i < 256; i++) {
|
for (size_t i = 0; i < 256; i++) {
|
||||||
gammaT[i] = (int)(powf((float)i / 255.0f, gamma) * 255.0f + 0.5f);
|
gammaT[i] = (int)(powf((float)i / 255.0f, gamma) * 255.0f + 0.5f);
|
||||||
|
gammaT_inv[i] = (int)(powf((float)i / 255.0f, gamma_inv) * 255.0f + 0.5f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,13 +158,16 @@ class NeoGammaWLEDMethod {
|
|||||||
public:
|
public:
|
||||||
[[gnu::hot]] static uint8_t Correct(uint8_t value); // apply Gamma to single channel
|
[[gnu::hot]] static uint8_t Correct(uint8_t value); // apply Gamma to single channel
|
||||||
[[gnu::hot]] static uint32_t Correct32(uint32_t color); // apply Gamma to RGBW32 color (WLED specific, not used by NPB)
|
[[gnu::hot]] static uint32_t Correct32(uint32_t color); // apply Gamma to RGBW32 color (WLED specific, not used by NPB)
|
||||||
static void calcGammaTable(float gamma); // re-calculates & fills gamma table
|
static void calcGammaTable(float gamma); // re-calculates & fills gamma tables
|
||||||
static inline uint8_t rawGamma8(uint8_t val) { return gammaT[val]; } // get value from Gamma table (WLED specific, not used by NPB)
|
static inline uint8_t rawGamma8(uint8_t val) { return gammaT[val]; } // get value from Gamma table (WLED specific, not used by NPB)
|
||||||
|
static inline uint8_t rawInverseGamma8(uint8_t val) { return gammaT_inv[val]; } // get value from inverse Gamma table (WLED specific, not used by NPB)
|
||||||
private:
|
private:
|
||||||
static uint8_t gammaT[];
|
static uint8_t gammaT[];
|
||||||
|
static uint8_t gammaT_inv[];
|
||||||
};
|
};
|
||||||
#define gamma32(c) NeoGammaWLEDMethod::Correct32(c)
|
#define gamma32(c) NeoGammaWLEDMethod::Correct32(c)
|
||||||
#define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c)
|
#define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c)
|
||||||
|
#define gamma8inv(c) NeoGammaWLEDMethod::rawInverseGamma8(c)
|
||||||
[[gnu::hot, gnu::pure]] uint32_t color_blend(uint32_t c1, uint32_t c2 , uint8_t blend);
|
[[gnu::hot, gnu::pure]] uint32_t color_blend(uint32_t c1, uint32_t c2 , uint8_t blend);
|
||||||
inline uint32_t color_blend16(uint32_t c1, uint32_t c2, uint16_t b) { return color_blend(c1, c2, b >> 8); };
|
inline uint32_t color_blend16(uint32_t c1, uint32_t c2, uint16_t b) { return color_blend(c1, c2, b >> 8); };
|
||||||
[[gnu::hot, gnu::pure]] uint32_t color_add(uint32_t, uint32_t, bool preserveCR = false);
|
[[gnu::hot, gnu::pure]] uint32_t color_add(uint32_t, uint32_t, bool preserveCR = false);
|
||||||
|
@ -341,7 +341,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
gammaCorrectBri = false;
|
gammaCorrectBri = false;
|
||||||
gammaCorrectCol = false;
|
gammaCorrectCol = false;
|
||||||
}
|
}
|
||||||
NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up table
|
NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up tables
|
||||||
|
|
||||||
t = request->arg(F("TD")).toInt();
|
t = request->arg(F("TD")).toInt();
|
||||||
if (t >= 0) transitionDelayDefault = t;
|
if (t >= 0) transitionDelayDefault = t;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user