如何用p5.js实现连续彩色艺术化Perlin流场效果
实现彩色独立Perlin流场效果的优化方案
我看了你的代码,核心问题是所有颜色的流场用了完全相同的Perlin噪声计算,导致三种颜色的粒子轨迹完全重叠,看不出独立的流场效果。另外还有一些性能和视觉细节可以优化,下面是修改后的完整代码,附带详细说明:
核心问题分析
- 流场同质化:
angleMaroon、angleBlue、angleYellow都用了相同的noise(xoff, yoff, zoff),所以三个流场的方向完全一致,粒子轨迹重叠。 - 粒子数量过载:每种颜色1000个粒子,总共4000个,会导致帧率下降,流畅度不足。
- 视觉缺少动态关联:EEG数据(
maroon_data等)没有和流场的视觉属性(透明度、流速)绑定,无法体现数据变化的效果。 - 背景刷新过于彻底:每次
draw()都画纯白背景,轨迹没有渐变拖尾,艺术感不足。
修改后的完整代码
index.html(无需修改)
<html> <head> <script language="javascript" type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.min.js"></script> <script language="javascript" src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/addons/p5.dom.min.js"></script> <script language="javascript" src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/addons/p5.sound.min.js"></script> <script language="javascript" type="text/javascript" src="sketch.js"></script> <script language="javascript" type="text/javascript" src="particle.js"></script> </head> <body> </body> </html>
particle.js(优化透明度动态设置)
function Particle() { this.pos = createVector(random(width), random(height)); this.vel = createVector(0, 0); this.acc = createVector(0, 0); this.maxspeed = 3; // 降低最大速度,让轨迹更平滑 this.prevPos = this.pos.copy(); // 新增:动态设置透明度的方法 this.setAlpha = function(alphaVal) { this.alphaPower = constrain(alphaVal, 5, 30); // 限制透明度范围,避免过暗或过亮 } this.update = function() { this.vel.add(this.acc); this.vel.limit(this.maxspeed); this.pos.add(this.vel); this.acc.mult(0); } this.follow = function(vectors) { var x = floor(this.pos.x / scl); var y = floor(this.pos.y / scl); var index = x + y * cols; var force = vectors[index]; this.applyForce(force); } this.applyForce = function(force) { this.acc.add(force); } this.showBlue = function() { stroke(0, 76, 153, this.alphaPower); strokeWeight(1); line(this.pos.x, this.pos.y, this.prevPos.x, this.prevPos.y); this.updatePrev(); } this.showMaroon = function() { stroke(165, 0, 68, this.alphaPower); strokeWeight(1); line(this.pos.x, this.pos.y, this.prevPos.x, this.prevPos.y); this.updatePrev(); } this.showYellow = function() { stroke(237, 188, 0, this.alphaPower); strokeWeight(1); line(this.pos.x, this.pos.y, this.prevPos.x, this.prevPos.y); this.updatePrev(); } this.updatePrev = function() { this.prevPos.x = this.pos.x; this.prevPos.y = this.pos.y; } this.edges = function() { if (this.pos.x > width) { this.pos.x = 0; this.updatePrev(); } if (this.pos.x < 0) { this.pos.x = width; this.updatePrev(); } if (this.pos.y > height) { this.pos.y = 0; this.updatePrev(); } if (this.pos.y < 0) { this.pos.y = height; this.updatePrev(); } } }
sketch.js(核心修改:独立流场+数据关联+性能优化)
var inc = 0.01; var scl = 10; var cols, rows; var zoff = 0; var fr; // 减少粒子数量,每种颜色500个,平衡性能和视觉效果 var particleCount = 500; var particlesMaroon = []; var particlesBlue = []; var particlesYellow = []; var flowfieldMaroon; var flowfieldBlue; var flowfieldYellow; var gamma_is_high = false; var beta_is_high = false; var alpha_is_high = false; var maroon_data=1000; var blue_data = 1000; var yellow_data = 1000; setInterval(function() { ChangeLines(); }, 5000); function ChangeLines(){ maroon_data = random(500, 2000); blue_data = random(500, 2000); yellow_data = random(500, 2000); gamma_is_high = true; alpha_is_high = true; beta_is_high = true; } function setup() { slider = createSlider(0.01, 0.1, 0.02, 0); slider.position(10, 10); slider.style('width', '80px'); ChangeLines(); createCanvas(windowWidth-15, windowHeight-20); cols = floor(width / scl); rows = floor(height / scl); fr = createP(''); // 初始化流场数组 flowfieldMaroon = new Array(cols * rows); flowfieldBlue = new Array(cols * rows); flowfieldYellow = new Array(cols * rows); // 初始化每种颜色的粒子 for (var i = 0; i < particleCount; i++) { particlesMaroon[i] = new Particle(); particlesBlue[i] = new Particle(); particlesYellow[i] = new Particle(); } // 初始背景用纯白 background(255); } function draw() { let val = slider.value(); inc = val; // 半透明背景,实现轨迹渐变拖尾效果 background(255, 3); var yoff = 0; for (var y = 0; y < rows; y++) { var xoff = 0; for (var x = 0; x < cols; x++) { var index = x + y * cols; // 给每种颜色的噪声添加独立偏移量,生成不同的流场 // 偏移量要足够大,确保噪声图案完全独立 var angleMaroon = noise(xoff, yoff, zoff + 1000) * TWO_PI; var angleBlue = noise(xoff, yoff, zoff + 2000) * TWO_PI; var angleYellow = noise(xoff, yoff, zoff + 3000) * TWO_PI; // 将EEG数据关联到流场强度:数据越大,流场的力越强 var magMaroon = map(maroon_data, 500, 2000, 2, 6); var magBlue = map(blue_data, 500, 2000, 2, 6); var magYellow = map(yellow_data, 500, 2000, 2, 6); var vm = p5.Vector.fromAngle(angleMaroon); var vb = p5.Vector.fromAngle(angleBlue); var vy = p5.Vector.fromAngle(angleYellow); vm.setMag(magMaroon); vb.setMag(magBlue); vy.setMag(magYellow); flowfieldMaroon[index] = vm; flowfieldBlue[index] = vb; flowfieldYellow[index] = vy; xoff += inc; } yoff += inc; } // 加快流场变化速度,让视觉效果更生动 zoff += 0.001; // 处理栗色粒子 if(gamma_is_high){ // 根据EEG数据设置粒子透明度 let maroonAlpha = map(maroon_data, 500, 2000, 10, 30); for (var i = 0; i < particlesMaroon.length; i++) { particlesMaroon[i].setAlpha(maroonAlpha); particlesMaroon[i].follow(flowfieldMaroon); particlesMaroon[i].update(); particlesMaroon[i].edges(); particlesMaroon[i].showMaroon(); } } // 处理蓝色粒子 if(beta_is_high){ let blueAlpha = map(blue_data, 500, 2000, 10, 30); for (var i = 0; i < particlesBlue.length; i++) { particlesBlue[i].setAlpha(blueAlpha); particlesBlue[i].follow(flowfieldBlue); particlesBlue[i].update(); particlesBlue[i].edges(); particlesBlue[i].showBlue(); } } // 处理黄色粒子 if(alpha_is_high){ let yellowAlpha = map(yellow_data, 500, 2000, 10, 30); for (var i = 0; i < particlesYellow.length; i++) { particlesYellow[i].setAlpha(yellowAlpha); particlesYellow[i].follow(flowfieldYellow); particlesYellow[i].update(); particlesYellow[i].edges(); particlesYellow[i].showYellow(); } } fr.html(floor(frameRate())); }
关键修改说明
- 独立流场生成:给每种颜色的噪声添加了不同的z轴偏移量(
zoff + 1000、zoff + 2000等),这样三个流场的Perlin噪声图案完全独立,粒子轨迹不再重叠。 - EEG数据关联:
- 流场强度(
setMag的值)通过map()函数关联到EEG数据,数据越大,粒子的移动速度越快。 - 粒子透明度也通过
map()和EEG数据绑定,数据越大,轨迹越明显。
- 流场强度(
- 视觉优化:
- 背景改为半透明(
background(255, 3)),让旧轨迹逐渐淡出,形成渐变拖尾的艺术效果。 - 降低了粒子的最大速度,轨迹更平滑自然。
- 背景改为半透明(
- 性能优化:减少了粒子总数(从4000降到1500),避免帧率过低,同时保证视觉密度足够。
这样修改后,你就能看到三种颜色的独立流场动态变化,而且EEG数据的变化会直接反映在流场的速度和轨迹亮度上,完全符合你想要的连续彩色艺术化Perlin流场效果。
内容的提问来源于stack exchange,提问作者Saad Anees
相关产品推荐
相关产品推荐

