Random Rainbow (min character requirement)

Is it possible w/ PB to do something like make a slow wave for each color LED? Rather than working w/ hue’s?
Basically… All the rainbow cycling type patterns I’ve seen so far, are predictable. They cycle though the rainbow in order.

I built an analog LED color changing light (about 20+ years ago) which has 4 very slow oscillators controlling R,G,B, and Violet LED’s. I love that light! It’s slow, smooth, and totally random. Makes colors I’ve never seen anything else make.

Seems like it would be easy to accomplish this in code these days… And I probably just haven’t looked at the right pattern yet.

Does anyone know of an example that does something like this?

Because they basically cycle from 0 to 1, and use hue to do so.

It sounds.like you want smooth color changing, but in unpredictable ways via RGB (so depending on the brightness of each color, you’ll get red colors if green and blue are very low, or yellowish if red and green are in ratio, etc…)

The problem is that if all 3 are in ratio to each other, it’s white… Do you want white? Complicates the mix, since the lights will also change intensity depending on how bright each color is…

There are lots of ways to do what you describe.

Random walks thru hue, 0-1 smooth changes to a random spot, pick a new and fade to that, but it’ll change in a rainbow way (so if it was changing from red to green, it would go thru yellow, and changing from red to blue could either go thru green (one direction) or thru purple (the other direction, wrapping from 1 to 0)

Another way just picks a hue and fades more directly by shifting some LEDs from color A to color B, which is more visually abrupt (as opposed to all of the LEDs being the same color)

All of these are doable. Each would use different techniques.

Thanks for the reply.
Yes, you understand what I’m wanting to do. And it’s fine if it is sometimes white, and fine that it will also always randomly be changing in brightness… On my analog one, it’s so slow, sometimes it will just be black for several minutes… same with white.

I guess my primary question is, can we control just the R G and B brightness? If so, it would be simple… 3 slow sine waves of slightly different periods is all I’m wanting to do…

Otherwise, I need to think about hue more… Maybe randomly selecting a hue and slowly fading to it would be similar. While also randomly picking saturation and brightness values and slowly fade to them. I can probably find examples of that in the patterns.

When I have time for trying these things, I don’t have the pixelblaze… I already installed the light in my sons room, heh. I guess I need another for playing.

The answer is yes

rgb(.5,.5,.5) is half of each… Values between 0 and 1.

wave(time(.15)) is approximately 1 second sine wave. (Increase the value to increase length). Values will go between 0 and 1.

1 Like

I think that what you’re really looking for is different to your question, or at least there’s a different way of looking at it.

First of all, let’s look at a hue wheel for reference:

Normally the random colour hue patterns will walk around the circumference at a fixed speed. I think what you’re asking for is to walk is a straight line across the hue wheel, which means that the angular speed will vary.

Spherically interpolation should get you started:

@yngndrw - I once started writing slerp with quaternion math in Pixelblaze, but I gave up when patterns got really slow and I didn’t have the time to try optimizations. If you are capable and want to take a stab at it, I think it’d be a really valuable contribution (to be able to properly fade between colors in 3D HSV colorspace).

1 Like

I had a bit of a play, well okay I got a little carried away and it’s now 5AM but that’s beside the point. It seems I’m a little rusty on this subject. It’s pointless showing any code as it’s not even in the same language, but I wanted to explore the various ways of interpolating between colours.

The first four interpolations all just work with Hue. (Saturation is fixed at 100%, Luminance is fixed at 50%)
Colour Lerp

Lerp is a simple linear interpolation of the hue, around the perimeter of the hue circle.

NLerp is a linear interpolation with the hue “angle” split out into X and Y coordinates which are the normalised, that was a waste of time.

CJ Kimberlin Lerp is one I found online, I misread the article and it isn’t really for this problem.

Slerp is a “spherical” interpolation based on the X and Y coordinates and is what I described above, you’ll notice that the speed is no-longer linear - The speed starts off slow, speeds up in the middle and slows down at the end. It looks odd because I’ve missed out something crucial, saturation and luminance.

Which brings us to the last one, a linear interpolation of separate red, green and blue components. You’ll notice that the hue matches the Slerp, but saturation and luminance are now also considered. In my test I simply converted my start and end hue into RGB components, linearly interpolated across the three components and output the RGB values. The interpolation is quick to calculate for each frame once the start and end hues have been converted into their RGB components - There’s no trigonometry like there is with the Slerp method.

Hope this helps.

2 Likes

Here’s one way of doing it – this pattern generates two random colors, usually fairly saturated, then fades slowly between them by doing linear RGB interpolation at a random per-channel rate. Transition time can be set by slider for between 0 and 15 seconds.

// Smooth, slow interpolation between random RGB colors, at random
// rate per channel.
//
// 2021 ZRanger1 


// global variables and initialization
var frameTime = 0;
export var speed = 5000;

var r,g,b;
var rRate,gRate,bRate;
randomizeChannelRates();

var color1 = array(3);
randomRGB(color1);

var color2 = array(3);
randomRGB(color2);

// simple, quick HSV to RGB algorithm adapted from random GLSL
function hsvToRGB(h,s,v,rgbColor) {
  var r,g,b,cv,k;

  h *= 6;
  k = v * s;
  cv = 1-s; cv *=cv;
  
  r = (h+5) % 6;
  r = v - k * max(min(min(r,4-r),1),0);
  
  g = (h+3) % 6;
  g = v - k * max(min(min(g,4-g),1),0);
  
  b = (h+1) % 6;
  b = v - k * max(min(min(b,4-b),1),0);
  
  rgbColor[0] = r;
  rgbColor[1] = g;
  rgbColor[2] = b;
}

// generate random RGB color, with a strong bias towards more
// saturated colors
function randomRGB(c) {
  var h,s,v;
  // generate the color as HSV, then convert. It's easier to control saturation
  // that way.
  h = random(1);
  s = 1-(random(1) * random(1) * random(1) * random(1));
  v = max(random(1),0.0125);
  
  hsvToRGB(h,s,v,c);
}

// color fade time - 0 to 15 seconds
export function sliderSpeed(v) {
  speed = 15000 * v;
}

// generate "normalized" per-channel change rates that we
// can use as simple multipliers
function randomizeChannelRates() {
  var m;
  
  rRate = random(1);
  gRate = random(1);
  bRate = random(1);
  
  m = max(rRate,max(gRate,bRate));
  
  rRate = 2 - rRate/m; 
  gRate = 2 - gRate/m;
  bRate = 2 - bRate/m;
}

// linear interpolator. 
function mix(start,end,val) {
  val = min(1,val)
  return start * (1-val) + end * val;
}

export function beforeRender(delta) {
  pct = frameTime/speed;    
  frameTime += delta;

  // calculate current color by linear interpolation
  r =  mix(color1[0],color2[0],pct * rRate);
  g =  mix(color1[1],color2[1],pct * gRate);
  b =  mix(color1[2],color2[2],pct * bRate);  

  // when we reach the end of a fade, generate
  // new target color 
  if (frameTime > speed) {
    color1[0] = color2[0];
    color1[1] = color2[1];    
    color1[2] = color2[2];    
    
    randomRGB(color2);
    randomizeChannelRates();
    
    frameTime = 0;
  }
}

export function render(index) {
  rgb(r,g,b);
}
1 Like