Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Aurora Borealis effect #1589

Merged
merged 10 commits into from
Jan 4, 2021
Merged
Prev Previous commit
Improvements to Aurora effect
- Smoother on low speed
- CRGB is trivially copiable
- Replaced Red & Blue mode
- Simplified logic and mem use a tiny bit
- Aurora2 palette a bit less yellowish
  • Loading branch information
Aircoookie committed Jan 4, 2021
commit 7d98cbdba9de0364738c14328041df43e73d1037
106 changes: 47 additions & 59 deletions wled00/FX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -994,14 +994,6 @@ uint16_t WS2812FX::mode_running_color(void) {
}


/*
* Alternating red/blue pixels running.
*/
uint16_t WS2812FX::mode_running_red_blue(void) {
return running(RED, BLUE);
}


/*
* Alternating red/green pixels running.
*/
Expand Down Expand Up @@ -3878,72 +3870,70 @@ uint16_t WS2812FX::mode_tv_simulator(void) {
#define BACKLIGHT 5
#define W_MAX_COUNT 20 //Number of simultaneous waves
#define W_MAX_SPEED 6 //Higher number, higher speed
#define W_WIDTH_FACTOR 3 //Higher number, smaller waves
#define W_WIDTH_FACTOR 6 //Higher number, smaller waves

class AuroraWave {
private:
uint32_t segment_length;
uint ttl;
uint16_t ttl;
CRGB basecolor;
float basealpha;
uint age;
uint width;
uint16_t age;
uint16_t width;
float center;
bool goingleft;
float speed;
float speed_factor;
bool alive = true;

public:
void init(uint32_t segment_length, uint32_t wave_speed, CRGB color) {
this -> segment_length = segment_length;
void init(uint32_t segment_length, CRGB color) {
ttl = random(500, 1501);
basecolor = color;
basealpha = random(50, 101) / (float)100;
basealpha = random(60, 101) / (float)100;
age = 0;
width = random(segment_length / 10, segment_length / W_WIDTH_FACTOR);
width = random(segment_length / 20, segment_length / W_WIDTH_FACTOR); //half of width to make math easier
if (!width) width = 1;
center = random(101) / (float)100 * segment_length;
goingleft = random(0, 2) == 0;
speed = (random(10, 31) / (float)100 * W_MAX_SPEED / 255) * wave_speed;
speed_factor = (random(10, 31) / (float)100 * W_MAX_SPEED / 255);
alive = true;
}

CRGB* getColorForLED(int ledIndex) {
if(ledIndex < center - width / 2 || ledIndex > center + width / 2) {
//Position out of range of this wave
return NULL;
} else {
CRGB* rgb = new CRGB();

//Offset of this led from center of wave
//The further away from the center, the dimmer the LED
int offset = abs(ledIndex - center);
float offsetFactor = (float)offset / (width / 2);

//The age of the wave determines it brightness.
//At half its maximum age it will be the brightest.
float ageFactor = 0.1;
if((float)age / ttl < 0.5) {
ageFactor = (float)age / (ttl / 2);
} else {
ageFactor = (float)(ttl - age) / ((float)ttl * 0.5);
}
CRGB getColorForLED(int ledIndex) {
if(ledIndex < center - width || ledIndex > center + width) return 0; //Position out of range of this wave

//Calculate color based on above factors and basealpha value
rgb -> r = basecolor.r * (1 - offsetFactor) * ageFactor * basealpha;
rgb -> g = basecolor.g * (1 - offsetFactor) * ageFactor * basealpha;
rgb -> b = basecolor.b * (1 - offsetFactor) * ageFactor * basealpha;

return rgb;
CRGB rgb;

//Offset of this led from center of wave
//The further away from the center, the dimmer the LED
float offset = ledIndex - center;
if (offset < 0) offset = -offset;
float offsetFactor = offset / width;

//The age of the wave determines it brightness.
//At half its maximum age it will be the brightest.
float ageFactor = 0.1;
if((float)age / ttl < 0.5) {
ageFactor = (float)age / (ttl / 2);
} else {
ageFactor = (float)(ttl - age) / ((float)ttl * 0.5);
}

//Calculate color based on above factors and basealpha value
float factor = (1 - offsetFactor) * ageFactor * basealpha;
rgb.r = basecolor.r * factor;
rgb.g = basecolor.g * factor;
rgb.b = basecolor.b * factor;

return rgb;
};

//Change position and age of wave
//Determine if its sill "alive"
void update() {
void update(uint32_t segment_length, uint32_t speed) {
if(goingleft) {
center -= speed;
center -= speed_factor * speed;
} else {
center += speed;
center += speed_factor * speed;
}

age++;
Expand All @@ -3952,11 +3942,11 @@ class AuroraWave {
alive = false;
} else {
if(goingleft) {
if(center + width / 2 < 0) {
if(center + width < 0) {
alive = false;
}
} else {
if(center - width / 2 > segment_length) {
if(center - width > segment_length) {
alive = false;
}
}
Expand Down Expand Up @@ -3986,36 +3976,34 @@ uint16_t WS2812FX::mode_aurora(void) {
waves = reinterpret_cast<AuroraWave*>(SEGENV.data);

for(int i = 0; i < SEGENV.aux1; i++) {
waves[i].init(SEGMENT.length(), SEGMENT.speed, col_to_crgb(color_from_palette(random8(), false, false, random(0, 3))));
waves[i].init(SEGLEN, col_to_crgb(color_from_palette(random8(), false, false, random(0, 3))));
}
} else {
waves = reinterpret_cast<AuroraWave*>(SEGENV.data);
}

for(int i = 0; i < SEGENV.aux1; i++) {
//Update values of wave
waves[i].update();
waves[i].update(SEGLEN, SEGMENT.speed);

if(!(waves[i].stillAlive())) {
//If a wave dies, reinitialize it starts over.
waves[i].init(SEGMENT.length(), SEGMENT.speed, col_to_crgb(color_from_palette(random8(), false, false, random(0, 3))));
waves[i].init(SEGLEN, col_to_crgb(color_from_palette(random8(), false, false, random(0, 3))));
}
}

//Loop through LEDs to determine color
for(int i = 0; i < SEGMENT.length(); i++) {
for(int i = 0; i < SEGLEN; i++) {
CRGB mixedRgb = CRGB(BACKLIGHT, BACKLIGHT, BACKLIGHT);

//For each LED we must check each wave if it is "active" at this position.
//If there are multiple waves active on a LED we multiply their values.
for(int j = 0; j < SEGENV.aux1; j++) {
CRGB* rgb = waves[j].getColorForLED(i);
CRGB rgb = waves[j].getColorForLED(i);

if(rgb != NULL) {
mixedRgb += *rgb;
if(rgb != CRGB(0)) {
mixedRgb += rgb;
}

delete []rgb;
}

setPixelColor(i, mixedRgb[0], mixedRgb[1], mixedRgb[2], BACKLIGHT);
Expand Down
17 changes: 7 additions & 10 deletions wled00/FX.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@
#define IS_REVERSE ((SEGMENT.options & REVERSE ) == REVERSE )
#define IS_SELECTED ((SEGMENT.options & SELECTED ) == SELECTED )

#define MODE_COUNT 119
#define MODE_COUNT 118

#define FX_MODE_STATIC 0
#define FX_MODE_BLINK 1
Expand Down Expand Up @@ -159,7 +159,7 @@
#define FX_MODE_TRAFFIC_LIGHT 35
#define FX_MODE_COLOR_SWEEP_RANDOM 36
#define FX_MODE_RUNNING_COLOR 37
#define FX_MODE_RUNNING_RED_BLUE 38
#define FX_MODE_AURORA 38
#define FX_MODE_RUNNING_RANDOM 39
#define FX_MODE_LARSON_SCANNER 40
#define FX_MODE_COMET 41
Expand Down Expand Up @@ -239,7 +239,6 @@
#define FX_MODE_BLENDS 115
#define FX_MODE_TV_SIMULATOR 116
#define FX_MODE_DYNAMIC_SMOOTH 117
#define FX_MODE_AURORA 118

class WS2812FX {
typedef uint16_t (WS2812FX::*mode_ptr)(void);
Expand Down Expand Up @@ -389,7 +388,7 @@ class WS2812FX {
_mode[FX_MODE_TRAFFIC_LIGHT] = &WS2812FX::mode_traffic_light;
_mode[FX_MODE_COLOR_SWEEP_RANDOM] = &WS2812FX::mode_color_sweep_random;
_mode[FX_MODE_RUNNING_COLOR] = &WS2812FX::mode_running_color;
_mode[FX_MODE_RUNNING_RED_BLUE] = &WS2812FX::mode_running_red_blue;
_mode[FX_MODE_AURORA] = &WS2812FX::mode_aurora;
_mode[FX_MODE_RUNNING_RANDOM] = &WS2812FX::mode_running_random;
_mode[FX_MODE_LARSON_SCANNER] = &WS2812FX::mode_larson_scanner;
_mode[FX_MODE_COMET] = &WS2812FX::mode_comet;
Expand Down Expand Up @@ -471,7 +470,6 @@ class WS2812FX {
_mode[FX_MODE_BLENDS] = &WS2812FX::mode_blends;
_mode[FX_MODE_TV_SIMULATOR] = &WS2812FX::mode_tv_simulator;
_mode[FX_MODE_DYNAMIC_SMOOTH] = &WS2812FX::mode_dynamic_smooth;
_mode[FX_MODE_AURORA] = &WS2812FX::mode_aurora;

_brightness = DEFAULT_BRIGHTNESS;
currentPalette = CRGBPalette16(CRGB::Black);
Expand Down Expand Up @@ -604,7 +602,7 @@ class WS2812FX {
mode_colorful(void),
mode_traffic_light(void),
mode_running_color(void),
mode_running_red_blue(void),
mode_aurora(void),
mode_running_random(void),
mode_larson_scanner(void),
mode_comet(void),
Expand Down Expand Up @@ -684,8 +682,7 @@ class WS2812FX {
mode_candy_cane(void),
mode_blends(void),
mode_tv_simulator(void),
mode_dynamic_smooth(void),
mode_aurora(void);
mode_dynamic_smooth(void);

private:
NeoPixelWrapper *bus;
Expand Down Expand Up @@ -766,15 +763,15 @@ const char JSON_mode_names[] PROGMEM = R"=====([
"Solid","Blink","Breathe","Wipe","Wipe Random","Random Colors","Sweep","Dynamic","Colorloop","Rainbow",
"Scan","Scan Dual","Fade","Theater","Theater Rainbow","Running","Saw","Twinkle","Dissolve","Dissolve Rnd",
"Sparkle","Sparkle Dark","Sparkle+","Strobe","Strobe Rainbow","Strobe Mega","Blink Rainbow","Android","Chase","Chase Random",
"Chase Rainbow","Chase Flash","Chase Flash Rnd","Rainbow Runner","Colorful","Traffic Light","Sweep Random","Running 2","Red & Blue","Stream",
"Chase Rainbow","Chase Flash","Chase Flash Rnd","Rainbow Runner","Colorful","Traffic Light","Sweep Random","Running 2","Aurora","Stream",
"Scanner","Lighthouse","Fireworks","Rain","Merry Christmas","Fire Flicker","Gradient","Loading","Police","Police All",
"Two Dots","Two Areas","Circus","Halloween","Tri Chase","Tri Wipe","Tri Fade","Lightning","ICU","Multi Comet",
"Scanner Dual","Stream 2","Oscillate","Pride 2015","Juggle","Palette","Fire 2012","Colorwaves","Bpm","Fill Noise",
"Noise 1","Noise 2","Noise 3","Noise 4","Colortwinkles","Lake","Meteor","Meteor Smooth","Railway","Ripple",
"Twinklefox","Twinklecat","Halloween Eyes","Solid Pattern","Solid Pattern Tri","Spots","Spots Fade","Glitter","Candle","Fireworks Starburst",
"Fireworks 1D","Bouncing Balls","Sinelon","Sinelon Dual","Sinelon Rainbow","Popcorn","Drip","Plasma","Percent","Ripple Rainbow",
"Heartbeat","Pacifica","Candle Multi", "Solid Glitter","Sunrise","Phased","Twinkleup","Noise Pal", "Sine","Phased Noise",
"Flow","Chunchun","Dancing Shadows","Washing Machine","Candy Cane","Blends","TV Simulator","Dynamic Smooth","Aurora"
"Flow","Chunchun","Dancing Shadows","Washing Machine","Candy Cane","Blends","TV Simulator","Dynamic Smooth"
])=====";


Expand Down
10 changes: 5 additions & 5 deletions wled00/palettes.h
Original file line number Diff line number Diff line change
Expand Up @@ -632,11 +632,11 @@ const byte temperature_gp[] PROGMEM = {
255, 80, 3, 3};

const byte Aurora2[] PROGMEM = {
0, 17, 177, 13, //Greenish
64, 148, 242, 5, //Greenish
128, 25, 173, 121, //Turquoise
192, 250, 77, 127, //Pink
255, 171, 101, 221 //Purple
0, 17, 177, 13, //Greenish
64, 121, 242, 5, //Greenish
128, 25, 173, 121, //Turquoise
192, 250, 77, 127, //Pink
255, 171, 101, 221 //Purple
};

// Single array of defined cpt-city color palettes.
Expand Down