Pulsating PGraphics used as mask only updated in one direction

Hello,

I have a PGraphics with random rectangles appearing and disappearing progressively using changing value of fill(). It functions as expected.

However, when used as a mask, the rectangles appear progressively but don’t disappear afterwards.

What’s wrong?

Thank you in advance.


int bright = 0;
int brightDiff = 10;

PImage underlyingImg;

PGraphics maskImg;

int posX, posY, sizeX, sizeY, minX, maxX, minY, maxY;

void setup() {
  size(800, 600, P2D);
  noStroke();
  smooth(1);
  frameRate(30);
  fill(255); 
  underlyingImg = createImage(1620, 1080, RGB);
  maskImg = createGraphics(underlyingImg.width,underlyingImg.height,P2D);
  fillImage();
  minX = underlyingImg.width/40;
  maxX = underlyingImg.width/10;
  minY = underlyingImg.height/40;
  maxY = underlyingImg.height/10;
  sizeX = int(random(maxX-minX))+minX;
  sizeY = int(random(maxY-minY))+minY;
  posX = int(random(underlyingImg.width-sizeX/2)+sizeX/2);
  posY = int(random(underlyingImg.height-sizeY/2)/sizeY/2); 
}

void draw() {
  maskImg.beginDraw();
  maskImg.background(0);  
  maskImg.fill(bright);
  maskImg.rect(posX, posY, sizeX, sizeY);
  bright += brightDiff;
  if (bright >= 255) brightDiff = -brightDiff;    
  if (bright <= 0) {
    brightDiff = int(random(29))+1;
    sizeX = int(random(maxX-minX))+minX;
    sizeY = int(random(maxY-minY))+minY;
    posX = int(random(underlyingImg.width-sizeX/2)+sizeX/2);
    posY = int(random(underlyingImg.height-sizeY/2)+sizeY/2);     
  }
  bright = constrain(bright, 0, 255);
  underlyingImg.mask(maskImg);
  maskImg.updatePixels();
  //image(maskImg, 0, 0, width, height);         // uncomment this line to see the Pgraphics pulsating...
  image(underlyingImg, 0, 0, width, height);     // ...and comment this one
  maskImg.endDraw();
}

void fillImage() {
  for (int i = 0; i < underlyingImg.width; i++) {
    for (int j = 0; j < underlyingImg.height; j++) {
      int pos = j * width + i;
      underlyingImg.pixels[pos] = color(random(255));
    }
  }
}

Hi @amundsen,

you almost had it… :slight_smile:
Cheers
— mnse

PS: But think a bit about your code structuring …

int bright = 0;
int brightDiff = 10;

PImage underlyingImg;

PGraphics maskImg;

int posX, posY, sizeX, sizeY, minX, maxX, minY, maxY;

void setup() {
  size(800, 600, P2D);
  noStroke();
  smooth(1);
  frameRate(30);
  fill(255); 
  underlyingImg = createImage(800, 600, RGB);
  maskImg = createGraphics(underlyingImg.width,underlyingImg.height,P2D);
  fillImage();
  minX = underlyingImg.width/40;
  maxX = underlyingImg.width/10;
  minY = underlyingImg.height/40;
  maxY = underlyingImg.height/10;
  sizeX = int(random(maxX-minX))+minX;
  sizeY = int(random(maxY-minY))+minY;
  posX = int(random(underlyingImg.width-sizeX/2)+sizeX/2);
  posY = int(random(underlyingImg.height-sizeY/2)/sizeY/2); 
}

void draw() {
  background(0);
  maskImg.beginDraw();
  maskImg.background(0);  
  maskImg.fill(bright);
  maskImg.rect(posX, posY, sizeX, sizeY);
  bright += brightDiff;
  if (bright >= 255) brightDiff = -brightDiff;    
  if (bright <= 0) {
    brightDiff = int(random(29))+1;
    sizeX = int(random(maxX-minX))+minX;
    sizeY = int(random(maxY-minY))+minY;
    posX = int(random(underlyingImg.width-sizeX/2)+sizeX/2);
    posY = int(random(underlyingImg.height-sizeY/2)+sizeY/2);     
  }
  bright = constrain(bright, 0, 255);
  underlyingImg.mask(maskImg);
  maskImg.endDraw();
  image(underlyingImg, 0, 0, width, height);     // ...and comment this one
}

void fillImage() {
  for (int i = 0; i < underlyingImg.width; i++) {
    for (int j = 0; j < underlyingImg.height; j++) {
      int pos = j * width + i;
      underlyingImg.pixels[pos] = color(random(255));
    }
  }
  underlyingImg.updatePixels();
}

Thank you @mnse!

Can you elaborate? Please note that the fillImage() function is there to replace an image file I have on my drive.

By the way, for those who haven’t seen it, the issue was caused by the missing background() in draw()! Weird.

1 Like

Hi,

void draw() {
  background(0);

  // You can put the whole block outside the drawing stuff below
  // So it is structured
  // preparation stuff
  // drawing stuff

  // You can combine these two statements
  bright = constrain(bright+brightDiff, 0, 255);

  if (bright >= 255) 
      brightDiff = -brightDiff;    
  else if (bright <= 0) { // use else if no need to check both as it is the opposite
    brightDiff = int(random(29))+1;
    sizeX = int(random(maxX-minX))+minX;
    sizeY = int(random(maxY-minY))+minY;
    posX = int(random(underlyingImg.width-sizeX/2)+sizeX/2);
    posY = int(random(underlyingImg.height-sizeY/2)+sizeY/2);     
  }
  
  // Afterwards do the drawing stuff
  maskImg.beginDraw();
  maskImg.background(0);  
  maskImg.fill(bright);
  maskImg.rect(posX, posY, sizeX, sizeY);
  maskImg.endDraw();
  // Put this outside from begin/enddraw as it not belongs to it
  underlyingImg.mask(maskImg);
  image(underlyingImg, 0, 0, width, height);     // ...and comment this one
}

// Additionally you can think about the bright to be calculated maybe on a sin curve instead of -/+brightdiff
// You can map the sin() from 0-1 by doing sin*0.5+0.5 and on the flip point (ie. 0) you can trigger new pos/size etc.
// You can even go further to make your rects a class which objects handles their on brightness an gives a elegant way to have multiple cutouts with different fade in/outs :)

// but this is only a side note :)

Cheers
— mnse

1 Like

“Expected” is a better way to describe it…

References:
https://processing.org/reference/setup_.html
https://processing.org/reference/draw_.html
https://processing.org/reference/background_.html

Once you understand the flow of an active sketch it all makes sense.

Have fun!

:)

1 Like