Successive draws of a transparent object don't end up fully opaque?

In this example, I draw a semi-transparent black rectangle to cover the canvas on every run-through of draw(), to gradually cover up and darken the results of the stuff I’d drawn in all previous draw() runs. Shouldn’t the previously-drawn elements (lines and ellipses) eventually turn fully black? Instead, they just turn a dark gray, and stay that way forever. I tried out different draw modes (P2D, P3D), no change. Searched, didn’t find an answer.

Example screenshot, code below:
p_walker_01

float x1, y1, x2, y2; 
int pad = 20;
int roam = 100;
int radiusE = 8;

void setup() {
  size(600, 400);
  background(0);
  frameRate(30);
  
  x1 = random(0 + pad, width - pad);
  y1 = random(0 + pad, height - pad);
}

void draw() {
  rectMode(CORNERS);
  fill(0, 5); // transparent black
  rect(-2, -2, width + 2, height + 2); // draw transparent rect
  
  x2 = random(x1 - roam, x1 + roam);
  y2 = random(y1 - roam, y1 + roam);
  x2 = constrain(x2, 0 + pad, width - pad);
  y2 = constrain(y2, 0 + pad, height - pad);
  
  color color1 = color(random(64, 128), random(64, 128), random(192, 255));
  
  fill(color1);
  strokeWeight(2);
  stroke(color1);
  
  // draw horiz line
  line(x1, y1, x2, y1);
  ellipse(x2, y1, radiusE, radiusE);
  
  // draw vertical line
  line(x2, y1, x2, y2);
  ellipse(x2, y2, radiusE, radiusE);
  
  x1 = x2;
  y1 = y2;
}

Works with white background. I had this many times before…
It seems to be an issue with black… For me it starts working at about fill(0,16);
But you cannot control how long it takes to fade.

The same goes for using a PGraphics…

Although I imagine you could use a number of PGraphics and put them on top of each other, drawing into them one after another each frame. When you reached the topmost PGraphics, clear the one in the back, push it up to the front and draw into it…

So you can clear the backlist one being 100% sure nothing is shown.

Seems completely overkill to me.
Maybe someone else knows better :slight_smile:

OR: Use two PGraphics.
Draw into the first. -> copy that into the second and use tint to fade it
First on top on the second.
Clear the first completely, draw into it, copy to second, fade.
maybe that works. As complicated…

1 Like

Yeah, maybe it’s a quirk of however the compositing happens, I dunno. I just tried setting the blend mode of the rect’s fill to something like blendMode(DARKEST), and that happens to fix the problem in this particular case, but it’s not what you’d always want.

I hadn’t heard of PGraphics or tint() before this, so I looked them up, spent time trying to rig up a shifting array of tinted frame buffers, trying different combinations of things, and … still didn’t work lol. The buffers composited weirdly too. Oh well, at least I learned some new stuff.

You can achieve it going to total black by using the blendMode() to SUBTRACT then filling with near black, then setting the blendMode() back to BLEND (or ADD, or whatever):

  blendMode(SUBTRACT);
  rectMode(CORNERS);
  fill(1); // almost black – no need for alpha
  rect(-2, -2, width + 2, height + 2); // draw transparent rect
  blendMode(BLEND);

Hope this helps.

2 Likes