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

如何用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()));
}

关键修改说明

  1. 独立流场生成:给每种颜色的噪声添加了不同的z轴偏移量(zoff + 1000、zoff + 2000等),这样三个流场的Perlin噪声图案完全独立,粒子轨迹不再重叠。
  2. EEG数据关联:
    • 流场强度(setMag的值)通过map()函数关联到EEG数据,数据越大,粒子的移动速度越快。
    • 粒子透明度也通过map()和EEG数据绑定,数据越大,轨迹越明显。
  3. 视觉优化:
    • 背景改为半透明(background(255, 3)),让旧轨迹逐渐淡出,形成渐变拖尾的艺术效果。
    • 降低了粒子的最大速度,轨迹更平滑自然。
  4. 性能优化:减少了粒子总数(从4000降到1500),避免帧率过低,同时保证视觉密度足够。

这样修改后,你就能看到三种颜色的独立流场动态变化,而且EEG数据的变化会直接反映在流场的速度和轨迹亮度上,完全符合你想要的连续彩色艺术化Perlin流场效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:45:45