Slowly fading background in p5.js

Hey!

I want to make a slowly fading background in p5.js.

I tried using a new createGraphics layer, which works well in the sense that i does not leave ugly trails, but it fades too fast for what I want to achieve. Any ideas?

var pg;
function setup() {
  createCanvas(100, 100);
  pg = createGraphics(100, 100);
}
function draw() {
  pg.fill(255,1);
  pg.noStroke();
  pg.rect(0,0,width, height);
  image(pg, 0, 0);
  noStroke();
  fill(0);
  ellipse(mouseX, mouseY, 5, 5);
}

I would like to avoid having to fade the color of the objects I draw on screen themselves (eg. calling background(255) in draw and adjusting the fill of the trails), and just find a solution using a fading background/graphics layer/etc.

Answers

  • The approach in those links is to map() -- the input is the current clock time millis() compared to a start/end time; the output is the desired alpha range. At any clock time your background will be faded the right amount.

    If you have any questions about how to apply them to your situation, give more information on what you are trying to do -- fade many times, or only once at the start? Fade in and out, or just in? Etc....

  • Thanks a lot for the links.

    @jeremydouglass: I want to fade all the time so whatever I draw on screen slowly fades away, and I am able to control the fading speed.

  • edited May 2017

    You can condition your fading statements to current frameCount: :-B
    https://p5js.org/reference/#/p5/frameCount

    And use the % modulo (remainder) operator in order to skip a certain # of frames: :>
    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Remainder_()

    Let's say you wish to only fade each 6th frame and skip the rest. Which corresponds to 60/6 = 10 FPS:

    const SKIP = 6; // Fading at each 6th frameCount (10 FPS)
    
    function draw() {
      // Invoke fade() only when frameCount is divisible by SKIP:
      frameCount % SKIP || fade();
    
      // Your other drawing stuff below:
    }
    
    function fade() {
      // Your fading code below:
    }
    

    An even easier option is just lower the FPS via frameRate(): :P
    https://p5js.org/reference/#/p5/frameRate

    But then the non-fading code gets slower as well! =P~

  • You can also use @GoToLoop's approach and scale the amount of fade to the elapsed time (currentMillis - lastMillis). This would make your code semi-independent of frameRate.

    Keep in mind that the technique of repeated applications of small alpha washes will probably not converge at 0 or 255 -- they will fade to something like 10 or 245.

  • Hmm, I have tried but using tint() and createGraphics but am not getting exactly what I want to achieve.

    So far I have this, where I can control the speed via frameCount & modulo, but the fading is not very smooth.

    var pg;
    function setup() {
      createCanvas(600,600);
      pg = createGraphics(600, 600);
    }
    function draw() {
      pg.fill(255,255,255,1);
      pg.noStroke();
      pg.rect(0,0,width, height);
      if (frameCount % 10 == 0) image(pg, 0, 0);
      noStroke();
      fill(0);
      ellipse(mouseX, mouseY, 50, 50);
    }
    
  • Fading background color: http://p5js.sketchpad.cc/asuP2EIx9S

    That is what I thought for fading. However, your examples is about fading previous shapes, like vanishing drawing objects based on their history.

    If I remove your conditional, I get smooth fading. You mean the fading is happening too fast? You want to make it longer or have more control on the time it takes to fade?

    Kf

  • edited May 2017

    If I remove your conditional, I get smooth fading. You mean the fading is happening too fast? You want to make it longer or have more control on the time it takes to fade?>

    Yes, it is happening too fast currently. And want it to take longer, but still be smooth.

    However, your examples is about fading previous shapes, like vanishing drawing objects based on their history.

    Yeah, but I am not interested storing a lot of information about the objects history. I kinda just want the background to fade over them and make them disappear, if that it is possible?

  • Not sure if you could have the control you desire using tint or alpha values. You are limited to the range of 255. In your example above, you could just add the ellipses to an array list and then paint them in order with dynamically changing their alpha value based on position in the list. You can make the list as big as you want to give you the effect you want.

    I tried colorMode(RGB, 255, 255, 255, 1024); hoping this could work... no difference (one needs to dig under the hood...). I thought about reducing the frameRate() as a test.... and it is similar to having the modulus conditional above... jumpy/no-smooth drawing.

    One question... if you skip frames then you might be missing previous steps between two positions. Is that a good approach or will that not satify your smooth concept?

    Kf

  • The example I provided with the ellipses is just an example, and my question is a bit more general: Is there really no way to draw whatever you want on the canvas and fade it out over a duration you decide yourself, without storing all information about the objects you draw?

  • edited May 2017

    Here is an example in Processing(Java) of the approach I described above -- use a timer to check how much alpha shifting should be done each frame, then alpha shift the PGraphics pixels where past drawing is accumulating.

    Adjust STEPTIME and STEPALPHA to control how often the alpha shifts, and by how much. The effect is a bit like a Buddha Board.

    PGraphics pg;
    float STEPTIME = 10;
    int STEPALPHA = 1;
    int stepAmt, stepTimeLast;
    
    void setup() {
      size(100, 100);
      pg = createGraphics(100, 100);
      pg.beginDraw();
      pg.stroke(0);
      pg.strokeWeight(5);
      pg.fill(0);
      pg.endDraw();
    }
    
    void draw() {
      background(255);
      // draw simple brush strokes
      pg.beginDraw();
      pg.line(mouseX, mouseY, pmouseX, pmouseY);
      pg.endDraw();
      image(pg, 0, 0);
      // fade the brush surface
      fadeTimer();
    }
    
    void fadeTimer() {
      // has enough time passed to increment the fade?
      stepAmt = (int)((millis()-stepTimeLast)/STEPTIME);
      // fade that many steps
      if (stepAmt > 0) {
        fade(pg, stepAmt);
        stepTimeLast = millis();
      }
    }
    
    void fade(PGraphics pg, int amt) {
      pg.beginDraw();
      pg.loadPixels();
      // shift pixel alpha up
      for (int i = 0; i < width*height; i++) {
        if (((pg.pixels[i] >> 24) & 0xFF) >= 0+amt ) {
          pg.pixels[i] = (pg.pixels[i] - (amt<<24));
        }
      }
      pg.updatePixels();
      pg.endDraw();
    }
    
  • Yes, I don't think PGraphics has access to loadPixels... I tried to come up with the p5.js version but I couldn't get it to work... A quick glance online didn't provide an obvious answer. Probably one needs to work on image objects instead...

    Maybe somebody can spot what I was doing wrong in my attempt: http://p5js.sketchpad.cc/sp/pad/view/4lAKuEcTH2/latest

    Kf

  • Thanks for the attempt @kfrajer

    @jeremydouglass how would you make that work in p5.js?

  • edited May 2017

    @Andreas_Ref -- I'm not really a p5.js expert. If fade isn't working in p5.js because you can't pixel-shift the p5.Renderer, perhaps try this instead:

    1. call fadeTimer()
    2. if true, call tint(255,1) and draw a rect (instead of fade) https://p5js.org/reference/#/p5/tint

    It has the color convergence problem, but should otherwise work the same.

  • @kfrajer -- not sure, but in the p5.js for some reason stepAmt might always evaluate to 0, so fade is never called...?

    stepAmt = (int)((millis()-stepTimeLast)/STEPTIME);
    
Sign In or Register to comment.