P5js blendmode is so strange

Hello guys,I’m trying to make an animation of rains flowing down a window,
but there’s still some color left that doesn’t blend with the background.
So I look up the blendMode() reference, and find a fomula for BLEND C = Afactor +B. This is so different from what I used to know. I think the typical one should be "C = Afactor + B*(1-factor)" . Is there any way I can do to solve this issue? Please give me some instructions, I’m a beginner to p5 and javascript. :grinning:`

function setup() {
  createCanvas(400, 400);
  background(20, 255);
  rain1 = new Rain(100, 100);
class Rain {
  constructor(x, y) {
    this.x = x;
    this.y = y;
    this.radius = 20;
    this.age = 0;
  show() {
    circle(this.x, this.y, this.radius);
  move() {
    this.y += 1;
    this.x += noise(this.y) - 0.5;
    this.radius -= 0.01;
  // detect() {
  //   loadPixels();
  //   for (var i = -0.785; i <= 0.785; i += 0.1) {
  //     if (get(x, y + radius * cos(i)) != color(20)) {
  //       return true;
  //     }
  //   }
  // }
rains = [];

function draw() {
  background(20, 5);
  if (random(0, 1) < 0.01) {
    rains.push(new Rain(random(0, 400), random(0, 400)));
  for (var i = 0; i < rains.length; i++) {
    if (rains[i].age > 1000) {
      rains.splice(i, 1);
  // rain1.show();
  // rain1.move();

I don’t think this is a facet of p5.js per se. BLEND is the default blend mode and it maps directly to a CanvasRenderingContext2D.globalCompositeOperation value of source-over. I believe that the residual color that never quite goes away has to do with the math that is used to combine colors with alpha values. If you want to avoid the residual streaks, while maintaining the same rate of fade you could double the alpha value for your call to background() but only call it every other frame.

I went down the rabbit hole.

As KumuPaul says P5.js simply sets the compostion operation of an HTML 5 canvas (See [1]).
The specification of the blending operations are given in [2].
In the P5 source code BLEND is defined in [3] as “source-over”.
The souce-over formulas are:

Fa = 1; Fb = 1 – αs
co = αs x Cs + αb x Cb x (1 – αs)
αo = αs + αb x (1 – αs)

See [2] for an explanation.

And as yang mentioned the middle formula shows not B but B*(1-factor).
So I think the formula in the P. and P5js references is a bit simplistic.
Maybe on purpose - but confusing nevertheless.

FWIW the Source for P. contains a Java implementation of the blend operations, see [4].
The blend_blend function implements the default source over operation.

[1] p5.js/p5.Renderer2D.js at 374acfb44588bfd565c54d61264df197d798d121 · processing/p5.js · GitHub

[2] Compositing and Blending Level 1

[3] p5.js/constants.js at 374acfb44588bfd565c54d61264df197d798d121 · processing/p5.js · GitHub


1 Like

Thank you so much for your detailed reply. As KumuPaul suggested I doubled the alpha value, but the problem even become worse. Perhaps I’ll find a way to bypass the alpha and blendmode. :sweat_smile:

Why don’t you just use lerpColor?


Use the age variable as the map and go from filling the rain drop color to fading into the background color. The blend mode is not going to do what you want, it is not like photoshop.

Thanks for your advice! Do you mean I should save the trail of a raindrop in an array, and change the color every frame until they fade into background? Or I could change every pixel that aren’t background but the computation seems a bit heavy :crazy_face:. I have no idea why p5 draws the background so fast ,but thank you anyway.

Yes you could use an array and push the circles / rain drop object to it. Without knowing your project it’s hard to say what’s best, but p5 can handle arrays of objects pretty well depending on what else is going on in your program. The blend mode itself is going to be computation heavy. You could also try to make the rain not a trail, but use a line or something and have them overlay everything like a particle system, but I don’t know what you are trying to accomplish. Just a suggestion.