Run several patterns layers on top of each other

Hello,

I’m trying to run 2 or more patterns in one pattern on a 2D mapping.
Let’s say i have pattern1 running all the time, and when I click a toggle button, i want a second pattern to run on top. The best would be to give priority to the most “luminous” pixel of each pattern when displaying, but i can also live with layers (if a pixel is ON in layer 1 for example, it is displayed regardless of the pixel status in layer 2).

The idea is to basically be able to take a manual input to activate/deactivate some effects without changing the pattern, for example to select appropriate animations manually depending of the music (if we’re in buildup, break, full on…) on a festival stage.

I created the code below (DO NOT RUN IT !), and put each pattern calculation (based on x/y since i have a 2D mapping) in sub functions:

//Program to test the ability of having 2 or more separate animations in 1 pattern

//Define working variables specific to the 2D mapping
pixelColumns = 9
pixelHeight = pixelCount / pixelColumns

//Define arrays to render separately the patterns
var hsvPattern1 = [1, 1, 1]
var hsvPattern2 = [1, 1, 1]

//Button to activate second pattern or not
var tooglePattern2 =0

// Toggle to activate or not a sub pattern
export function togglePattern2(c) {
  tooglePattern2 = c
}



//----------------------------------------------------------
export function beforeRender(delta) {
  
  t1 = time(.1)
}

//----------------------------------------------------------
export function render2D(index,x,y) {
  
  
  pattern1(index,x,y)
  //Apply pattern 1 to hsv
  h = hsvPattern1[0]
  s = hsvPattern1[1]
  v = hsvPattern1[2]


  pattern2(index,x,y)
  // Apply pattern 2 to hsv only if luminosity of pattern 2 is higher AND if we have activated it
  if (hsvPattern2[2] > v && tooglePattern2 == 1){
    h = hsvPattern2[0]
    s = hsvPattern2[1]
    v = hsvPattern2[2]
  }
  
  hsv(h, s, v)
}

//----------------------------------------------------------
// Calculation of a frame of pattern 1
export function pattern1(index,x,y) {
  
  hsvPattern1 = [y+t1, 1, 1]
  
}

// Calculation of a frame of pattern 2
export function pattern2(index,x,y) {
  
  hsvPattern2 = [1, 1, y]
  
}

I obviously did a mistake because it sends my FPS to 0.01 and almost froze my Pixelblaze (couldn’t change to another pattern). Didn’t expect it…
I’m kinda struggling with this. Can someone help me understand WHY this code kills the CPU ? I feel i don’t get the logic behind render2D…

Thank you !

Maybe it’s that in your patternX() functions you are making a new array every time!

When you write

foo = [1, 2, 3]

the [] allocates a new array. It does not overwrite the values in an existing array.

If you do

hsvPattern1[0] = y+t1
hsvPattern1[1] = 1
hsvPattern1[2] = 1

(and similarly in pattern2) Then you’ll be using the existing array instead of … allocating 2 new arrays for every pixel which would totally explain the CPU being very busy.

2 Likes

Many thanks, it was absolutely that !

I have revised my code and it works (animations are pretty basic but it’s more of a proof of concept).

  • Pattern 1 has vertical bars moving up and down and flashing with each “cue” impulse coming every 500ms (the idea is to link this to sensor board feedbacks later)
  • Pattern 2 is flashing random pixels and can be enabled/disabled with the toogle button. Since it has more light than pattern 1, if the same pixel is on in both patterns, the white flash will have priority (more brightness)

So i can basically activate or not patterns, which allows manual input, for example during a music track.

//Program to test the ability of having 2 or more separate animations in 1 pattern

//Define working variables specific to the 2D mapping
pixelColumns = 9
pixelHeight = pixelCount / pixelColumns

//Interval in ms between delayed executions (to avoid running it at each execution)
intervalCue =500

//Define arrays to render separately the patterns
var hsvPattern1 = [1, 1, 1]
var hsvPattern2 = [1, 1, 1]

//Button to activate second pattern or not
//var tooglePattern2 =0

// Toggle to activate or not a sub pattern
export function togglePattern2(c) {
  tooglePattern2 = c
}


//----------------------------------------------------------
export function beforeRender(delta) {
  
  //Running timer between 0 and 1
  t1 = time(.1)
  

  debounce = clamp(debounce + delta, 0, 6000)   // Prevents overflow when caclulating time elapsed since last execution of this code
  
  // If time is over the intervalCue defined by user, we reset the time counter and trigger the cue
  if (debounce > intervalCue) {
    debounce = 0                                // Reset time counter
    impulse=0
    randomValue=random(1)                       //Generates a random value to be used in the code if necessary
  }
  if (debounce < intervalCue) {                 //If we are in between the cues
    if (impulse>=0){
    impulse=2*wave(debounce/intervalCue)-0.5      //Starts at cue a wave that will go from 0, to
    }
  }
  
  
}

//----------------------------------------------------------
export function render2D(index,x,y) {
  
  
  pattern1(index,x,y)
  //Apply pattern 1 to hsv
  h = hsvPattern1[0]
  s = hsvPattern1[1]
  v = hsvPattern1[2]


  pattern2(index,x,y)
  // Apply pattern 2 to hsv only if luminosity of pattern 2 is higher AND if we have activated it
  if (hsvPattern2[2] > v && tooglePattern2 == 1){
    h = hsvPattern2[0]
    s = hsvPattern2[1]
    v = hsvPattern2[2]
  }
  
  hsv(h, s, v)
}

//----------------------------------------------------------
// Calculation of a frame of pattern 1 (impulse vertical bars at every cue)
export function pattern1(index,x,y) {
  
  hsvPattern1[0] = (t1+y)/5
  hsvPattern1[1] = 1
  pos=wave(t1)
  if(y>pos-0.3 && y<pos+0.3){
  hsvPattern1[2] = (impulse-10*abs(pos-y))/2
  }
  else{
    hsvPattern1[2] = 0
  }

  
}

// Calculation of a frame of pattern 2 (particules flash)
export function pattern2(index,x,y) {
  
  hsvPattern2[0] = 1
  hsvPattern2[1] = 0
  randomValue=ceil(random(1)*pixelCount)
  if(randomValue==index){
    hsvPattern2[2] =1
  }
  else{
  hsvPattern2[2] = 0
  }
  
}
1 Like

Glad I could help!

Here’s something that is a minor point with these simple render functions, but can have a big impact when combining more expensive functions:

You can get a bit more performance when only using pattern1 by not calculating pattern2 when you’re not gonna use it:

if(tooglePattern2 == 1) {
  pattern2(index,x,y)
  if(hsvPattern2[2] > v) {
    ...
  }
}

These micro-optimizations can add up to extra fps, so they are worth doing until they make your code unreadable. :relaxed:

3 Likes