Perlin Flow Field Tapestry
Generated by GridFlow AI | Tags: perlin noise, flow field, particle system, emergent behavior, organic texture, interactive art, generative
💡 AI 提示词
Create an organic texture mapping system using Perlin noise as a driving force for a particle flow field, with emergent patterns, mouse interaction, and fluid-like dynamics.🔧 核心算法要点
- Initialize a 2D flow field grid with resolution-based cells that sample 3D Perlin noise for angle generation
- Map noise values (0-1) to angles spanning multiple rotations for complex directional patterns
- Spawn particles that sample the flow field at their current position and follow the resulting vectors
- Add curl noise perturbation based on position-time relationships for additional organic complexity
- Implement mouse-based forces: radial repulsion within 150px and directional drift influence
- Apply velocity damping and acceleration limiting for smooth, organic particle movement
- Render particles with HSB colors derived from position, velocity magnitude, and time for chromatic emergence
- Fade background each frame to create ghostly trails that build complex layered textures
🎨 原始代码
var sketch = function(p) {
var particles = [];
var t = 0;
var zoff = 0;
var scale = 0.003;
var noiseStrength = 1.5;
var particleCount = 1200;
var flowField = [];
var cols, rows;
var resolution = 20;
p.setup = function() {
var container = document.getElementById('p5-wrapper');
p.createCanvas(container.offsetWidth, container.offsetHeight).parent(container);
p.colorMode(p.HSB, 360, 100, 100, 100);
p.background(0, 0, 8);
p.noStroke();
cols = Math.floor(p.width / resolution) + 1;
rows = Math.floor(p.height / resolution) + 1;
flowField = new Array(cols * rows);
for (var i = 0; i < particleCount; i++) {
particles.push(p.createParticle());
}
};
p.createParticle = function() {
return {
pos: p.createVector(p.random(p.width), p.random(p.height)),
vel: p.createVector(0, 0),
acc: p.createVector(0, 0),
maxSpeed: p.random(1.5, 4),
hueOffset: p.random(360),
size: p.random(1.5, 4),
life: p.random(150, 350),
maxLife: 0
};
};
p.updateFlowField = function() {
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 angle = p.noise(xoff, yoff, zoff) * p.TWO_PI * 3;
var v = p5.Vector.fromAngle(angle);
v.setMag(noiseStrength);
flowField[index] = v;
xoff += scale;
}
yoff += scale;
}
zoff += 0.0008;
};
p.getFlowVector = function(x, y) {
var xIndex = Math.floor(x / resolution);
var yIndex = Math.floor(y / resolution);
xIndex = p.constrain(xIndex, 0, cols - 1);
yIndex = p.constrain(yIndex, 0, rows - 1);
return flowField[xIndex + yIndex * cols];
};
p.draw = function() {
p.background(0, 0, 8, 8);
p.updateFlowField();
var mouseInfluence = p.createVector(p.mouseX - p.width / 2, p.mouseY - p.height / 2);
mouseInfluence.mult(0.003);
for (var i = 0; i < particles.length; i++) {
var part = particles[i];
var flow = p.getFlowVector(part.pos.x, part.pos.y);
part.acc.add(flow);
part.acc.add(mouseInfluence);
var distanceToMouse = p.dist(part.pos.x, part.pos.y, p.mouseX, p.mouseY);
if (distanceToMouse < 150) {
var repel = p5.Vector.sub(part.pos, p.createVector(p.mouseX, p.mouseY));
repel.normalize();
repel.mult(p.map(distanceToMouse, 0, 150, 2, 0));
part.acc.add(repel);
}
var curlNoise = p.noise(part.pos.x * 0.002, part.pos.y * 0.002, t * 0.5);
var curlAngle = curlNoise * p.TWO_PI * 2;
var curlForce = p5.Vector.fromAngle(curlAngle);
curlForce.mult(0.15);
part.acc.add(curlForce);
part.vel.add(part.acc);
part.vel.limit(part.maxSpeed);
part.vel.mult(0.98);
part.pos.add(part.vel);
part.acc.mult(0);
part.life--;
var lifeRatio = part.life / 350;
var hue = (part.hueOffset + t * 80 + p.map(part.pos.x, 0, p.width, 0, 60)) % 360;
var saturation = p.map(p.abs(part.vel.x) + p.abs(part.vel.y), 0, part.maxSpeed * 2, 50, 90);
var brightness = p.map(lifeRatio, 0, 1, 40, 95);
var alpha = p.map(lifeRatio, 0, 1, 10, 70);
p.fill(hue, saturation, brightness, alpha);
var drawSize = part.size * p.map(lifeRatio, 0, 1, 0.3, 1);
p.ellipse(part.pos.x, part.pos.y, drawSize, drawSize);
if (part.pos.x < 0 || part.pos.x > p.width || part.pos.y < 0 || part.pos.y > p.height || part.life <= 0) {
var newPart = p.createParticle();
if (Math.random() > 0.3) {
var spawnSide = Math.floor(p.random(4));
if (spawnSide === 0) {
newPart.pos.x = 0;
newPart.pos.y = p.random(p.height);
} else if (spawnSide === 1) {
newPart.pos.x = p.width;
newPart.pos.y = p.random(p.height);
} else if (spawnSide === 2) {
newPart.pos.x = p.random(p.width);
newPart.pos.y = 0;
} else {
newPart.pos.x = p.random(p.width);
newPart.pos.y = p.height;
}
}
particles[i] = newPart;
}
}
t += 0.015;
};
p.windowResized = function() {
var container = document.getElementById('p5-wrapper');
p.resizeCanvas(container.offsetWidth, container.offsetHeight);
cols = Math.floor(p.width / resolution) + 1;
rows = Math.floor(p.height / resolution) + 1;
flowField = new Array(cols * rows);
};
};
// p5 init stripped
✨ AI 艺术解读
This piece explores the emergent beauty of noise-driven particle systems where simple local rules create complex global patterns. The flow field acts as an invisible conductor, guiding thousands of particles through a choreographed dance that never repeats. Mouse interaction introduces controlled chaos, allowing viewers to sculpt the composition in real-time while the accumulated particle trails reveal the hidden mathematics underlying organic forms. The resulting tapestry speaks to the fundamental connection between deterministic systems and apparent randomness in nature.
📝 补充说明
- The flow field resolution (20px cells) balances visual smoothness with computational efficiency for real-time performance
- Curl noise addition at 15% strength creates subtle swirling without overwhelming the primary flow direction
- Background fade rate of 8/255 creates optimal trail persistence for the given particle density and lifetime
- Spawning particles at screen edges with outward bias maintains consistent density while preventing clustering
- Using HSB color mode with time-based hue rotation ensures smooth chromatic transitions across the entire spectrum