如何用HTML、JavaScript、p5.js实现霉菌状晃动扩散文字效果?
需求与问题描述
我想用HTML、JavaScript和p5.js实现文字霉菌/细胞式晃动+扩散效果——文字边缘像霉菌生长一样不规则晃动,同时有逐渐扩散的视觉表现。我不清楚这类效果的具体名称,尝试了自己写的p5.js代码,但没达到预期,希望得到实现建议;如果原效果难度太高,类似的替代方案也可以接受。
附尝试的p5.js代码:
<!DOCTYPE html> <html> <head> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script> </head> <body> <script> const MAX = 1000; let particles = []; let list = []; let axis; let count = 0; let typedText = 'Macro'; let inputText = []; let graphics; function setup() { createCanvas(1200, 600); colorMode(RGB, 255, 255, 255); frameRate(30); noStroke(); noCursor(); graphics = createGraphics(width, height); graphics.textFont("Arial", 300); graphics.fill(0); graphics.textAlign(CENTER, CENTER); graphics.text(typedText, width / 2, height / 2 - 70); typedText = ""; inputText = []; count = 0; list = new Array(width * height); graphics.loadPixels(); for(let y = 0; y <= height - 1; y++) { for(let x = 0; x <= width - 1; x++) { let index = (x + y * graphics.width) * 4; if(graphics.pixels[index] < 128) { list[y * width + x] = 0; } else { list[y * width + x] = 1; } } } graphics.updatePixels(); particles = []; } function draw() { if (count < MAX) { let i = 0; while(i < 3) { axis = createVector(int(random(100, width - 300)), int(random(100, height - 300))); if(list[int(axis.y * width + axis.x)] == 0) { particles.push(new Particle(axis.x, axis.y)); i++; count++; } } } background(239); for (let i = 0; i < particles.length; i++) { let p = particles[i]; fill(20); p.display(); p.update(); } } function keyReleased() { if (keyCode == ENTER) { typedText = inputText.join(''); setup(); } else { inputText.push(key); } } class Particle { constructor(x, y) { this.location = createVector(x, y); this.velocity = createVector(0, 0); this.scale = random(0.35, 0.9); this.radius = this.scale * 45; this.border = 15; } update() { let noiseX = noise(this.location.x * 0.005, this.location.y * 0.005); let noiseY = noise(this.location.y * 0.005, this.location.x * 0.005); this.velocity.x = map(noiseX, 0, 1, -0.5, 0.5); this.velocity.y = map(noiseY, 0, 1, -0.5, 0.5); this.location.add(this.velocity); // Check if the particle is out of the text area if(list[int((this.location.y + this.velocity.y) * width + int(this.location.x + this.velocity.x))] == 1) { this.velocity.mult(-1); } } display() { ellipse(this.location.x, this.location.y, this.radius, this.radius); } } </script> </body> </html>
实现建议与改进方案
一、现有代码的核心问题
你的代码用粒子模拟文字区域,但离目标效果有两个关键差距:
- 粒子仅在文字内部随机生成,没有沿文字边缘扩散生长的逻辑,无法体现霉菌/细胞的蔓延感
- 粒子的运动是全局噪声驱动,没有和文字轮廓绑定,缺少“附着在文字上晃动”的视觉关联
二、针对性改进方案(贴合原效果)
1. 提取文字边缘的种子点
放弃随机生成粒子,改为从文字轮廓的边缘像素提取初始粒子:
- 在
setup()的像素遍历阶段,只标记文字边缘像素(即周围有空白像素的文字区域像素)作为粒子生成点 - 可以通过检测当前像素上下左右是否有
list值为1(空白)的像素来判断边缘
2. 让粒子沿边缘“扩散生长”
修改粒子生成逻辑:
- 初始只在文字边缘生成少量粒子
- 每帧让部分粒子在自身周围(文字内部)生成新的子粒子,模拟霉菌繁殖扩散
- 给子粒子添加生长延迟,让扩散有先后顺序,更自然
3. 绑定晃动效果到文字轮廓
调整粒子运动逻辑:
- 粒子的噪声运动范围限制在文字内部,且靠近边缘的粒子晃动幅度更大(模拟边缘的不规则蠕动)
- 可以给粒子添加“向文字内部/边缘偏移”的微小力,避免粒子乱跑
三、简化替代方案(快速实现类似效果)
如果觉得粒子扩散逻辑太复杂,可以用噪声扰动文字轮廓的方式快速实现:
- 在
setup()中生成文字的像素蒙版 - 每帧绘制文字时,对每个文字像素的位置添加Perlin噪声偏移:
function draw() { background(239); graphics.loadPixels(); for(let y=0; y<height; y++) { for(let x=0; x<width; x++) { let idx = (x + y*width)*4; if(graphics.pixels[idx] < 128) { // 添加噪声偏移 let offsetX = noise(x*0.02, y*0.02, frameCount*0.01)*10 -5; let offsetY = noise(x*0.02+100, y*0.02, frameCount*0.01)*10 -5; fill(20); rect(x+offsetX, y+offsetY, 1, 1); } } } }
- 对边缘像素加大偏移量,内部像素减小偏移,模拟晃动+局部扩散的视觉效果
四、关键技巧总结
- 用Perlin噪声实现自然的随机晃动,通过
frameCount作为噪声第三个参数实现动画 - 文字蒙版是核心,所有效果都要基于蒙版判断文字区域/边缘
- 扩散效果可以通过“粒子繁殖”或“边缘像素逐步向外扩张”实现
内容的提问来源于stack exchange,提问作者yoonseo
相关产品推荐
相关产品推荐

