Help making a painting effect without refreshing background

Hi there! Full disclosure, this is a part of a larger assignment for my beginner’s processing class, so if you wouldn’t mind keeping any advice fairly simple I’d really appreciate that!
Basically, I’m trying to mimic what drawing on a frosted-over window looks like (ref. image included for anyone in a warmer climate), with my problem being the snow animation in the background - it means I can’t refresh my background image, which is all I know how to do to create a paint/erase effect. Both my professor and I have tried everything we can think of, and at this point, I’d like to even know if it’s possible!

// Snow class modified from Ziv Schnieder : https://openprocessing.org/sketch/115994/

Snow[] flakes = new Snow[300];

void setup() {
  size (640, 720);
  // background(0);
  for (int i = 0; i<flakes.length; i++) {
    flakes[i] = new Snow(random(2, 10));
    flakes[i].spreadY(i);
  }
}
void draw() {

  // BACKGROUND -------------------------------------
  push();
  fill(0, 0, 0, 200);
  rect(0, 0, 640, 720);
  pop();

  // SNOWFLAKES ------------------------------------
  for (int i = 0; i < flakes.length; i++) {
    flakes[i] .display();
  }

  // WINDOW "GLASS" --------------------------------
  push();
  fill(255, 80);
  rect(0, 0, 640, 720);
  pop();

  // ERASER ----------------------------------------
  if (mousePressed && (mouseButton == LEFT))
  {
    push();
    stroke(0, 90);
    strokeWeight(20);
    line(mouseX, mouseY, pmouseX, pmouseY);
    pop();
  }

  // WINDOW FRAME ----------------------------------
  push();
  fill(0, 0, 255);
  rect(0, 0, 50, 720);
  rect(590, 0, 50, 720);
  rect(0, 0, 640, 50);
  rect(0, 670, 640, 50);
  rect(300, 0, 20, 720);
  rect(0, 340, 640, 20);
  pop();
}

/*void mouseDragged()
 {
 if (mousePressed && (mouseButton == LEFT))
 {
 push();
 stroke(0,90);
 strokeWeight(20);
 line(mouseX, mouseY, pmouseX, pmouseY);
 pop();
 }
 }*/

// MISC ------------------------------------------------------------------------------------

class Snow {
  float x;
  float y;
  float alpha;
  float diameter;
  float speed = random(.1, .9);
  float descentX;

  Snow (float tempD) {
    x = random(-50, width+50);
    y = random(0, 40);
    diameter = tempD;
  }

  void spreadY(int i) {
    y = y - i*3;
  }

  void display() {
    alpha = map(y, 0, height, 255, -50);
    noStroke();
    fill(255, alpha);
    ellipse(x, y, diameter, diameter);
    y = y + speed;
    x = x + descentX;

    //checking the boundary
    if (y > height) {
      y = -diameter;
    }
    if (x < 0-50) {
      x = width+diameter;
    } else if (x > width+50) {
      x = 0-diameter;
    }
  }
}

Hi @moffmix,

Sorry, I can’t write an example now as I’m not on my box.

What you need is to introduce a layered approach and join them to display…

  • Paint background
  • Paint snow
  • Paint frost with masked scratch

Cheers
— mnse

There was someone with a similar issue in How to erase object's trail without 'background' in function draw.

The proposed solution in that post is for P5 (so not Processing), but a similar result can be obtained with PGraphics

2 Likes

I understand what you are trying to do. But I think the current approach of updating the background snow is going to be complicated.
The approach I would explore is by putting your glass layer into the PGraphics class.

Snow[] flakes = new Snow[300];
PGraphics glass;

void setup() {
  size (640, 720);
  // background(0);
  for (int i = 0; i<flakes.length; i++) {
    flakes[i] = new Snow(random(2, 10));
    flakes[i].spreadY(i);
  }
  glass = createGraphics(640, 720);
}
void draw() {

  // BACKGROUND -------------------------------------
  pushMatrix();
  fill(0, 0, 0, 200);
  rect(0, 0, 640, 720);
  popMatrix();

  // SNOWFLAKES ------------------------------------
  for (int i = 0; i < flakes.length; i++) {
    flakes[i] .display();
  }
  
  // WINDOW "GLASS" --------------------------------
//you will want to remove the gray fill() pixels so you have transparency in the areas that the mouse moves across. ***see further clarification below
  
  glass.beginDraw();
  glass.fill(255, 200);
  glass.rect(0, 0, 640, 720);
  glass.endDraw();
  image(glass, 0, 0);

This as outlined above is a very basic breakdown (NOT absolute amounts for the variables).
And since you would need to remove pixels where the mouse passes over, the use of an array list and the set(), get(), and delete() functions will come into play.
IMHO, I think it would be easier (more direct) to focus on the glass layer as that is the layer that is changing. Instead of creating an illusion of it changing…

Hopefully this helps,
:nerd_face:

3 Likes

Hello @moffmix,

It is possible!

Example of masking:

// Masking
// v1.0.0
// GLV 2022-11-13

PGraphics msk;
PImage img;

void setup()
  {
  size(500, 500);
  
  background(255, 0, 0); // Just to see if it bleeds through for testing.
  
  msk = createGraphics(500, 500);
  //img = loadImage("https://upload.wikimedia.org/wikipedia/commons/thumb/b/b1/Colouring_pencils.jpg/800px-Colouring_pencils.jpg");
  img = loadImage("https://c-fa.cdn.smule.com/rs-s79/arr/2f/9c/6081a9b7-fee9-4cd1-bdfa-4c03432bbbd3.jpg");
  img.resize(width, height);
  
  // This is the setup for the PGraphic to create the mask!
  msk.beginDraw();
  // bacground has an alpha in a PGraphic. :)
  msk.background(0, 0, 128);           // To emphasize the blue for masking!
  msk.endDraw();
  }

int rs;

void draw() 
  {   
  image(img, 0, 0);
  
  // Some snow here... too early in the season for me!    
    
  // This is the draw() for the PGraphic to create the mask!  
  msk.beginDraw();
  msk.fill(0, 0, 255);                // To emphasize the blue for masking!
  msk.noStroke();
  msk.circle(width/2, height/2, 400); //Consider using mouse here!
  msk.endDraw();
  
  // Masking part
  PImage img = g.copy();              // Make a copy of the current graphics buffer
  img.mask(msk);
  background(128);
  //g.clear();                        // See reference!
  image(img, 0, 0);                   // Show image with mask applied. 
  }

Experiment with this… it worked with your snow as well.

Image source:
https://quoters.info/quote/37894

:)

5 Likes

Hey, everyone! Thank you so much for the help! I’ve gotten it to work well enough for my project, I think, but I’ll absolutely keep trying to get it perfect!

1 Like