p5.js Perlin噪声场拖尾效果异常:无法限制拖尾长度
解决粒子拖尾效果的问题
问题核心原因
你使用了WEBGL渲染模式,p5.js在WEBGL下的background()方法逻辑和2D模式不同,直接设置alpha值不会产生叠加半透明的效果。而移除background()后,画布不会被清空,粒子会持续绘制导致无限延伸。
解决方案
要实现渐变消失的拖尾效果,需要在每帧开头用低透明度的背景矩形覆盖画布,配合clear()方法重置WEBGL的渲染状态:
- 在
draw函数最开头添加清除和半透明背景绘制的代码 - 调整背景色的alpha值控制拖尾的淡出速度(值越小拖尾越长,越大消失越快)
修改后的完整代码
import React from 'react'; import { ReactP5Wrapper } from "@p5-wrapper/react"; import "../../App.css"; const Flow = () => { let w, h, nums; let zOff = 0; let scl = 0.005; let speed = 2; let particles = []; let cursor; const setup = (p5, canvasParentRef) => { w = p5.windowWidth; h = p5.windowHeight; nums = 2000; p5.frameRate(60); p5.createCanvas(w, h, p5.WEBGL).parent(canvasParentRef); for (let i = 0; i < nums; i++) { particles.push(p5.createVector(p5.random(w), p5.random(h))); } cursor = p5.createVector(p5.mouseX, p5.mouseY); } const draw = (p5) => { // --- 修改部分:添加半透明背景实现拖尾 --- const bgColor = getComputedStyle(document.documentElement).getPropertyValue('--main-bg-color').trim(); const bgColorValues = bgColor.match(/\d+/g); const r = parseInt(bgColorValues[0]); const g = parseInt(bgColorValues[1]); const b = parseInt(bgColorValues[2]); // WEBGL模式下先清除画布 p5.clear(); // 设置带alpha的背景色,alpha=20(可根据需求调整) p5.fill(r, g, b, 20); // 绘制覆盖整个画布的矩形,对应translate后的坐标 p5.rect(-w/2, -h/2, w, h); // --- 修改结束 --- p5.stroke(getComputedStyle(document.documentElement).getPropertyValue('--main-text-color')); p5.translate(-w / 2, -h / 2); p5.strokeWeight(3); cursor.set(p5.mouseX, p5.mouseY); for (let i = 0; i < nums; i++) { let p = particles[i]; let distance = p5.dist(p.x, p.y, cursor.x, cursor.y); if (distance < 50) { let dir = p5.createVector(p.x, p.y); dir.sub(cursor); dir.normalize(); let repulsion = 3; dir.mult(repulsion); p.add(dir); } let n = p5.noise(p.x * scl, p.y * scl, zOff); let angle = p5.TWO_PI * n; p.x += Math.cos(angle) * speed; p.y += Math.sin(angle) * speed; if (!onScreen(p, w, h)) { p.x = p5.random(p5.windowWidth); p.y = p5.random(p5.windowHeight); } p5.point(p.x, p.y); } zOff += 0.002; } const onScreen = (v, w, h) => { return v.x >= 0 && v.x <= w && v.y >= 0 && v.y <= h; } const windowResized = (p5) => { w = p5.windowWidth; h = p5.windowHeight; p5.resizeCanvas(w, h); }; return ( <ReactP5Wrapper sketch={p => { p.setup = () => setup(p); p.draw = () => draw(p); p.windowResized = () => windowResized(p); }} /> ) } export default Flow;
关键细节说明
p5.clear():WEBGL模式下必须调用,否则之前的渲染内容会残留导致异常- 背景alpha值:推荐在10-50之间调整,数值越小拖尾痕迹保留越久
- 矩形绘制:因为使用了
translate(-w/2, -h/2),所以矩形的起始坐标要设为(-w/2, -h/2)才能覆盖整个画布
内容的提问来源于stack exchange,提问作者Shivam Singh
相关产品推荐
相关产品推荐

