Perlin Marble Veining Effect
Generated by GridFlow AI | Tags: perlin-noise, fluid-dynamics, particle-system, organic-veins, generative-art, flow-field, procedural-marble, emergent-patterns
💡 AI 提示词
Create an organic marble veining effect using Perlin noise as the foundation for a fluid flow field, with particles tracing vein paths that emerge from noise-driven dynamics.🔧 核心算法要点
- Multi-octave Perlin noise combining three noise layers at different scales to create complex base marble texture
- Flow field computed from noise gradients where particle movement follows noise-derived angle fields
- Curl noise added to flow field for natural swirling motion simulating fluid dynamics in stone formation
- Particle system with velocity, drag, and maximum speed constraints creating organic vein tracer paths
- Dynamic vein generation based on noise thresholds - medium values produce directional veins while high values create nodes
- Dual-layer particle rendering with trail effects for depth, including fade-in and fade-out lifecycle management
- Vein coloration influenced by local noise values creating darker streaks in high-density regions
- Secondary elliptical overlays at vein intersections for enhanced mineral deposit appearance
🎨 原始代码
var sketch = function(p) {
var container;
var canvas;
var particles = [];
var field = [];
var cols, rows;
var cellSize = 5;
var time = 0;
var noiseScale = 0.008;
p.setup = function() {
container = document.getElementById('p5-wrapper');
canvas = p.createCanvas(container.offsetWidth, container.offsetHeight).parent(container);
p.colorMode(p.HSB, 360, 100, 100, 100);
p.noiseDetail(4, 0.5);
cols = Math.ceil(p.width / cellSize) + 2;
rows = Math.ceil(p.height / cellSize) + 2;
for (var i = 0; i < 500; i++) {
particles.push({
x: p.random(p.width),
y: p.random(p.height),
vx: 0,
vy: 0,
life: p.random(150, 350),
maxLife: 0,
baseHue: p.randomGaussian(30, 15),
speed: p.random(0.8, 2.5),
age: 0
});
particles[i].maxLife = particles[i].life;
}
};
p.draw = function() {
p.noStroke();
p.fill(0, 0, 95, 3);
p.rect(0, 0, p.width, p.height);
for (var x = 0; x < cols; x++) {
for (var y = 0; y < rows; y++) {
var idx = x + y * cols;
var n1 = p.noise(x * noiseScale, y * noiseScale, time);
var n2 = p.noise(x * noiseScale * 2.5, y * noiseScale * 2.5, time * 1.5 + 100);
var n3 = p.noise(x * noiseScale * 0.3, y * noiseScale * 0.3, time * 0.5 + 200);
field[idx] = n1 * 0.5 + n2 * 0.3 + n3 * 0.2;
}
}
p.noFill();
for (var x = 1; x < cols - 1; x++) {
for (var y = 1; y < rows - 1; y++) {
var idx = x + y * cols;
var nVal = field[idx];
if (nVal > 0.55 && nVal < 0.65) {
var angle = p.map(p.noise(x * noiseScale * 3, y * noiseScale * 3, time * 0.8), 0, 1, 0, p.TWO_PI);
var px = x * cellSize;
var py = y * cellSize;
var len = p.map(nVal, 0.55, 0.65, 8, 25);
p.stroke(40, 25, 85, 35);
p.strokeWeight(p.map(nVal, 0.55, 0.65, 0.5, 1.2));
p.line(px, py, px + len * p.cos(angle), py + len * p.sin(angle));
}
if (nVal > 0.72) {
var px = x * cellSize;
var py = y * cellSize;
var thickness = p.map(nVal, 0.72, 1, 1, 3.5);
p.stroke(35, 30, 70, 45);
p.strokeWeight(thickness);
p.ellipse(px, py, thickness * 1.5, thickness * 1.5);
}
}
}
for (var i = 0; i < particles.length; i++) {
var part = particles[i];
var col = Math.floor(part.x / cellSize);
var row = Math.floor(part.y / cellSize);
col = p.constrain(col, 0, cols - 1);
row = p.constrain(row, 0, rows - 1);
var nAngle = p.noise(col * noiseScale * 2, row * noiseScale * 2, time * 0.6) * p.TWO_PI * 4;
part.vx += p.cos(nAngle) * 0.15;
part.vy += p.sin(nAngle) * 0.15;
var curl = p.noise(col * noiseScale * 4, row * noiseScale * 4, time * 0.3 + 50) * p.TWO_PI;
part.vx += p.cos(curl) * 0.05;
part.vy += p.sin(curl) * 0.05;
var drag = 0.96;
var maxSpeed = 3;
part.vx *= drag;
part.vy *= drag;
var speed = p.sqrt(part.vx * part.vx + part.vy * part.vy);
if (speed > maxSpeed) {
part.vx = (part.vx / speed) * maxSpeed;
part.vy = (part.vy / speed) * maxSpeed;
}
part.x += part.vx * part.speed;
part.y += part.vy * part.speed;
part.age++;
if (part.x < 0) part.x += p.width;
if (part.x > p.width) part.x -= p.width;
if (part.y < 0) part.y += p.height;
if (part.y > p.height) part.y -= p.height;
var lifeRatio = part.life / part.maxLife;
var fadeIn = p.min(part.age / 30, 1);
var fadeOut = p.max(0, lifeRatio);
var alpha = fadeIn * fadeOut * 70;
if (alpha > 0.5) {
var baseBright = p.map(nVal, 0, 1, 55, 92);
var veinInfluence = p.constrain(p.map(field[col + row * cols], 0.5, 0.75, 1, 0), 0, 1);
var hue = part.baseHue + veinInfluence * 20;
var sat = 15 + veinInfluence * 35;
var bright = baseBright - veinInfluence * 30;
p.stroke(hue, sat, bright, alpha);
p.strokeWeight(0.8 + lifeRatio * 0.6);
p.point(part.x, part.y);
if (part.age > 5 && lifeRatio > 0.3) {
p.stroke(hue, sat * 0.7, bright + 5, alpha * 0.4);
p.strokeWeight(1.2);
p.point(part.x - part.vx * 2, part.y - part.vy * 2);
}
}
if (part.life <= 0 || (lifeRatio < 0.2 && p.random() < 0.01)) {
part.x = p.random(p.width);
part.y = p.random(p.height);
part.vx = 0;
part.vy = 0;
part.life = p.random(200, 400);
part.maxLife = part.life;
part.age = 0;
part.baseHue = p.randomGaussian(30, 15);
part.speed = p.random(0.8, 2.5);
} else {
part.life -= 1;
}
}
p.noStroke();
for (var x = 0; x < cols; x++) {
for (var y = 0; y < rows; y++) {
var idx = x + y * cols;
var n = field[idx];
if (n < 0.4) {
var px = x * cellSize;
var py = y * cellSize;
var a = p.map(n, 0, 0.4, 8, 0);
p.fill(200, 30, 85, a);
p.ellipse(px, py, 3, 3);
}
}
}
time += 0.003;
};
p.windowResized = function() {
p.resizeCanvas(container.offsetWidth, container.offsetHeight);
cols = Math.ceil(p.width / cellSize) + 2;
rows = Math.ceil(p.height / cellSize) + 2;
};
};
✨ AI 艺术解读
This piece captures the millions-year geological process of marble formation compressed into an eternal moment. The veins emerge organically from noise fields as if mineral-laden water once flowed through ancient limestone, leaving behind traces of its journey. Each particle traces a path that mirrors how real marble's characteristic veining forms through pressure and fluid movement through rock strata. The result feels both ancient and timeless, with complexity that suggests hand-crafted artistry despite emerging entirely from mathematical rules.
📝 补充说明
- Increase cellSize for larger, more visible veins or decrease for denser micro-veining patterns
- Modify noiseDetail parameters to change the 'roughness' of the marble texture from smooth to granular
- Particle count directly impacts density of final veining - more particles create busier, more complex patterns
- The three noise octave combination creates natural-looking stone without appearing artificially generated
- Consider adding additional color layers for calcite and pyrite inclusions in the marble for extra realism