Alpha mask between objects

Hello guys! I hope you are safe :slight_smile:

I’m trying to hide a part of a shape I did using alpha mask but I have no idea how to achieve it.

My current result looks like that:

Screenshot 2020-07-06 at 12.27.48 AM

I want the black shape to act like an alpha mask and hide the white part behind it. I tried different solutions but didn’t manage to solve it :confused:

Here is my code:

// Responsive Canvas
function windowResized() {
    
    var w = windowWidth / 1.5;
    var h = w * 1.43;

    if (windowHeight < h) {
        h = windowHeight - (windowHeight / 10);
        w = h / 1.43;    
    }

    var cnv = createCanvas(w, h);
    cnv.style('display', 'block');
}

var arColors = ['magenta', '#23fafa', '#456783']; // library of colors

let amt, startColor, newColor; // variables for color fading


function setup() { 
    windowResized();
    rectMode(CENTER);
    startColor = color(random(arColors)); // set start color
    newColor = color(random(arColors)); // set new color
    amt = 0;
}
  
function draw() {
    var roundedCorner = width/30;
    var centerH = height / 2;
    var centerW = width / 2;
    var marginWidth = width / 27;

    background(0,0); // bacground transparent

    // sign fill
    fill(lerpColor(startColor, newColor, smoothstep(0.3,0.7,amt)));
    amt += 0.01;
    if(amt >= 1){
        amt = 0.0;
        startColor = newColor;
        newColor = color(random(arColors));
    }

    // sign base
    
    rect(centerW, centerH, width, height, roundedCorner); 
    noStroke();
   
    // white path
    var thickness = (height / 6.4) - marginWidth ;
    var strokePosition = marginWidth + thickness/2;

    strokeWeight(thickness);
    strokeCap(ROUND);
    strokeJoin(ROUND);
    stroke(255);
    noFill();

    beginShape();
    var n = 2.495;
    var dist = 1.495;
    vertex(width - strokePosition , strokePosition);
    vertex(strokePosition, strokePosition);
    vertex(strokePosition, strokePosition);
    vertex(strokePosition , strokePosition * n);
    vertex(strokePosition , strokePosition * n);
    vertex(width - strokePosition , strokePosition * n);
    vertex(width - strokePosition , strokePosition * n);
    var n = n + dist;
    vertex(width - strokePosition , strokePosition * n);
    vertex(width - strokePosition , strokePosition * n);
    vertex(strokePosition , strokePosition * n);
    vertex(strokePosition , strokePosition * n);
    n = n + dist;
    vertex(strokePosition , strokePosition * n);
    vertex(strokePosition , strokePosition * n);
    vertex(width - strokePosition  , strokePosition * n);
    vertex(width - strokePosition  , strokePosition * n);
    n = n + dist;
    vertex(width - strokePosition , strokePosition * n);
    vertex(width - strokePosition , strokePosition * n);
    vertex(strokePosition , strokePosition * n);
    vertex(strokePosition , strokePosition * n);
    n = n + dist;
    vertex(strokePosition , strokePosition * n);
    vertex(strokePosition , strokePosition * n);
    vertex(width - strokePosition , strokePosition * n);
    vertex(width - strokePosition , strokePosition * n);
    n = n + dist;
    vertex(width - strokePosition , strokePosition * n);
    vertex(width - strokePosition , strokePosition * n);
    vertex(strokePosition , strokePosition * n);
    endShape();
    noStroke();
    
  // mask
  fill(0);
  noStroke();
  beginShape(); 
  vertex(marginWidth / 2 , (height - marginWidth) / 1.155);
  vertex(marginWidth + width/12.75 , (height - marginWidth) / 1.155);
  vertex(marginWidth + width/12.75 , (height - marginWidth) / 1.155);
  vertex(marginWidth, strokePosition * n);
  vertex(marginWidth, strokePosition * n);
  vertex(marginWidth + width/12.75 , height - marginWidth);
  vertex(marginWidth + width/12.75 , height - marginWidth);
  vertex(marginWidth / 2 , height - marginWidth);
  vertex(marginWidth / 2 , height - marginWidth);
  vertex(marginWidth / 2 , (height - marginWidth) / 1.155);
  endShape();
}

function smoothstep(edge0, edge1, m) {
    m = constrain((m - edge0) / (edge1 - edge0), 0.0, 1.0); 
    return m * m * (3 - 2 * m);
}
1 Like

You can use a custom shape as a mask.

https://p5js.org/reference/#/p5/beginShape
https://p5js.org/reference/#/p5/createGraphics
https://p5js.org/reference/#/p5.Image/mask

Here is a quick example … after I threw this together I realized I did the opposite of what you are going for in terms of what you want masked out, but you can easily tweak it to your liking.

let msk,
  mskClone,
  mskGraphic;

function setup() {
  createCanvas(400, 200);
  
  msk = createGraphics(width, height);
  mskGraphic = createGraphics(width, height);
}

function draw() {
  background(13, 17, 21);
  mskGraphic.clear();
  msk.beginShape();
  msk.vertex(30, 10);
  msk.vertex(130, 10);
  msk.vertex(50,100);
  msk.vertex(130, height-10);
  msk.vertex(30, height-10);
  msk.endShape(CLOSE);
  
  //same shape as mask - used to draw the stroke for visual aid
  noFill();
  stroke('#fffafa');
  strokeWeight(2);
  beginShape();
  vertex(30, 10);
  vertex(130, 10);
  vertex(50,100);
  vertex(130, height-10);
  vertex(30, height-10);
  endShape(CLOSE);

  //graphic visual when not masked
  mskGraphic.ellipse(mouseX, mouseY, 25, 25);

  //mask
  (mskClone = msk.get()).mask(mskGraphic.get());
  image(mskClone, 0, 0);
}
2 Likes

Remember mask vertices must be called in the opposite direction to other vertices.

1 Like

see previous post

1 Like

Thank you guys for answering! You are the best :slight_smile:

ok guys I tried it but unfortunately it didn’t work :frowning: actually I think that something’s going wrong with the

(mskClone = msk.get()).mask(mskGraphic.get());
  image(mskClone, 0, 0);

Here’s my code:

// Responsive Canvas
function windowResized() {
  let w = windowWidth / 1.5;
  let h = w * 1.43;
  if (windowHeight < h) {
    h = windowHeight - (windowHeight / 10);
    w = h / 1.43;    
  }
  let cnv = createCanvas(w, h);
  cnv.style('display', 'block');
}

//variables

let arColors = ['magenta', '#23fafa', '#456783']; // library of colors
let amt, startColor, newColor; // variables for color fading

let msk,
  mskClone,
  mskGraphic;

function setup() { 
  windowResized();
  rectMode(CENTER);

  startColor = color(random(arColors)); // set start color
  newColor = color(random(arColors)); // set new color
  amt = 0;
  
  msk = createGraphics(width, height);
  mskGraphic = createGraphics(width, height);
}
  
function draw() {
  let roundedCorner = width/30;
  let centerH = height / 2;
  let centerW = width / 2;
  let marginWidth = width / 27;

  background(0,0); // background transparent

  // sign fill
  fill(lerpColor(startColor, newColor, smoothstep(0.3,0.7,amt)));
  amt += 0.01;
  if(amt >= 1){
    amt = 0.0;
    startColor = newColor;
    newColor = color(random(arColors));
  }

  // sign base
  rect(centerW, centerH, width, height, roundedCorner); 
  noStroke();

    
  let thickness = (height / 6.4) - marginWidth ;
  let strokePosition = marginWidth + thickness/2;
  
  // mask
  fill(0);
  strokeWeight(7);

  mskGraphic.clear();
  msk.beginShape();        
  msk.vertex(marginWidth / 2 , (height - marginWidth) / 1.155);
  msk.vertex(marginWidth + width/12.75 , (height - marginWidth) / 1.155);
  msk.vertex(marginWidth + width/12.75 , (height - marginWidth) / 1.155);
  msk.vertex(marginWidth, strokePosition * n);
  msk.vertex(marginWidth, strokePosition * n);
  msk.vertex(marginWidth + width/12.75 , height - marginWidth);
  msk.vertex(marginWidth + width/12.75 , height - marginWidth);
  msk.vertex(width - marginWidth , height - marginWidth);
  msk.vertex(width - marginWidth , marginWidth);
  msk.vertex(marginWidth , marginWidth);
  msk.endShape(CLOSE);

  //white path
  noFill();
  strokeWeight(thickness);
  strokeCap(ROUND);
  strokeJoin(ROUND);
  stroke(255);

  var n = 2.495, 
      dist = 1.495;
  
  mskGraphic.beginShape();
  mskGraphic.vertex(width - strokePosition , strokePosition);
  mskGraphic.vertex(strokePosition, strokePosition);
  mskGraphic.vertex(strokePosition, strokePosition);
  mskGraphic.vertex(strokePosition, strokePosition * n);
  mskGraphic.vertex(strokePosition, strokePosition * n);
  mskGraphic.vertex(width - strokePosition, strokePosition * n);
  mskGraphic.vertex(width - strokePosition, strokePosition * n);
  mskGraphic.vertex(width - strokePosition, strokePosition * (n =  n + dist));
  mskGraphic.vertex(width - strokePosition, strokePosition * n);
  mskGraphic.vertex(strokePosition, strokePosition * n);
  mskGraphic.vertex(strokePosition, strokePosition * n);
  mskGraphic.vertex(strokePosition, strokePosition * (n =  n + dist));
  mskGraphic.vertex(strokePosition, strokePosition * n);
  mskGraphic.vertex(width - strokePosition, strokePosition * n);
  mskGraphic.vertex(width - strokePosition, strokePosition * n);
  mskGraphic.vertex(width - strokePosition, strokePosition * (n =  n + dist));
  mskGraphic.vertex(width - strokePosition, strokePosition * n);
  mskGraphic.vertex(strokePosition, strokePosition * n);
  mskGraphic.vertex(strokePosition, strokePosition * n);
  mskGraphic.vertex(strokePosition, strokePosition * (n =  n + dist));
  mskGraphic.vertex(strokePosition, strokePosition * n);
  mskGraphic.vertex(width - strokePosition, strokePosition * n);
  mskGraphic.vertex(width - strokePosition, strokePosition * n);
  mskGraphic.vertex(width - strokePosition , strokePosition * (n =  n + dist));
  mskGraphic.vertex(width - strokePosition , strokePosition * n);
  mskGraphic.vertex(strokePosition , strokePosition * n);
  mskGraphic.endShape();
  stroke(0);
  strokeWeight(7);
  ellipse(20,20,20,20);
  noStroke();
  
  (mskClone = msk.get()).mask(mskGraphic.get());
  image(mskClone, 0, 0);

}

function smoothstep(edge0, edge1, m) {
  m = constrain((m - edge0) / (edge1 - edge0), 0.0, 1.0); 
  return m * m * (3 - 2 * m);
}



I think this is actually not true for masks. It is true for PShape inner contours created with beginContour

https://processing.org/reference/beginContour_.html

First draw vertices for the exterior shape in clockwise order, then for internal shapes, draw vertices counterclockwise.

PGraphics masks are rendered to pixel data, so the vertex order can be the same as any other drawing.

…oops! Sorry, I gave a Processing(Java) answer to a p5.js question. My mistake.