Skip to content

Instantly share code, notes, and snippets.

@neophob
Created April 10, 2013 22:02
Show Gist options
  • Save neophob/5358858 to your computer and use it in GitHub Desktop.
Save neophob/5358858 to your computer and use it in GitHub Desktop.
stripinvaders addon
/*
Fireplace and Perlin Noise colour effect for a WS2801 addressable RGB LED strip.
By Ruben VC
Swapped R and B to compensate LPD8066 vs WS2801 in Fireplace code.
Based on fast and smooth random colour patterns for a LPD8066 addressable RGB LED strip.
By happyinmotion ([email protected])
Simplex noise code taken from Stephen Carmody's Java implementation at:
http://stephencarmody.wikispaces.com/Simplex+Noise
Perlin Noise code copyright 2007 Mike Edwards:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1191768812
*/
// Strip variables:
const int LEDs_for_simplex = 8;
// Extra fake LED at the end, to avoid fencepost problem.
// It is used by simplex node and interpolation code.
float LED_array_blue[NR_OF_PIXELS+1];
float LED_array_green[NR_OF_PIXELS+1];
float LED_array_red[NR_OF_PIXELS+1];
int node_spacing = NR_OF_PIXELS / LEDs_for_simplex;
// Perlin noise global variables:
float x1,y1,x2,y2;
// Set up Perlin globals:
// Simplex noise global variables:
int i, j, k, A[] = {0, 0, 0};
float u, v, w, s;
static float onethird = 0.333333333;
static float onesixth = 0.166666667;
int T[] = {0x15, 0x38, 0x32, 0x2c, 0x0d, 0x13, 0x07, 0x2a};
// Simplex noise variables:
// So that subsequent calls to SimplexNoisePattern produce similar outputs, this needs to be outside the scope of loop()
float yoffset = 0.0;
int perlinmode = 0;
// Simplex noise parameters:
// Useable values for time increment range from 0.005 (barely perceptible) to 0.2 (irritatingly flickery)
// 0.02 seems ideal for relaxed screensaver
float timeinc = 0.1;
// Useable values for space increment range from 0.8 (LEDS doing different things to their neighbours), to 0.02 (roughly one feature present in 15 LEDs).
// 0.05 seems ideal for relaxed screensaver
float spaceinc = 0.1;
void setupFire() {
delay(0.5);
perlinmode = 0;
timeinc = 0.1;
}
void setupPerlin() {
delay(0.5);
perlinmode = 1;
timeinc = 0.05;
}
void loopFire() {
// Simplex noise for whole strip of 64 LEDs.
// (Well, it's simplex noise for 24 LEDs and cubic interpolation between those nodes.)
SimplexNoisePatternInterpolated(spaceinc, timeinc, yoffset);
yoffset += timeinc;
AllOff();
}
void loopPerlin() {
// Simplex noise for whole strip of 64 LEDs.
// (Well, it's simplex noise for 8 LEDs and cubic interpolation between those nodes.)
SimplexNoisePatternInterpolated( spaceinc, timeinc, yoffset);
yoffset += timeinc;
AllOff();
}
void SimplexNoisePatternInterpolated( float spaceinc, float timeinc, float yoffset) {
// Calculate simplex noise for LEDs that are nodes:
// Store raw values from simplex function (-0.347 to 0.347)
float xoffset = 0.0;
for (int i=0; i<=NR_OF_PIXELS; i=i+node_spacing) {
xoffset += spaceinc;
LED_array_blue[i] = SimplexNoise(xoffset,yoffset,0);
LED_array_green[i] = SimplexNoise(xoffset,yoffset,1);
LED_array_blue[i] = SimplexNoise(xoffset,yoffset,2);
}
// Interpolate values for LEDs between nodes
for (int i=0; i<NR_OF_PIXELS; i++) {
int position_between_nodes = i % node_spacing;
int last_node, next_node;
// If at node, skip
if ( position_between_nodes == 0 ) {
// At node for simplex noise, do nothing but update which nodes we are between
last_node = i;
next_node = last_node + node_spacing;
}
// Else between two nodes, so identify those nodes
else {
// And interpolate between the values at those nodes for red and green
float t = float(position_between_nodes) / float(node_spacing);
float t_squaredx3 = 3*t*t;
float t_cubedx2 = 2*t*t*t;
LED_array_red[i] = LED_array_red[last_node] * ( t_cubedx2 - t_squaredx3 + 1.0 ) + LED_array_red[next_node] * ( -t_cubedx2 + t_squaredx3 );
LED_array_blue[i] = LED_array_blue[last_node] * ( t_cubedx2 - t_squaredx3 + 1.0 ) + LED_array_blue[next_node] * ( -t_cubedx2 + t_squaredx3 );
LED_array_green[i] = LED_array_green[last_node] * ( t_cubedx2 - t_squaredx3 + 1.0 ) + LED_array_green[next_node] * ( -t_cubedx2 + t_squaredx3 );
}
}
// Convert values from raw noise to scaled r,g,b and feed to strip
// blue is not used, red is prime color and green is used for lighter orange colors.
if(perlinmode<1){
for (int i=0; i<NR_OF_PIXELS; i++) {
int b = int(LED_array_blue[i]*403 + 16);
int g = int(LED_array_green[i]*403 + 16);
int r = int(0);
if ( g>75 ) { g=75; }
else if ( g<65 ) { g=65; }
if ( b>255 ) { b=255; }
else if ( b<175 ) { b=175; }
strip.setPixelColor(i, r, g, b);
}
} else {
for (int i=0; i<NR_OF_PIXELS; i++) {
int r = int(LED_array_red[i]*403 + 16);
int g = int(LED_array_green[i]*403 + 16);
int b = int(LED_array_blue[i]*403 + 16);
if ( r>127 ) { r=127; }
else if ( r<0 ) { r=0; } // Adds no time at all. Conclusion: constrain() sucks.
if ( g>127 ) { g=127; }
else if ( g<0 ) { g=0; }
if ( b>127 ) { b=127; }
else if ( b<0 ) { b=0; }
strip.setPixelColor(i, r, g, b);
}
}
}
/*****************************************************************************/
// Simplex noise code:
// From an original algorythm by Ken Perlin.
// Returns a value in the range of about [-0.347 .. 0.347]
float SimplexNoise(float x, float y, float z) {
// Skew input space to relative coordinate in simplex cell
s = (x + y + z) * onethird;
i = fastfloor(x+s);
j = fastfloor(y+s);
k = fastfloor(z+s);
// Unskew cell origin back to (x, y , z) space
s = (i + j + k) * onesixth;
u = x - i + s;
v = y - j + s;
w = z - k + s;;
A[0] = A[1] = A[2] = 0;
// For 3D case, the simplex shape is a slightly irregular tetrahedron.
// Determine which simplex we're in
int hi = u >= w ? u >= v ? 0 : 1 : v >= w ? 1 : 2;
int lo = u < w ? u < v ? 0 : 1 : v < w ? 1 : 2;
return k_fn(hi) + k_fn(3 - hi - lo) + k_fn(lo) + k_fn(0);
}
int fastfloor(float n) {
return n > 0 ? (int) n : (int) n - 1;
}
float k_fn(int a) {
s = (A[0] + A[1] + A[2]) * onesixth;
float x = u - A[0] + s;
float y = v - A[1] + s;
float z = w - A[2] + s;
float t = 0.6f - x * x - y * y - z * z;
int h = shuffle(i + A[0], j + A[1], k + A[2]);
A[a]++;
if (t < 0) return 0;
int b5 = h >> 5 & 1;
int b4 = h >> 4 & 1;
int b3 = h >> 3 & 1;
int b2 = h >> 2 & 1;
int r = h & 3;
float p = r == 1 ? x : r == 2 ? y : z;
float q = r == 1 ? y : r == 2 ? z : x;
float b = r == 1 ? z : r == 2 ? x : y;
p = b5 == b3 ? -p : p;
q = b5 == b4 ? -q: q;
b = b5 != (b4^b3) ? -r : r;
t *= t;
return 8 * t * t * (p + (b == 0 ? q + b : b2 == 0 ? q : r));
}
int shuffle(int i, int j, int k) {
return b(i, j, k, 0) + b(j, k, i, 1) + b(k, i, j, 2) + b(i, j, k, 3) + b(j, k, i, 4) + b(k, i, j, 5) + b(i, j, k, 6) + b(j, k, i, 7);
}
int b(int i, int j, int k, int B) {
return T[b(i, B) << 2 | b(j, B) << 1 | b(k, B)];
}
int b(int N, int B) {
return N >> B & 1;
}
void AllOff() {
// Reset LED strip
strip.begin();
strip.show();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment