Subsurface Organic Matter
Generated by GridFlow AI | Tags: perlin-noise, subsurface-scattering, organic-matter, particle-systems, flow-fields, emergent-behavior, organic-textures
💡 AI 提示词
Perlin noise driven subsurface organic matter with multi-layered particle systems simulating living tissue, featuring flowing vein-like structures, depth-based color variation, and pulsing biological rhythms.🔧 核心算法要点
- Multi-octave Perlin noise fields driving particle velocity vectors at different scales for complex emergent motion
- Layered subsurface cellular background using grid-based noise sampling with depth-dependent coloring
- Organic vein network generated with flowing curve vertices modulated by noise for lifelike branching patterns
- Particle system with three visual layers per particle creating subsurface scattering depth effect
- Central breathing core glow that pulses with sinusoidal rhythm simulating heartbeat-like biological activity
- Margin-based boundary forces and center-distance modulation for natural spatial distribution
🎨 原始代码
var sketch = function(p) {
var particles = [];
var numParticles = 900;
var noiseScale1 = 0.003;
var noiseScale2 = 0.007;
var timeScale = 0.0003;
var t = 0;
var veins = [];
var numVeins = 25;
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(20, 30, 8);
p.noStroke();
for (var i = 0; i < numParticles; i++) {
particles.push(createParticle(p.random(p.width), p.random(p.height), i));
}
for (var i = 0; i < numVeins; i++) {
veins.push({
x: p.random(p.width),
y: p.random(p.height),
angle: p.random(p.TWO_PI),
length: p.random(80, 200),
hue: p.random(10, 35),
speed: p.random(0.3, 0.8)
});
}
};
function createParticle(x, y, id) {
var hueBase = 5 + p.noise(id * 0.02) * 25;
var satBase = 65 + p.noise(id * 0.03) * 35;
return {
pos: p.createVector(x, y),
vel: p.createVector(0, 0),
acc: p.createVector(0, 0),
baseSize: 3 + p.noise(id * 0.01) * 10,
hue: hueBase,
sat: satBase,
bri: 70 + p.noise(id * 0.025) * 30,
alpha: 25 + p.noise(id * 0.015) * 35,
phase: p.random(p.TWO_PI),
layer: Math.floor(p.random(3))
};
}
p.draw = function() {
p.fill(20, 30, 8, 8);
p.rect(0, 0, p.width, p.height);
t += timeScale * 60;
drawSubsurfaceLayers();
drawVeins();
updateParticles();
drawCoreGlow();
};
function drawSubsurfaceLayers() {
for (var layer = 0; layer < 3; layer++) {
var layerOffset = t * (0.5 + layer * 0.3);
var numCells = 15 + layer * 5;
var cellW = p.width / numCells;
var cellH = p.height / numCells;
for (var i = 0; i < numCells; i++) {
for (var j = 0; j < numCells; j++) {
var cx = i * cellW + cellW * 0.5;
var cy = j * cellH + cellH * 0.5;
var n1 = p.noise(i * 0.15 + layerOffset, j * 0.15, t * 0.5);
var n2 = p.noise(i * 0.08 + layerOffset * 0.7, j * 0.08, t * 0.3 + 100);
var combined = (n1 + n2 * 0.5) / 1.5;
var hue = 8 + combined * 18 + layer * 3;
var sat = 40 + combined * 40 - layer * 10;
var bri = 12 + combined * 18;
var alpha = 15 + combined * 20;
var offsetX = p.noise(i * 0.2 + t, j * 0.2) * cellW * 0.3;
var offsetY = p.noise(i * 0.2, j * 0.2 + t) * cellH * 0.3;
var size = cellW * (0.6 + combined * 0.4) * (1 + layer * 0.1);
p.fill(hue, sat, bri, alpha);
p.ellipse(cx + offsetX, cy + offsetY, size, size * 0.9);
}
}
}
}
function drawVeins() {
for (var i = 0; i < veins.length; i++) {
var v = veins[i];
var angleNoise = p.noise(v.x * 0.002, v.y * 0.002, t * v.speed);
v.angle += (angleNoise - 0.5) * 0.05;
var pulse = 0.5 + p.noise(v.x * 0.005 + t, v.y * 0.005) * 0.5;
var flowOffset = t * 50 * v.speed;
p.strokeWeight(1 + pulse * 2);
p.stroke(v.hue, 60, 40, 10 + pulse * 15);
p.noFill();
p.beginShape();
for (var j = 0; j < v.length; j += 8) {
var nx = p.noise(v.x * 0.01 + j * 0.02, flowOffset) - 0.5;
var ny = p.noise(v.y * 0.01 + j * 0.02, flowOffset + 50) - 0.5;
var px = v.x + Math.cos(v.angle) * j + nx * 30;
var py = v.y + Math.sin(v.angle) * j + ny * 30;
p.curveVertex(px, py);
}
p.endShape();
}
p.noStroke();
}
function updateParticles() {
for (var i = 0; i < particles.length; i++) {
var pt = particles[i];
var n1 = p.noise(pt.pos.x * noiseScale1, pt.pos.y * noiseScale1, t);
var n2 = p.noise(pt.pos.x * noiseScale2, pt.pos.y * noiseScale2, t * 1.5 + 100);
var angle1 = n1 * p.TWO_PI * 3;
var angle2 = n2 * p.TWO_PI * 2;
var force1 = (n1 - 0.5) * 0.4;
var force2 = (n2 - 0.5) * 0.2;
var fx = Math.cos(angle1) * force1 + Math.cos(angle2) * force2;
var fy = Math.sin(angle1) * force1 + Math.sin(angle2) * force2;
pt.acc.set(fx, fy);
pt.vel.add(pt.acc);
pt.vel.mult(0.94);
pt.pos.add(pt.vel);
var margin = 80;
if (pt.pos.x < margin) pt.vel.x += 0.15;
if (pt.pos.x > p.width - margin) pt.vel.x -= 0.15;
if (pt.pos.y < margin) pt.vel.y += 0.15;
if (pt.pos.y > p.height - margin) pt.vel.y -= 0.15;
var centerDist = p.dist(pt.pos.x, pt.pos.y, p.width / 2, p.height / 2);
var maxDist = p.dist(0, 0, p.width / 2, p.height / 2);
var normDist = centerDist / maxDist;
var pulse = 1 + Math.sin(t * 2 + pt.phase) * 0.3 * (1 - normDist * 0.5);
var depthPulse = p.noise(pt.pos.x * 0.01, pt.pos.y * 0.01, t * 0.5 + pt.layer * 100);
var displaySize = pt.baseSize * pulse * (0.7 + depthPulse * 0.5);
var lifeAlpha = 0.6 + Math.sin(t + pt.phase) * 0.4;
var finalAlpha = pt.alpha * lifeAlpha;
var layerHue = pt.hue + Math.sin(t * 0.5 + pt.phase) * 8;
var layerSat = pt.sat - pt.layer * 10;
var layerBri = pt.bri - pt.layer * 8;
p.fill(layerHue, layerSat, layerBri, finalAlpha * 0.4);
p.ellipse(pt.pos.x, pt.pos.y, displaySize * 1.8, displaySize * 1.8);
p.fill(layerHue, layerSat, layerBri, finalAlpha * 0.7);
p.ellipse(pt.pos.x, pt.pos.y, displaySize * 1.2, displaySize * 1.2);
p.fill(layerHue + 5, layerSat - 10, layerBri + 10, finalAlpha);
p.ellipse(pt.pos.x, pt.pos.y, displaySize, displaySize);
}
}
function drawCoreGlow() {
var cx = p.width / 2;
var cy = p.height / 2;
var coreSize = Math.min(p.width, p.height) * 0.6;
var breathe = 1 + Math.sin(t * 0.8) * 0.1;
for (var r = coreSize; r > 0; r -= coreSize / 8) {
var alpha = (1 - r / coreSize) * 12;
var hue = 15 + (1 - r / coreSize) * 10;
p.fill(hue, 50, 30, alpha);
p.ellipse(cx, cy, r * breathe, r * breathe * 0.95);
}
}
p.windowResized = function() {
var container = document.getElementById('p5-wrapper');
p.resizeCanvas(container.offsetWidth, container.offsetHeight);
p.background(20, 30, 8);
};
};
// p5 init stripped
✨ AI 艺术解读
This piece simulates the intimate visual experience of peering into living organic tissue beneath the surface. The multi-layered particle system creates the illusion of depth found in biological matter, where particles at different depths contribute to a translucent, layered appearance. The flowing vein structures weave through the composition like capillaries or mycelium networks, constantly evolving through noise-driven movement. The warm color palette evokes flesh tones while the pulsing central glow suggests a living core, making the viewer feel they are witnessing something alive and breathing.
📝 补充说明
- Layering multiple noise octaves at different scales creates more organic, unpredictable movement than single noise fields
- Subsurface scattering effect achieved by drawing multiple semi-transparent ellipses per particle at varying sizes and alphas
- Vein structures use curveVertex with noise-modulated offsets for smooth, organic-looking tendrils
- The breathing core uses radial gradient-like layering achieved through concentric ellipses with decreasing alpha
- Boundary margin forces keep particles active near edges while preventing harsh wrapping artifacts