p5js 剪贴蒙版等效?

p5js clipping mask equivalent?

我有一个超级简单的脚本,可以创建一个带有交替“切片”颜色的圆圈

let slices = 12;


function setup() {
  createCanvas(400, 400);
  noStroke();
}

function draw() {
  background(220);
  translate(width/2, height/2);
  
  let inc = TWO_PI/slices;
  let c = 0
  for (let i = 0; i < TWO_PI+inc; i+=inc) {
    if (c % 2 == 0) {
      fill('white')
    } else {
      fill('black')
    }
    arc(0, 0, width/2, width/2, i, i+inc);
    c++
  } 
}

我怎样才能用正方形(或三角形、六边形等)做同样的事情?也就是说,我想要交替的切片颜色,但封装在正方形而不是圆形中。我不确定如何执行此操作,因为我使用 arc() 创建切片。有什么方法可以制作面具之类的吗?或者有更简单的方法解决我的问题吗?

您可以使用 p5.Image 上的 mask() 功能将您的图案应用到任意形状。或者,您可以找到构成每个饼图切片的每条射线与形状周长的交点,并使用交点和形状的定义来构造一个适合指定形状的饼图切片,但这会很多比较复杂。

举个例子。单击可更改形状。

let slices = 12;
let pattern;
let masked;
let density;

const MaskTypes = ['circle', 'square', 'triangle', 'text'];
let ix = 0;

function setup() {
  createCanvas(400, 400);
  density = pixelDensity();
  
  let g = createGraphics(width, height);
  g.noStroke();
  g.translate(width / 2, height / 2);
  
  const inc = TWO_PI / slices;
  // fill the screen
  const d = sqrt(width * width + height * height);
  let c = 0;
  for (let i = 0; i < TWO_PI + inc; i += inc) {
    if (c % 2 == 0) {
      g.fill('white');
    } else {
      g.fill('black');
    }
    g.arc(0, 0, d, d, i, i + inc);
    c++;
  }
  
  pattern = createImage(width * density, height * density);
  pattern.copy(g, 0, 0, width, height, 0, 0, width * density, height * density);
  
  updateMask();
}

function mouseClicked() {
  ix = (ix + 1) % MaskTypes.length;
  updateMask();
}

function updateMask() {
  let m = makeMask(MaskTypes[ix]);
  
  masked = createImage(width * density, height * density);
  masked.copy(pattern, 0, 0, width * density, height * density, 0, 0, width * density, height * density);
  masked.mask(m);
}

function makeMask(type) {
  let g = createGraphics(width, height);
  g.noStroke();
  g.fill(0);
  g.translate(width / 2, height / 2);
  
  switch (type) {
    case 'circle':
      g.circle(0, 0, width / 2);
      break;
    case 'square':
      g.rect(-width / 4, -height / 4, width / 2, height / 2);
      break;
    case 'triangle':
      g.triangle(-width / 4, height / 4, 0, -height / 4, width / 4, height / 4);
      break;
    case 'text':
      g.textAlign(CENTER, CENTER);
      g.textSize(96);
      g.text("Hello!", 0, 0);
      break;
  }
  
  let mask = createImage(width * density, height * density);
  mask.copy(g, 0, 0, width, height, 0, 0, width * density, height * density);
  
  return mask;
}

function draw() {
  background(220);
  
  image(masked, 0, 0, width, height)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>