Advertisement
pchestna

L3D Cube Perlin/simplex noise demo

Dec 27th, 2014
464
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.93 KB | None | 0 0
  1. #include<FastLED.h>
  2.  
  3. #define LED_PIN     2
  4. #define BRIGHTNESS  32
  5. #define LED_TYPE    WS2812B
  6. #define COLOR_ORDER GRB
  7.  
  8. const uint8_t kCubeSize = 8;
  9. const bool    kMatrixSerpentineLayout = false;
  10.  
  11. typedef enum {X_LAYER, Y_LAYER, Z_LAYER} LAYER;
  12. typedef enum {UP, DOWN} DIRECTION;
  13.  
  14. // Dictates the direction of the frames
  15. DIRECTION fillDirection = UP;
  16. // Which axis are we filling the frames
  17. LAYER layer = Y_LAYER;
  18. // Which frame number gets the new noise data
  19. int nFillFrame;
  20.  
  21. #define NUM_LEDS (kCubeSize * kCubeSize * kCubeSize)
  22. #define MAX_DIMENSION kCubeSize
  23.  
  24. // The leds
  25. CRGB leds[NUM_LEDS];
  26.  
  27. // The 16 bit version of our coordinates
  28. static uint16_t x;
  29. static uint16_t y;
  30. static uint16_t z;
  31.  
  32. // This example combines two features of FastLED to produce a remarkable range of
  33. // effects from a relatively small amount of code.  This example combines FastLED's
  34. // color palette lookup functions with FastLED's Perlin/simplex noise generator, and
  35. // the combination is extremely powerful.
  36. //
  37. // You might want to look at the "ColorPalette" and "Noise" examples separately
  38. // if this example code seems daunting.
  39. //
  40. // The basic setup here is that for each frame, we generate a new array of
  41. // 'noise' data, and then map it onto the LED matrix through a color palette.
  42. //
  43. // Periodically, the color palette is changed, and new noise-generation parameters
  44. // are chosen at the same time.  In this example, specific noise-generation
  45. // values have been selected to match the given color palettes; some are faster,
  46. // or slower, or larger, or smaller than others, but there's no reason these
  47. // parameters can't be freely mixed-and-matched.
  48. //
  49. // In addition, this example includes some fast automatic 'data smoothing' at
  50. // lower noise speeds to help produce smoother animations in those cases.
  51. //
  52. // The FastLED built-in color palettes (Forest, Clouds, Lava, Ocean, Party) are
  53. // used, as well as some 'hand-defined' ones, and some proceedurally generated
  54. // palettes.
  55.  
  56. // We're using the x/y dimensions to map to the x/y pixels on the matrix.  We'll
  57. // use the z-axis for "time".  speed determines how fast time moves forward.  Try
  58. // 1 for a very slow moving effect, or 60 for something that ends up looking like
  59. // water.
  60. uint16_t speed = 1; // speed is set dynamically once we've started up
  61.  
  62. // Scale determines how far apart the pixels in our noise matrix are.  Try
  63. // changing these values around to see how it affects the motion of the display.  The
  64. // higher the value of scale, the more "zoomed out" the noise will be.  A value
  65. // of 1 will be so zoomed in, you'll mostly see solid colors.
  66. uint16_t scale = 30; // scale is set dynamically once we've started up
  67.  
  68. // This is the array that we keep our computed noise values in
  69. uint8_t noise[MAX_DIMENSION][MAX_DIMENSION];
  70.  
  71. CRGBPalette16 currentPalette( LavaColors_p );
  72. uint8_t       colorLoop = 1;
  73.  
  74. void setup() {
  75.   delay(3000);
  76.   LEDS.addLeds<LED_TYPE,LED_PIN,COLOR_ORDER>(leds,NUM_LEDS);
  77.   LEDS.setBrightness(BRIGHTNESS);
  78.  
  79.   // Initialize our coordinates to some random values
  80.   x = random16();
  81.   y = random16();
  82.   z = random16();
  83.  
  84.   if (fillDirection == UP) nFillFrame = 0; else nFillFrame = kCubeSize-1;
  85. }
  86.  
  87. // Fill a frame of the x/y array of 8-bit noise values using the inoise8 function.
  88. void fillnoise8() {
  89.   // If we're runing at a low "speed", some 8-bit artifacts become visible
  90.   // from frame-to-frame.  In order to reduce this, we can do some fast data-smoothing.
  91.   // The amount of data smoothing we're doing depends on "speed".
  92.   uint8_t dataSmoothing = 0;
  93.   if( speed < 50) {
  94.     dataSmoothing = 200 - (speed * 4);
  95.   }
  96.  
  97.   for(int i = 0; i < MAX_DIMENSION; i++) {
  98.     int ioffset = scale * i;
  99.     for(int j = 0; j < MAX_DIMENSION; j++) {
  100.       int joffset = scale * j;
  101.      
  102.       uint8_t data = inoise8(x + ioffset,y + joffset,z);
  103.  
  104.       // The range of the inoise8 function is roughly 16-238.
  105.       // These two operations expand those values out to roughly 0..255
  106.       // You can comment them out if you want the raw noise data.
  107.       data = qsub8(data,16);
  108.       data = qadd8(data,scale8(data,39));
  109.  
  110.       if( dataSmoothing ) {
  111.         uint8_t olddata = noise[i][j];
  112.         uint8_t newdata = scale8( olddata, dataSmoothing) + scale8( data, 256 - dataSmoothing);
  113.         data = newdata;
  114.       }
  115.      
  116.       noise[i][j] = data;
  117.     }
  118.   }
  119.  
  120.   z += speed;
  121.  
  122.   // apply slow drift to X and Y, just for visual variation.
  123.   x += speed / 8;
  124.   y -= speed / 16;
  125. }
  126.  
  127. void mapNoiseToLEDsUsingPalette()
  128. {
  129.   static uint8_t ihue=0;
  130.  
  131.   for(int i = 0; i < kCubeSize; i++) {
  132.     for(int j = 0; j < kCubeSize; j++) {
  133.       // We use the value at the (i,j) coordinate in the noise
  134.       // array for our brightness, and the flipped value from (j,i)
  135.       // for our pixel's index into the color palette.
  136.  
  137.       uint8_t index = noise[j][i];
  138.       uint8_t bri =   noise[i][j];
  139.  
  140.       // if this palette is a 'loop', add a slowly-changing base value
  141.       if( colorLoop) {
  142.         index += ihue;
  143.       }
  144.  
  145.       // brighten up, as the color palette itself often contains the
  146.       // light/dark dynamic range desired
  147.       if( bri > 127 ) {
  148.         bri = 255;
  149.       } else {
  150.         bri = dim8_raw( bri * 2);
  151.       }
  152.  
  153.       CRGB color = ColorFromPalette( currentPalette, index, bri);
  154.      
  155.       static int nTo;
  156.       switch (layer)
  157.       {
  158.          case X_LAYER:
  159.            nTo = XYZ(nFillFrame, i, j);
  160.          break;
  161.          case Y_LAYER:
  162.            nTo = XYZ(i, nFillFrame, j);
  163.          break;
  164.          case Z_LAYER:
  165.            nTo = XYZ(i, j, nFillFrame);
  166.          break;
  167.       }
  168.       leds[nTo] = color;
  169.     }
  170.   }
  171.  
  172.   ihue+=1;
  173. }
  174.  
  175. // Copies pixels from one layer to another
  176. void copyLayer(uint8_t fromLayer, uint8_t toLayer);
  177. void copyLayer(uint8_t fromLayer, uint8_t toLayer)
  178. {
  179.   int nFrom; // from pixel
  180.   int nTo; // to pixel
  181.  
  182.   for (int m = 0; m < kCubeSize; m++)
  183.     for (int n = 0; n < kCubeSize; n++)
  184.     {
  185.       switch (layer)
  186.       {
  187.          case X_LAYER:
  188.            nFrom = XYZ(fromLayer, m, n);
  189.            nTo = XYZ(toLayer, m, n);
  190.          break;
  191.          case Y_LAYER:
  192.            nFrom = XYZ(m, fromLayer, n);
  193.            nTo = XYZ(m, toLayer, n);
  194.          break;
  195.          case Z_LAYER:
  196.            nFrom = XYZ(m, n, fromLayer);
  197.            nTo = XYZ(m, n, toLayer);
  198.          break;
  199.       }
  200.       leds[nTo] = leds[nFrom];
  201.     }
  202. }
  203.  
  204. // Copy frames foward in the plane being used from the fillFrame back
  205. void moveFrameForward()
  206. {
  207.   switch (fillDirection)
  208.   {
  209.     case UP:
  210.     {
  211.       for (int nLayer = kCubeSize-1; nLayer > 0; nLayer--)
  212.         copyLayer(nLayer-1, nLayer);
  213.     }
  214.     break;
  215.    
  216.     case DOWN:
  217.     {
  218.       for (int nLayer = 0; nLayer < kCubeSize; nLayer++)
  219.         copyLayer(nLayer+1, nLayer);
  220.     }
  221.     break;
  222.   }
  223. }
  224.  
  225. void loop() {
  226.   // Periodically choose a new palette, speed, and scale
  227.   //ChangePaletteAndSettingsPeriodically();
  228.  
  229.   // generate noise data
  230.   fillnoise8();
  231.  
  232.   // convert the noise data to colors in the LED array
  233.   // using the current palette
  234.   mapNoiseToLEDsUsingPalette();
  235.  
  236.   LEDS.show();
  237.   delay(10);
  238.  
  239.   // Copy frames
  240.   moveFrameForward();
  241. }
  242.  
  243.  
  244.  
  245. // There are several different palettes of colors demonstrated here.
  246. //
  247. // FastLED provides several 'preset' palettes: RainbowColors_p, RainbowStripeColors_p,
  248. // OceanColors_p, CloudColors_p, LavaColors_p, ForestColors_p, and PartyColors_p.
  249. //
  250. // Additionally, you can manually define your own color palettes, or you can write
  251. // code that creates color palettes on the fly.
  252.  
  253. // 1 = 5 sec per palette
  254. // 2 = 10 sec per palette
  255. // etc
  256. #define HOLD_PALETTES_X_TIMES_AS_LONG 5
  257.  
  258. void ChangePaletteAndSettingsPeriodically()
  259. {
  260.   uint8_t secondHand = ((millis() / 1000) / HOLD_PALETTES_X_TIMES_AS_LONG) % 60;
  261.   static uint8_t lastSecond = 99;
  262.  
  263.   if( lastSecond != secondHand) {
  264.     lastSecond = secondHand;
  265.     if( secondHand ==  0)  { currentPalette = RainbowColors_p;         speed = 1; scale = 30; colorLoop = 1; }
  266.     if( secondHand ==  5)  { SetupPurpleAndGreenPalette();             speed = 1; scale = 50; colorLoop = 1; }
  267.     if( secondHand == 10)  { SetupBlackAndWhiteStripedPalette();       speed = 1; scale = 30; colorLoop = 1; }
  268.     if( secondHand == 15)  { currentPalette = ForestColors_p;          speed = 1; scale =120; colorLoop = 0; }
  269.     if( secondHand == 20)  { currentPalette = CloudColors_p;           speed = 1; scale = 30; colorLoop = 0; }
  270.     if( secondHand == 25)  { currentPalette = LavaColors_p;            speed = 1; scale = 50; colorLoop = 0; }
  271.     if( secondHand == 30)  { currentPalette = OceanColors_p;           speed = 1; scale = 90; colorLoop = 0; }
  272.     if( secondHand == 35)  { currentPalette = PartyColors_p;           speed = 1; scale = 30; colorLoop = 1; }
  273.     if( secondHand == 40)  { SetupRandomPalette();                     speed = 1; scale = 20; colorLoop = 1; }
  274.     if( secondHand == 45)  { SetupRandomPalette();                     speed = 1; scale = 50; colorLoop = 1; }
  275.     if( secondHand == 50)  { SetupRandomPalette();                     speed = 1; scale = 90; colorLoop = 1; }
  276.     if( secondHand == 55)  { currentPalette = RainbowStripeColors_p;   speed = 1; scale = 20; colorLoop = 1; }
  277.   }
  278. }
  279.  
  280. // This function generates a random palette that's a gradient
  281. // between four different colors.  The first is a dim hue, the second is
  282. // a bright hue, the third is a bright pastel, and the last is
  283. // another bright hue.  This gives some visual bright/dark variation
  284. // which is more interesting than just a gradient of different hues.
  285. void SetupRandomPalette()
  286. {
  287.   currentPalette = CRGBPalette16(
  288.                       CHSV( random8(), 255, 32),
  289.                       CHSV( random8(), 255, 255),
  290.                       CHSV( random8(), 128, 255),
  291.                       CHSV( random8(), 255, 255));
  292. }
  293.  
  294. // This function sets up a palette of black and white stripes,
  295. // using code.  Since the palette is effectively an array of
  296. // sixteen CRGB colors, the various fill_* functions can be used
  297. // to set them up.
  298. void SetupBlackAndWhiteStripedPalette()
  299. {
  300.   // 'black out' all 16 palette entries...
  301.   fill_solid( currentPalette, 16, CRGB::Black);
  302.   // and set every fourth one to white.
  303.   currentPalette[0] = CRGB::White;
  304.   currentPalette[4] = CRGB::White;
  305.   currentPalette[8] = CRGB::White;
  306.   currentPalette[12] = CRGB::White;
  307.  
  308. }
  309.  
  310. // This function sets up a palette of purple and green stripes.
  311. void SetupPurpleAndGreenPalette()
  312. {
  313.   CRGB purple = CHSV( HUE_PURPLE, 255, 255);
  314.   CRGB green  = CHSV( HUE_GREEN, 255, 255);
  315.   CRGB black  = CRGB::Black;
  316.  
  317.   currentPalette = CRGBPalette16(
  318.     green,  green,  black,  black,
  319.     purple, purple, black,  black,
  320.     green,  green,  black,  black,
  321.     purple, purple, black,  black );
  322. }
  323.  
  324. //
  325. // xyz coordinate mapping code
  326. //
  327. uint16_t XYZ( uint8_t x, uint8_t y, uint8_t z)
  328. {
  329.   uint16_t i;
  330.  
  331.   i = 8 * ((y * kCubeSize) + x) + z;
  332.  
  333.   if ((i >= 0) && (i <= 512))
  334.     return i;
  335.   else
  336.     return 0;
  337. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement