html5 canvas可通过粒子系统或像素扩散法模拟颜料晕染效果:前者用带色粒子+速度场实现交互式流动,后者用逐帧邻域扩散+模糊实现低开销动画,均强调扩散、对流、粘滞混合的视觉特征而非物理精确。

HTML5 Canvas 本身不提供流体力学物理引擎,但可以通过粒子系统 + 网格求解(如稳定流体算法)或简化的扩散模型,在视觉层面模拟颜料在水中自然晕染、融合、流动的效果。关键不是复刻Navier-Stokes方程,而是抓住“扩散”“对流”“粘滞混合”三个视觉特征,并用高效可交互的方式落地。
用粒子+速度场模拟颜料扩散
适合中等性能要求、需用户交互(如点击滴落颜料)的场景。核心是把每滴颜料视为一组带颜色和速度的粒子,再叠加一个全局低频速度扰动场(模拟水流):
- 初始化时,按点击位置生成20–50个粒子,赋予随机小初速度和相近色相(如HSL中H±5,S≈80%,L≈60%)
- 每帧更新:粒子位置 += 速度;速度 *= 0.98(模拟水阻);再叠加一个正弦扰动项(如
dx += Math.sin(p.y * 0.03 + time * 0.5) * 0.3),制造轻微漂移感 - 渲染时不用画点,而用
ctx.globalCompositeOperation = "lighter"叠加半透明圆形(radius 1–3px,alpha 0.15–0.3),多次重叠自然形成柔边晕染 - 为增强真实感,可对相邻同色粒子做简单距离检测:若距离<8px,则融合成一个新粒子,颜色取平均,半径略增大
基于像素级扩散的快速近似法
适合静态图像上叠加“颜料渗入”动画,或作为背景特效,性能开销低、兼容性好(IE9+):
- 准备一张初始颜料贴图(PNG,中心高饱和色,边缘渐隐),用
ctx.drawImage()绘制到离屏canvas - 逐帧对离屏canvas执行“模糊+衰减”:调用
ctx.getImageData()读取像素,对每个非透明像素,向周围4邻域(或8邻域)按权重(如0.15)扩散其RGBA值,同时自身alpha乘以0.99 - 扩散后用
ctx.putImageData()写回,再整体用ctx.filter = "blur(0.5px)"轻度柔化边缘(注意:filter仅影响绘制结果,不影响ImageData) - 重复该过程15–30帧,即可看到类似墨水滴入清水缓慢散开的效果
结合径向渐变与动态遮罩实现“滴落-晕染”节奏感
不追求物理精确,但强调表现力和响应速度,常用于LOGO加载页或艺术展示:
- 用
createRadialGradient(x,y,0,x,y,r)创建从中心向外发散的渐变,色标设为[颜料色→透明],r随时间线性增大 - 将该渐变填充到一个圆形路径上,设置
globalAlpha = 0.7,并启用globalCompositeOperation = "multiply",使其与底层底图自然融合 - 为模拟液体表面张力,可在渐变圆外再叠加一个更淡、更大的第二层渐变(相同圆心,r大2倍,alpha=0.1),营造“湿润晕边”
- 若需多色共存,为每种颜料维护独立canvas层,最后用
destination-over合成,避免颜色硬叠加失真
避坑提醒:哪些做法效果差或不可行
实际开发中容易误入歧途,这几个方案建议绕开:
- CSS filter(如
blur()或url(#svgFilter))无法实现方向性扩散或颜色混合,只能做全局模糊,失去颜料特性 - 纯SVG
<feturbulence></feturbulence>+<fedisplacementmap></fedisplacementmap>调参极难获得“颜料感”,极易变成云纹或玻璃折射,且无法控制颜色扩散路径 - 直接用
ctx.fillRect()画大矩形再反复clearRect()不是扩散,是闪烁;扩散必须保留历史像素信息并渐进演化 - 未做跨域处理就用
getImageData()读取外部图片,会触发安全错误;务必确保图片同源或已设crossOrigin="anonymous"
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











