You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在p5.js中使用形状作为其他形状的遮罩或裁剪路径?

在p5.js中用形状作为遮罩/裁剪路径的实现方法

嘿,这个问题我刚好踩过坑!p5.js的mask()方法确实只针对图片对象,没法直接给形状用,但咱们可以借助Canvas底层API或者图形缓冲区来实现,下面给你分享三种实用方案:

方法1:直接用Canvas上下文的clip()函数(最简便)

p5.js基于Canvas API,所以咱们可以直接调用底层的clip()方法,它会把当前绘制的形状作为裁剪路径,之后所有绘制内容都会被这个形状“框住”。

基础示例:用矩形裁剪随机圆形

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

function draw() {
  background(220);
  
  // 第一步:先画你要当遮罩的形状(这里是一个居中矩形)
  noFill(); // 遮罩形状不需要填充,只要路径就行
  rect(100, 100, 200, 200);
  
  // 调用clip(),开启裁剪模式
  drawingContext.clip();
  
  // 第二步:绘制需要被裁剪的内容(一堆随机红色圆形)
  fill(255, 0, 0);
  noStroke();
  for(let i = 0; i < 50; i++){
    circle(random(width), random(height), 30);
  }
}

进阶:控制裁剪范围(避免影响后续绘制)

如果之后还要画其他不受裁剪影响的内容,记得用save()和restore()保存/恢复绘图状态:

function draw() {
  background(220);
  
  // 保存当前绘图状态(包括裁剪、颜色等设置)
  drawingContext.save();
  
  // 定义遮罩形状并开启裁剪
  noFill();
  rect(100, 100, 200, 200);
  drawingContext.clip();
  
  // 绘制被裁剪的内容
  fill(255, 0, 0);
  noStroke();
  for(let i = 0; i < 50; i++){
    circle(random(width), random(height), 30);
  }
  
  // 恢复之前的绘图状态,关闭裁剪
  drawingContext.restore();
  
  // 这里画的内容就不会被裁剪啦(比如一个外圈大圆)
  stroke(0);
  noFill();
  circle(200, 200, 350);
}

方法2:用createGraphics()生成缓冲区做遮罩(最灵活)

这种方法适合复杂遮罩(比如不规则形状、渐变遮罩)或者需要重复使用遮罩的场景。核心思路是把形状画到一个图形缓冲区里,转成图片后用mask()方法(毕竟图片支持mask)。

示例:用自定义形状做遮罩

let maskBuffer; // 保存遮罩的图形缓冲区

function setup() {
  createCanvas(400, 400);
  
  // 创建和画布同尺寸的缓冲区
  maskBuffer = createGraphics(width, height);
  maskBuffer.background(0, 0); // 背景设为透明
  maskBuffer.fill(255); // 遮罩区域用白色填充(白色对应显示内容,透明对应隐藏)
  
  // 在缓冲区里画遮罩形状(比如一个五角星)
  maskBuffer.beginShape();
  maskBuffer.vertex(200, 80);
  maskBuffer.vertex(230, 180);
  maskBuffer.vertex(320, 180);
  maskBuffer.vertex(250, 240);
  maskBuffer.vertex(270, 340);
  maskBuffer.vertex(200, 280);
  maskBuffer.vertex(130, 340);
  maskBuffer.vertex(150, 240);
  maskBuffer.vertex(80, 180);
  maskBuffer.vertex(170, 180);
  maskBuffer.endShape(CLOSE);
}

function draw() {
  background(220);
  
  // 创建要被遮罩的内容(这里用另一个缓冲区画线条)
  let contentBuffer = createGraphics(width, height);
  contentBuffer.stroke(255, 0, 0);
  contentBuffer.strokeWeight(2);
  for(let i = 0; i < 100; i++){
    contentBuffer.line(random(width), random(height), random(width), random(height));
  }
  
  // 将缓冲区转成图片,应用遮罩
  let contentImg = contentBuffer.get();
  contentImg.mask(maskBuffer.get());
  
  // 把遮罩后的内容画到画布上
  image(contentImg, 0, 0);
}

小提示:如果要做半透明遮罩,可以把缓冲区里的填充色改成灰色(比如fill(127)),灰度值对应遮罩的透明度,越黑越透明。

方法3:用blendMode()快速实现(适合简单场景)

如果只是需要快速实现“只显示重叠区域”的效果,可以用混合模式,比如DST_IN,不过这个方法局限性较大,不如前两种灵活。

示例:用圆形遮罩渐变背景

function draw() {
  // 先画内容:一个从红到蓝的渐变背景
  for(let y = 0; y < height; y++){
    let r = map(y, 0, height, 255, 0);
    let b = map(y, 0, height, 0, 255);
    stroke(r, 0, b);
    line(0, y, width, y);
  }
  
  // 设置混合模式为DST_IN:只保留内容和遮罩重叠的部分
  blendMode(DST_IN);
  
  // 画遮罩形状(填充颜色不影响,只要有像素即可)
  fill(255);
  circle(200, 200, 200);
  
  // 恢复默认混合模式
  blendMode(BLEND);
}

注意:这个方法需要先画内容再画遮罩,而且混合模式的效果可能和预期有差异,比如遮罩半透明时会让内容也变透明。


内容的提问来源于stack exchange,提问作者amcc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:00:07