Using mask() to alpha blend from a buffer.

Hi all, I am trying to draw into a buffer that will be used to blend two images. Basically, using the buffer to erase the top image and reveal the bottom image. I got this to work very easily in Processing, but not in P5. I've read about this being an issue between p5.Image and p5.Renderer, but I am clueless as to how to get it to work. Any help to put me in the right direction is appreciated. I've tried to simplify it here:

var topL, bottomL; //pImages
var pg;

function preload() {
  topL = loadImage("assets/topImage.jpg");
  bottomL = loadImage("assets/bottomImage.jpg");
}

function setup() {
  createCanvas(750, 750);
  pg = createGraphics(750, 750);
  pg.pixelDensity(1);
}

function draw() {

  image(topL, 0, 0);
  bottomL.mask(pg._renderer);
  image(bottomL, 0, 0);

  image(pg, 0, 0);

  push();
  translate(mouseX, mouseY);
  rect(0, 0, 20, 20);
  pop();
}


function mouseMoved() {
  pg.push();
  pg.translate(mouseX, mouseY);
  pg.fill(255);
  pg.ellipse(0, 0, 20, 20);
  pg.pop();
}
Tagged:

Answers

  • @bwood

    I was looking at the reference of mask in the p5js reference website and I didn't find it. This is not the first time it happens to me and I find checking the example section has better implicit documentation than the actual reference site.

    Now, I couldn't figure out why you wanted to have a pg object. Also I am not familiar with your call in line 18 (I am also coming from Processing so little experience in JS)

    Here are three examples to consider:
    https://p5js.org/examples/image-transparency.html
    https://p5js.org/examples/image-alpha-mask.html

    In this last one, they use mask. I think when they are referring to mask, it seems they are looking at the blue channel as described in the processing website and shown in that example. I attempted to make it work but not success.

    A third approach is using blend(), http://p5js.sketchpad.cc/sp/pad/view/D7rVFoVTf0/latest:

    Use two images of the same size and adjust the size of the sketch as well.

    Kf

    var topL, bottomL; //pImages
    var pg;
     
    function preload() { //960 x 720
      bottomL = loadImage("/static/uploaded_resources/p.23038/15873268_10154911479359314_6278188222784055203_n.jpg");;//loadImage("assets/topImage.jpg");
      topL = loadImage("/static/uploaded_resources/p.23038/15871637_10154911473754314_6387307213869868101_n.jpg");  
    }
     
    function setup() {
      createCanvas(960, 720);
      imageMode(CENTER);
      bottomL.mask(topL);
      
    }
     
    function draw() {
        background(0);
     
      image(topL, width/2,height/2);
      blend(bottomL,0,0,width/2,height,width/2,0,width/2,height,LIGHTEST)
     
      rect(mouseX,mouseY, 20, 20);
    }
    
  • edited April 2017

    I was looking at the reference of mask() in the p5js reference website and I didn't find it.

    Actually, if you search for it within Processing Java's API root page you won't find it either: =P~
    https://Processing.org/reference/

    Why? B/c it's a method from class PImage: ;)
    https://Processing.org/reference/PImage.html
    https://Processing.org/reference/PImage_mask_.html

    p5.js' reference just follows that lead as well, but for class p5.Image instead: :>
    https://p5js.org/reference/#/p5.Image
    https://p5js.org/reference/#/p5.Image/mask

  • Thanks for taking a look at this. I've read through your suggestions and think it might be best for me to share the Processing code that works. Hopefully that will show how I am drawing to a buffer that in turn does the masking.

    GoToLoop, I've been trying to make your example work for what I am doing, but it's still missing the offscreen buffer, which is crucial. Make sense? or am I missing something?

    PImage top, bottom;
    PGraphics pg;
    
    void setup() {
      size(750, 750, P2D);
    
      imageMode(CENTER);
      top = loadImage("eraseTop.jpg");
      bottom = loadImage("eraseBot.jpg");
    
      pg = createGraphics(width, height, P2D);
      pg.beginDraw();
      pg.background(0);
      pg.endDraw();
    }
    
    void draw() {
      image(top, width/2, height/2);
      bottom.mask(pg);
      image(bottom, width/2, height/2);
    }
    
    void mouseMoved() {
      pg.noStroke();
      pg.fill(255);
      pg.beginDraw();
      pg.pushMatrix();
      pg.translate(mouseX, mouseY);
      pg.ellipse(0, 0, 20, 20);
      pg.popMatrix();
      pg.endDraw();
    }
    
  • Why do you need the second buffer? You are referring to the pg object?

    Couldn't you just do ellipse(mouseX,mouseY,20,20); What is your thought of having this second buffer? I think GoToLoop's examples fit your case.

    @GoToLoop Thanks for clarifying. as you see, I haven't explore all the P5js reference as much as the Processing one.

    Kf

  • Here's the "look" I am going for: http://vodstrup.com/eraserClean/ I want the "bottom" image to appear in the area being painted (painted black in this example).

    I think I've gotten close to what I want using get(), but I keep getting a "Cannot read property 'width' of undefined" error, which may have something to do with the async/defer that @GoToLoop talks about... still testing that.

Sign In or Register to comment.