jasoncoon/esp8266-fastled-webserver

Fade between patterns

Closed this issue · 4 comments

This is a request to add or suggest ideas on how to implement a fade feature between patterns. The idea is when switching between patterns to make the transition a bit more graceful instead of just flipping to the next pattern. Think of it like a crossfade between two video scenes. Now, crossfade is a bit more than I have in mind, I'm thinking just a quick fade to black and then fade up into the next pattern. Ideally the fade timing would be configurable.

I was thinking something just before FastLED.show() like:

check to see if fade is enabled then
compare current pattern to previous pattern, if changed then
fade the current pattern
fade up the next pattern

Am I crazy? Any ideas, suggestions would be appreciated!

I did something simliar. In my case I actually have 2 CRGB leds arrays. One where the patterns get written to and one which is written out by fastled. This way I can fade from the last frame of a pattern to the new pattern (already running). So not a real crossfade but coming close. And it gives me the possibility to divide in equal segments, mirror and reverse all patterns quite easy....

The challenge you have is that you need to wait when switching a pattern until your current pattern is completely off and then switch to the new one.
So you need the "currentPattern" and the next along with probably something for the fading.

Quick and dirty and absolutely untested:
replace the lines

// Call the current pattern function once, updating the 'leds' array
  patterns[currentPatternIndex].pattern();

  FastLED.show();

with

static uint8_t previousPatternIndex = currentPatternIndex; // static will remember its value over cetain loops but remains local
static uint8_t amountOfBlack = 0; // fraction of black currently on the stip
if(currentPatternIndex != previousPatternIndex)	// if one has set a new pattern, this shouldn differ from the old.
{
	if(amountOfBlack == 255)			// 255 should be all black
	{
		previousPatternIndex = currentPatternIndex;	// once everything is dark, switch previous to current
	}
	qadd8(amountOfBlack, 4); // increase the amoun t of black (fades out)
}
else
{
	qsub8(amountOfBlack, 4); // if patterns are equal (no new one) we fade back in  until amount of black is zero...
}
patterns[previousPatternIndex].pattern(); 	// call the previousPattern (names are a bit misleading as current pattern is now actually the next pattern
											// and previousPattern is the current one being calculated.

if(amountOfBlack) fadeToBlackby(leds, NUM_LEDS, amountOfBlack); // only fade if there is a portion of black

FastLED.Show();

// The speed to fade to black and back in is now (256/4 + 256/4) / FPS ~ 1 second at 120 fps
// if fade time should be adjustable, one may use the qadd/qsub parameter as settable variable....
// if you need a fixed timing you could calculate based on the fps...

You're not crazy at all, @atatistcheff! 😆 It's a great idea.

Thanks for the great recommendation @tobi01001.

Scott Marley has a great FastLED tutorial series on YouTube, and he covers another way of implementing pattern crossfade here: https://youtu.be/fRXJQVdwrog?t=324

I won't likely implement pattern crossfade in this project/repo any time soon, but it should be possible to add it to your own using one of these approaches.

Interesting.
Here's a smal extension to switch at least between Solid Colours in a smooth way:

void showSolidColor()
{
// fill_solid(leds, LEDMax, solidColor);
fadeTowardColor( leds, LEDMax, solidColor, 8);

FastLED.delay(30);

}

CRGB fadeTowardColor( CRGB& cur, const CRGB& target, uint8_t amount) {
nblendU8TowardU8( cur.red, target.red, amount);
nblendU8TowardU8( cur.green, target.green, amount);
nblendU8TowardU8( cur.blue, target.blue, amount);
return cur;
}

// Helper function that blends one uint8_t toward another by a given amount
void nblendU8TowardU8( uint8_t& cur, const uint8_t target, uint8_t amount) {
if( cur == target) return;

if( cur < target ) {
uint8_t delta = target - cur;
delta = scale8_video( delta, amount);
cur += delta;
} else {
uint8_t delta = cur - target;
delta = scale8_video( delta, amount);
cur -= delta;
}
}

// Fade an entire array of CRGBs toward a given background color by a given amount
// This function modifies the pixel array in place.
void fadeTowardColor( CRGB* L, uint16_t N, const CRGB& bgColor, uint8_t fadeAmount)
{
for( uint16_t i = 0; i < N; i++) { fadeTowardColor( L[i], bgColor, fadeAmount); }
}