Advertisement
Guest User

Fire2023 8x8

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