FastLED 3.9.15
Loading...
Searching...
No Matches
Fire2023.h
Go to the documentation of this file.
1
10
11/*This is a fire effect based on the famous Fire2012; but with various small improvements.
12Perlin noise is being used to make a fire layer and a smoke layer;
13and the overlay of both can make a quite realistic effect.
14
15The speed of both need to be adapted to the matrix size and width:
16* Super small matrices (like 3x3 led) don't need the smoke
17* medium sized matrices (8x8 for example) profit from fine tuning both Fire Speed/scale as well as Smoke speed/scale
18
19This code was adapted for a matrix with just four LED columns in 90° around a core and a height of 28.
20
21Right at the bottom of the code, you find a translation matrix that needs to be adapted to your set up. I included
22a link to a helpful page for this.
23
24@repo https://github.com/Anderas2/Fire2023
25@author https://github.com/Anderas2
26
27Demo: https://www.youtube.com/shorts/a_Wr0q9YQs4
28*/
29
30
31#include "FastLED.h"
32#include "fl/math/xymap.h"
33#include "fl/math/screenmap.h"
34#include "fl/stl/vector.h"
35
36
37
38// matrix size
39#define WIDTH 4
40#define HEIGHT 28
41#define CentreX (WIDTH / 2) - 1
42#define CentreY (HEIGHT / 2) - 1
43
44// NUM_LEDS = WIDTH * HEIGHT
45#define PIXELPIN 3 // universal pin that works on all platforms
46#define NUM_LEDS 120
47#define LAST_VISIBLE_LED 119
48
49
50// Fire properties
51#define BRIGHTNESS 255
52#define FIRESPEED 17
53#define FLAMEHEIGHT 3.8 // the higher the value, the higher the flame
54#define FIRENOISESCALE 125 // small values, softer fire. Big values, blink fire. 0-255
55
56// Smoke screen properties
57// The smoke screen works best for big fire effects. It effectively cuts of a part of the flames
58// from the rest, sometimes; which looks very much fire-like. For small fire effects with low
59// LED count in the height, it doesn't help
60// speed must be a little different and faster from Firespeed, to be visible.
61// Dimmer should be somewhere in the middle for big fires, and low for small fires.
62#define SMOKESPEED 25 // how fast the perlin noise is parsed for the smoke
63#define SMOKENOISE_DIMMER 250 // thickness of smoke: the lower the value, the brighter the flames. 0-255
64#define SMOKENOISESCALE 125 // small values, softer smoke. Big values, blink smoke. 0-255
65
67
68// fire palette roughly like matlab "hot" colormap
69// This was one of the most important parts to improve - fire color makes fire impression.
70// position, r, g, b value.
71// max value for "position" is BRIGHTNESS
73 27, 0, 0, 0, // black
74 28, 140, 40, 0, // red
75 30, 205, 80, 0, // orange
76 155, 255, 100, 0,
77 210, 255, 200, 0, // yellow
78 255, 255, 255, 255 // white
79};
80CRGBPalette32 hotPalette = hot_gp;
81
82// Map XY coordinates to numbers on the LED strip
83uint8_t XY (uint8_t x, uint8_t y);
84
85
86// parameters and buffer for the noise fl::array
87#define NUM_LAYERS 2
88// two layers of perlin noise make the fire effect
89#define FIRENOISE 0
90#define SMOKENOISE 1
91uint32_t x[NUM_LAYERS];
92uint32_t y[NUM_LAYERS];
93uint32_t z[NUM_LAYERS];
96
99
100uint8_t heat[NUM_LEDS];
101
102
104
105void setup() {
106
107 //Serial.begin(115200);
108 // Adjust this for you own setup. Use the hardware SPI pins if possible.
109 // On Teensy 3.1/3.2 the pins are 11 & 13
110 // Details here: https://github.com/FastLED/FastLED/wiki/SPI-Hardware-or-Bit-banging
111 // In case you see flickering / glitching leds, reduce the data rate to 12 MHZ or less
112 auto screenMap = makeScreenMap();
113 FastLED.addLeds<NEOPIXEL, PIXELPIN>(leds, NUM_LEDS).setScreenMap(screenMap); // Pin für Neopixel
114 FastLED.setBrightness(BRIGHTNESS);
115 FastLED.setDither(DISABLE_DITHER);
116}
117
118void Fire2023(uint32_t now);
119
120void loop() {
123 }
124 FastLED.show();
125}
126
129 for (uint16_t y = 0; y < WIDTH; y++) {
130 for (uint16_t x = 0; x < HEIGHT; x++) {
131 fl::vec2f xy = {float(x) * 3, float(y) * 20};
132 lut.push_back(xy);
133 }
134 }
135 return fl::ScreenMap(lut.data(), lut.size(), 1);
136}
137
138void Fire2023(uint32_t now) {
139 // some changing values
140 // these values are produced by perlin noise to add randomness and smooth transitions
141 uint16_t ctrl1 = inoise16(11 * now, 0, 0);
142 uint16_t ctrl2 = inoise16(13 * now, 100000, 100000);
143 uint16_t ctrl = ((ctrl1 + ctrl2) >> 1);
144
145 // parameters for the fire heat map
146 x[FIRENOISE] = 3 * ctrl * FIRESPEED;
147 y[FIRENOISE] = 20 * now * FIRESPEED;
148 z[FIRENOISE] = 5 * now * FIRESPEED;
149 scale_x[FIRENOISE] = scale8(ctrl1, FIRENOISESCALE);
150 scale_y[FIRENOISE] = scale8(ctrl2, FIRENOISESCALE);
151
152 //calculate the perlin noise data for the fire
153 for (uint8_t x_count = 0; x_count < WIDTH; x_count++) {
154 uint32_t xoffset = scale_x[FIRENOISE] * (x_count - CentreX);
155 for (uint8_t y_count = 0; y_count < HEIGHT; y_count++) {
156 uint32_t yoffset = scale_y[FIRENOISE] * (y_count - CentreY);
157 uint16_t data = ((inoise16(x[FIRENOISE] + xoffset, y[FIRENOISE] + yoffset, z[FIRENOISE])) + 1);
158 noise[FIRENOISE][x_count][y_count] = data >> 8;
159 }
160 }
161
162 // parameters for the smoke map
163 x[SMOKENOISE] = 3 * ctrl * SMOKESPEED;
164 y[SMOKENOISE] = 20 * now * SMOKESPEED;
165 z[SMOKENOISE] = 5 * now * SMOKESPEED;
166 scale_x[SMOKENOISE] = scale8(ctrl1, SMOKENOISESCALE);
167 scale_y[SMOKENOISE] = scale8(ctrl2, SMOKENOISESCALE);
168
169 //calculate the perlin noise data for the smoke
170 for (uint8_t x_count = 0; x_count < WIDTH; x_count++) {
171 uint32_t xoffset = scale_x[SMOKENOISE] * (x_count - CentreX);
172 for (uint8_t y_count = 0; y_count < HEIGHT; y_count++) {
173 uint32_t yoffset = scale_y[SMOKENOISE] * (y_count - CentreY);
174 uint16_t data = ((inoise16(x[SMOKENOISE] + xoffset, y[SMOKENOISE] + yoffset, z[SMOKENOISE])) + 1);
175 noise[SMOKENOISE][x_count][y_count] = data / SMOKENOISE_DIMMER;
176 }
177 }
178
179 //copy everything one line up
180 for (uint8_t y = 0; y < HEIGHT - 1; y++) {
181 for (uint8_t x = 0; x < WIDTH; x++) {
182 heat[XY(x, y)] = heat[XY(x, y + 1)];
183 }
184 }
185
186 // draw lowest line - seed the fire where it is brightest and hottest
187 for (uint8_t x = 0; x < WIDTH; x++) {
188 heat[XY(x, HEIGHT-1)] = noise[FIRENOISE][WIDTH - 1 - x][CentreX];
189 //if (heat[XY(x, HEIGHT-1)] < 200) heat[XY(x, HEIGHT-1)] = 150;
190 }
191
192 // dim the flames based on FIRENOISE noise.
193 // if the FIRENOISE noise is strong, the led goes out fast
194 // if the FIRENOISE noise is weak, the led stays on stronger.
195 // once the heat is gone, it stays dark.
196 for (uint8_t y = 0; y < HEIGHT - 1; y++) {
197 for (uint8_t x = 0; x < WIDTH; x++) {
198 uint8_t dim = noise[FIRENOISE][x][y];
199 // high value in FLAMEHEIGHT = less dimming = high flames
200 dim = dim / FLAMEHEIGHT;
201 dim = 255 - dim;
202 heat[XY(x, y)] = scale8(heat[XY(x, y)] , dim);
203
204 // map the colors based on heatmap
205 // use the heat map to set the color of the LED from the "hot" palette
206 // whichpalette position brightness blend or not
207 leds[XY(x, y)] = ColorFromPalette(hotPalette, heat[XY(x, y)], heat[XY(x, y)], LINEARBLEND);
208
209 // dim the result based on SMOKENOISE noise
210 // this is not saved in the heat map - the flame may dim away and come back
211 // next iteration.
212 leds[XY(x, y)].nscale8(noise[SMOKENOISE][x][y]);
213
214 }
215 }
216}
217
218/* Physical layout of LED strip ****************************/
219uint8_t XY (uint8_t x, uint8_t y) {
220 // any out of bounds address maps to the first hidden pixel
221 // https://macetech.github.io/FastLED-XY-Map-Generator/
222 if ( (x >= WIDTH) || (y >= HEIGHT) ) {
223 return (LAST_VISIBLE_LED + 1);
224 }
225 const uint8_t XYTable[] = {
226 25, 26, 81, 82,
227 25, 27, 81, 83,
228 25, 28, 80, 84,
229 24, 29, 79, 85,
230 23, 30, 78, 86,
231 22, 31, 77, 87,
232 21, 32, 76, 88,
233 20, 33, 75, 89,
234 19, 34, 74, 90,
235 18, 35, 73, 91,
236 17, 36, 72, 92,
237 16, 37, 71, 93,
238 15, 38, 70, 94,
239 14, 39, 69, 95,
240 13, 40, 68, 96,
241 12, 41, 67, 97,
242 11, 42, 66, 98,
243 10, 43, 65, 99,
244 9, 44, 64, 100,
245 8, 45, 63, 101,
246 7, 46, 62, 102,
247 6, 47, 61, 103,
248 5, 48, 60, 104,
249 4, 49, 59, 105,
250 3, 50, 58, 106,
251 2, 51, 57, 107,
252 1, 52, 56, 108,
253 0, 53, 55, 109
254 };
255
256 uint8_t i = (y * WIDTH) + x;
257 uint8_t j = XYTable[i];
258 return j;
259}
260
261
#define NUM_LEDS
fl::CRGB leds[NUM_LEDS]
#define BRIGHTNESS
int y
Definition simple.h:93
int x
Definition simple.h:92
FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_GLOBAL_CONSTRUCTORS CFastLED FastLED
Global LED strip management instance.
#define SMOKENOISE
Definition Fire2023.h:90
uint8_t noise[NUM_LAYERS][WIDTH][HEIGHT]
Definition Fire2023.h:97
#define CentreX
Definition Fire2023.h:41
#define FLAMEHEIGHT
Definition Fire2023.h:53
#define SMOKENOISESCALE
Definition Fire2023.h:64
uint32_t z[NUM_LAYERS]
Definition Fire2023.h:93
void setup()
Definition Fire2023.h:105
uint8_t XY(uint8_t x, uint8_t y)
Definition Fire2023.h:219
uint8_t heat[NUM_LEDS]
Definition Fire2023.h:100
CRGBPalette32 hotPalette
Definition Fire2023.h:80
uint8_t noise2[NUM_LAYERS][WIDTH][HEIGHT]
Definition Fire2023.h:98
#define SMOKESPEED
Definition Fire2023.h:62
#define LAST_VISIBLE_LED
Definition Fire2023.h:47
uint32_t scale_y[NUM_LAYERS]
Definition Fire2023.h:95
#define PIXELPIN
Definition Fire2023.h:45
#define FIRENOISE
Definition Fire2023.h:89
#define FIRENOISESCALE
Definition Fire2023.h:54
#define SMOKENOISE_DIMMER
Definition Fire2023.h:63
#define FIRESPEED
Definition Fire2023.h:52
fl::ScreenMap makeScreenMap()
Definition Fire2023.h:127
void Fire2023(uint32_t now)
Definition Fire2023.h:138
#define NUM_LAYERS
Definition Fire2023.h:87
#define CentreY
Definition Fire2023.h:42
uint32_t scale_x[NUM_LAYERS]
Definition Fire2023.h:94
void loop()
Definition Fire2023.h:120
unsigned int xy(unsigned int x, unsigned int y)
#define WIDTH
#define HEIGHT
fl::size size() const FL_NOEXCEPT
T * data() FL_NOEXCEPT
Definition vector.h:619
void push_back(const T &value) FL_NOEXCEPT
Definition vector.h:624
#define DEFINE_GRADIENT_PALETTE(X)
CRGB ColorFromPalette(const CRGBPalette16 &pal, fl::u8 index, fl::u8 brightness, TBlendType blendType)
#define DISABLE_DITHER
Disable dithering.
Definition dither_mode.h:10
fl::ScreenMap screenMap
Definition Corkscrew.h:101
fl::u16 inoise16(fl::u32 x, fl::u32 y, fl::u32 z, fl::u32 t)
#define EVERY_N_MILLISECONDS(N)
Alias for EVERY_N_MILLIS.
Definition lib8tion.h:1045
fl::u32 millis()
Universal millisecond timer - returns milliseconds since system startup.
vec2< float > vec2f
Definition geometry.h:333
Representation of an 8-bit RGB pixel (Red, Green, Blue)
Definition crgb.h:38