气泡浮力与流体动力学:Canvas 模拟水下气泡上升与破裂动效

发布时间:2026/9/26 16:27:38
气泡浮力与流体动力学:Canvas 模拟水下气泡上升与破裂动效
气泡浮力与流体动力学Canvas 模拟水下气泡上升与破裂动效在现代 Web 互动营销、水下科幻主题大屏以及先锋液体微交互设计中“晶莹剔透的水下气泡Underwater Bubbles升腾与表面张力破裂动效”是一种能极大赋予界面生机、空灵与梦幻呼吸感的顶级视觉元素。然而许多初级前端在手写气泡动效时往往只是简单地让圆形沿一条垂直直线匀速向上平移y - 2这种伪气泡看起来就像一颗颗死板的塑料小珠子在真空轨道中移动缺乏水下流体的粘滞阻力刹车感真实世界中的水下气泡在上升时由于背风侧周期性涡旋脱落Vortex Shedding / 卡门涡街效应必定会产生极其灵动的横向 S 形正弦左右摇曳Wobbling Swirl当气泡升至水面的一瞬间必须经历表面张力拉伸、并在毫秒内爆裂化作一团微小的晶莹飞溅水珠Droplets Burst将阿基米德浮力定律、斯托克斯流体阻力与涡街摆动微分方程融合进 Canvas 粒子动力学我们能够以极轻的纯数学算力在屏幕上呈现出宛如置身深海般逼真空灵的物理气泡升腾画卷。气泡流体动力学的四大物理方程推导设单个气泡为半径为 $r$ 的微小球体其在水中的空间坐标为 $\mathbf{p} (x, y)$上升速度为 $\mathbf{v} (v_x, v_y)$。每一帧作用在气泡上的流体力学合力由四部分构成[气泡在水下受力平衡图] ▲ │ 阿基米德浮力 (F_buoyancy 4/3 * pi * r^3 * rho_water * g) ┌───┴───┐ 流体涡街横向摆动力 ◀───────────────┤ 气泡 ├───────────────▶ 流体涡街横向摆动力 (F_wobble A * sin(omega * t)) └───┬───┘ (周期性左右交替产生 S 形轨迹) │ ▼ 斯托克斯流体粘滞阻力 (F_drag -6 * pi * eta * r * v)1. 向上阿基米德浮力Buoyancy Force$$F_{buoyancy} \rho_{water} \cdot V \cdot g \frac{4}{3} \pi r^3 \cdot \rho_{water} \cdot g$$气泡体积越大$r$ 越大受到的向上浮力呈三次方程爆发式增长上升初速度越快2. 斯托克斯流体粘滞阻力Stokes Drag Law对于在低雷诺数粘性流体中运动的球体水流阻力与速度的一次方成正比方向严格向下$$F_{drag} -6 \pi \cdot \eta \cdot r \cdot v_y$$当浮力与阻力完全平衡时气泡达到终端收尾上升速度Terminal Velocity。3. 涡街横向正弦摆动Vortex Wobbling气泡在上升过程中两侧不对称脱落的微旋涡对气泡施加横向周期性推力$$x(t) x_0 A_{wobble} \cdot \sin(\omega \cdot t \phi_0)$$其中摆动频率 $\omega$ 与气泡尺寸反相关小气泡高频微颤大气泡从容大摆。TypeScript 纯数学气泡物理引擎实现// underwater-bubble-engine.ts export interface BubbleBurstDroplet { x: number; y: number; vx: number; vy: number; alpha: number; } export class FluidBubble { public x: number; public y: number; public baseRadius: number; public currentRadius: number; public vy: number 0; public wobblePhase: number; public wobbleSpeed: number; public wobbleAmplitude: number; public isBursting: boolean false; public burstDroplets: BubbleBurstDroplet[] []; constructor(startX: number, startY: number, radius: number) { this.x startX; this.y startY; this.baseRadius radius; this.currentRadius radius; this.wobblePhase Math.random() * Math.PI * 2; this.wobbleSpeed (1.5 / radius) * 0.08 0.02; // 小气泡摆动更快 this.wobbleAmplitude radius * 0.8; } // 1. 物理步进 public update(waterSurfaceY: number) { if (this.isBursting) { // 破裂微粒子物理衰减 for (let i this.burstDroplets.length - 1; i 0; i--) { const d this.burstDroplets[i]; d.x d.vx; d.y d.vy; d.vy 0.15; // 微重力下坠 d.alpha - 0.04; if (d.alpha 0) this.burstDroplets.splice(i, 1); } return; } // A. 浮力与阻力平衡推进 const terminalSpeed -Math.min(6.5, this.baseRadius * 0.28 0.8); this.vy (terminalSpeed - this.vy) * 0.1; this.y this.vy; // B. 叠加涡街横向正弦摇曳 this.wobblePhase this.wobbleSpeed; this.x Math.cos(this.wobblePhase) * (this.wobbleAmplitude * 0.08); // C. 触达水面瞬间触发表面张力爆裂 if (this.y waterSurfaceY) { this.triggerBurst(); } } // 2. 触发气泡破裂微粒子飞溅 private triggerBurst() { this.isBursting true; const dropletCount Math.floor(this.baseRadius * 1.5); for (let i 0; i dropletCount; i) { const angle Math.random() * Math.PI * 2; const speed Math.random() * 3.5 1.0; this.burstDroplets.push({ x: this.x, y: this.y, vx: Math.cos(angle) * speed, vy: Math.sin(angle) * speed - 1.5, // 向上喷射 alpha: 1.0, }); } } }Canvas 晶莹水下高光折射渲染// bubble-canvas-stage.ts export class BubbleCanvasStage { private canvas: HTMLCanvasElement; private ctx: CanvasRenderingContext2D; private bubbles: FluidBubble[] []; private waterSurfaceY: number 60; constructor(canvas: HTMLCanvasElement) { this.canvas canvas; this.ctx canvas.getContext(2d)!; this.spawnBubbles(30); } private spawnBubbles(count: number) { for (let i 0; i count; i) { this.bubbles.push(new FluidBubble( Math.random() * this.canvas.width, this.canvas.height Math.random() * 400, Math.random() * 12 4 )); } } public renderLoop () { const w this.canvas.width; const h this.canvas.height; // 深海幽蓝渐变底板 const bgGrad this.ctx.createLinearGradient(0, 0, 0, h); bgGrad.addColorStop(0, #0f172a); bgGrad.addColorStop(1, #020617); this.ctx.fillStyle bgGrad; this.ctx.fillRect(0, 0, w, h); // 绘制水面微光线 this.ctx.strokeStyle rgba(56, 189, 248, 0.4); this.ctx.lineWidth 1.5; this.ctx.beginPath(); this.ctx.moveTo(0, this.waterSurfaceY); this.ctx.lineTo(w, this.waterSurfaceY); this.ctx.stroke(); for (let i this.bubbles.length - 1; i 0; i--) { const b this.bubbles[i]; b.update(this.waterSurfaceY); if (!b.isBursting) { // 绘制晶莹半透明气泡球体 this.ctx.beginPath(); this.ctx.arc(b.x, b.y, b.baseRadius, 0, 2 * Math.PI); this.ctx.fillStyle rgba(56, 189, 248, 0.15); this.ctx.fill(); this.ctx.strokeStyle rgba(255, 255, 255, 0.6); this.ctx.lineWidth 1.2; this.ctx.stroke(); // 绘制右上角物理高光白点 (Specular Highlight) this.ctx.beginPath(); this.ctx.arc( b.x - b.baseRadius * 0.35, b.y - b.baseRadius * 0.35, b.baseRadius * 0.25, 0, 2 * Math.PI ); this.ctx.fillStyle rgba(255, 255, 255, 0.85); this.ctx.fill(); } else { // 绘制破裂飞溅水滴 for (const d of b.burstDroplets) { this.ctx.beginPath(); this.ctx.arc(d.x, d.y, 1.5, 0, 2 * Math.PI); this.ctx.fillStyle rgba(56, 189, 248, ${d.alpha}); this.ctx.fill(); } // 破裂完毕后在底部重生 if (b.burstDroplets.length 0) { this.bubbles[i] new FluidBubble( Math.random() * w, h 40, Math.random() * 12 4 ); } } } requestAnimationFrame(this.renderLoop); }; }总结气泡升腾的灵动美感源于流体浮力与涡旋摆动在微观空间中自发涌现的自然秩序。将阿基米德浮力定律、斯托克斯阻力与表面张力破裂方程精确编织进 Canvas 渲染管线我们在屏幕上为微交互动效赋予了如同深海气泡般纯净、剔透且充满生命张力的物理真实质感。