cookbook/intermediate/noise.md
Difficulty Level: ⭐⭐ Intermediate Time to Complete: 45-55 minutes Prerequisites:
You'll Learn:
inoise8, inoise16) in 1D, 2D, and 3D for different effect complexityFastLED includes noise functions for creating organic, natural-looking animations. Unlike random values, noise produces smooth, continuous patterns that flow naturally over time and space.
Perlin noise is a type of gradient noise that creates smooth, natural-looking randomness. It's commonly used for:
Unlike random() which produces abrupt changes, noise creates smooth transitions between values.
FastLED provides several noise functions:
// 1D noise (single parameter)
uint8_t inoise8(uint16_t x);
// 2D noise (two parameters)
uint8_t inoise8(uint16_t x, uint16_t y);
// 3D noise (three parameters)
uint8_t inoise8(uint16_t x, uint16_t y, uint16_t z);
// 16-bit noise for higher precision
uint16_t inoise16(uint32_t x, uint32_t y, uint32_t z);
All noise functions return values in the range 0-255 (for inoise8) or 0-65535 (for inoise16).
void noiseEffect() {
static uint16_t x = 0;
for (int i = 0; i < NUM_LEDS; i++) {
// Generate noise value (0-255)
uint8_t noise = inoise8(x + (i * 100), millis() / 10);
// Map to color (hue)
leds[i] = CHSV(noise, 255, 255);
}
x += 10; // Move through noise space
}
The key to using noise effectively is understanding how the parameters affect the output:
// Each LED gets a different position in noise space
for (int i = 0; i < NUM_LEDS; i++) {
uint8_t noise = inoise8(i * 50); // Spacing controls smoothness
leds[i] = CHSV(noise, 255, 255);
}
void animatedNoise() {
for (int i = 0; i < NUM_LEDS; i++) {
// Add time-based animation
uint8_t noise = inoise8(
i * 50, // Spatial position
millis() / 20 // Time component
);
leds[i] = CHSV(noise, 255, 255);
}
}
The divisor on millis() controls animation speed:
Using two dimensions creates more complex, organic patterns:
void lavaLamp() {
for (int i = 0; i < NUM_LEDS; i++) {
// Create time-varying noise
uint8_t noise = inoise8(
i * 50, // X position (spatial)
millis() / 20 + i * 10 // Y position (time-based)
);
// Use with heat colors palette
leds[i] = ColorFromPalette(HeatColors_p, noise);
}
}
Three dimensions provide the most complex and interesting patterns:
void complexNoise() {
static uint16_t z = 0;
for (int i = 0; i < NUM_LEDS; i++) {
uint8_t noise = inoise8(
i * 50, // X: spatial position
millis() / 20, // Y: time
z // Z: additional animation dimension
);
leds[i] = CHSV(noise, 255, 255);
}
z += 1; // Slowly move through Z dimension
}
Combining noise with palettes creates beautiful effects:
void noisePalette() {
CRGBPalette16 palette = OceanColors_p;
for (int i = 0; i < NUM_LEDS; i++) {
uint8_t noise = inoise8(i * 60, millis() / 30);
leds[i] = ColorFromPalette(palette, noise, 255, LINEARBLEND);
}
}
Combine multiple noise layers for richer effects:
void layeredNoise() {
for (int i = 0; i < NUM_LEDS; i++) {
// Two noise layers with different scales
uint8_t noise1 = inoise8(i * 30, millis() / 20);
uint8_t noise2 = inoise8(i * 80, millis() / 50);
// Combine layers
uint8_t combined = (noise1 + noise2) / 2;
leds[i] = CHSV(combined, 255, 255);
}
}
void clouds() {
CRGBPalette16 cloudPalette = CloudColors_p;
for (int i = 0; i < NUM_LEDS; i++) {
uint8_t noise = inoise8(
i * 40,
millis() / 50 // Slow drift
);
leds[i] = ColorFromPalette(cloudPalette, noise, 255, LINEARBLEND);
}
}
void lava() {
CRGBPalette16 lavaPalette = LavaColors_p;
for (int i = 0; i < NUM_LEDS; i++) {
uint8_t noise = inoise8(
i * 60,
millis() / 25 + i * 15
);
leds[i] = ColorFromPalette(lavaPalette, noise, 255, LINEARBLEND);
}
}
void oceanWaves() {
CRGBPalette16 oceanPalette = OceanColors_p;
static uint16_t z = 0;
for (int i = 0; i < NUM_LEDS; i++) {
// Three layers for depth
uint8_t noise1 = inoise8(i * 40, millis() / 30, z);
uint8_t noise2 = inoise8(i * 70, millis() / 40, z + 1000);
uint8_t combined = (noise1 + noise2) / 2;
leds[i] = ColorFromPalette(oceanPalette, combined, 255, LINEARBLEND);
}
z += 2;
}
void rainbowNoise() {
static uint16_t offset = 0;
for (int i = 0; i < NUM_LEDS; i++) {
uint8_t noise = inoise8(i * 50 + offset, millis() / 20);
leds[i] = CHSV(noise, 200, 255);
}
offset += 5;
}
Use noise to control brightness instead of color:
void noiseBrightness() {
CRGB baseColor = CRGB::Blue;
for (int i = 0; i < NUM_LEDS; i++) {
uint8_t brightness = inoise8(i * 60, millis() / 30);
leds[i] = baseColor;
leds[i].nscale8(brightness);
}
}
Noise functions are computationally efficient, but here are some tips:
millis() / divisor// Problem: Too much variation
uint8_t noise = inoise8(i * 200, millis() / 5);
// Solution: Reduce spacing and slow down
uint8_t noise = inoise8(i * 50, millis() / 30);
// Problem: Barely moving
uint8_t noise = inoise8(i * 10, millis() / 200);
// Solution: Increase spacing or speed up
uint8_t noise = inoise8(i * 50, millis() / 30);
// Problem: All LEDs same color
uint8_t noise = inoise8(i, millis() / 30);
// Solution: Increase spatial multiplier
uint8_t noise = inoise8(i * 50, millis() / 30);
Create moving patterns using noise to control position:
void noisyMovement() {
fadeToBlackBy(leds, NUM_LEDS, 50);
// Use noise to determine which LED to light
uint8_t pos = inoise8(millis() / 10) % NUM_LEDS;
leds[pos] = CHSV(160, 255, 255);
}
#include <FastLED.h>
#define NUM_LEDS 60
#define DATA_PIN 6
CRGB leds[NUM_LEDS];
CRGBPalette16 currentPalette = OceanColors_p;
void setup() {
FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
FastLED.setBrightness(100);
}
void loop() {
noiseEffect();
FastLED.show();
FastLED.delay(1000 / 60); // 60 FPS
}
void noiseEffect() {
static uint16_t z = 0;
for (int i = 0; i < NUM_LEDS; i++) {
// Generate smooth noise
uint8_t noise = inoise8(
i * 50, // Spatial spacing
millis() / 30, // Time-based animation
z // Extra dimension
);
// Map to palette
leds[i] = ColorFromPalette(currentPalette, noise, 255, LINEARBLEND);
}
z += 2; // Move through Z dimension
}