HTML5建模怎么添加粒子效果_雨雪火焰特效制作技巧【技巧】

HTML5本身不提供建模或粒子系统能力,需借助Canvas 2D(轻量雨雪)或WebGL/Three.js(火焰爆炸)实现;核心是粒子数组管理、requestAnimationFrame更新、性能优化与物理逻辑模拟。

HTML5 本身不提供“建模”或“粒子系统”的内置能力,所谓“HTML5 建模+粒子特效”,实际是借助 CanvasWebGL(常通过 Three.js)在浏览器中实现的实时渲染效果。雨、雪、火焰这类粒子特效,本质是大量受物理规则(重力、风速、生命周期、碰撞)控制的小图形(circleimagesprite)批量更新与绘制。

Canvas 2D 实现轻量雨雪效果(适合页面装饰)

适用于不需要 3D 深度、性能要求不高、兼容性优先的场景。核心是手动管理粒子数组,在 requestAnimationFrame 中更新位置并重绘。

  • 每个雨滴用一个对象表示:{ x, y, speed, length, opacity }y 每帧 += speed,超出画布底部就重置到顶部
  • 避免直接 clearRect(0,0,w,h) 全屏清空——会闪;改用半透明黑色覆盖(ctx.fillStyle = 'rgba(0,0,0,0.1)'; ctx.fillRect(0,0,w,h))模拟残影
  • 雪粒建议加轻微左右飘移(x += Math.sin(y * 0.01) * 0.5),并随机缩放(Math.random() * 1.5)增强真实感
  • 注意 Canvas 像素比:用 canvas.width = canvas.offsetWidth * window.devicePixelRatio 防止模糊
const canvas = document.getElementById('rain');
const ctx = canvas.getContext('2d');
canvas.width = canvas.offsetWidth * window.devicePixelRatio;
canvas.height = canvas.offsetHeight * window.devicePixelRatio;
ctx.scale(window.devicePixelRatio, window.devicePixelRatio);

const drops = []; for (let i = 0; i < 150; i++) { drops.push({ x: Math.random() canvas.offsetWidth, y: Math.random() -canvas.offsetHeight, speed: 5 + Math.random() 10, length: 8 + Math.random() 12, opacity: 0.4 + Math.random() * 0.6 }); }

function drawRain() { ctx.fillStyle = 'rgba(0,0,0,0.05)'; ctx.fillRect(0, 0, canvas.offsetWidth, canvas.offsetHeight);

drops.forEach(d => { ctx.beginPath(); ctx.moveTo(d.x, d.y); ctx.lineTo(d.x + 2, d.y + d.length); ctx.strokeStyle = rgba(200, 200, 255, ${d.opacity}); ctx.lineWidth = 1; ctx.stroke();

d.y += d.speed;
if (d.y > canvas.offsetHeight) {
  d.y = Math.random() * -50;
  d.x = Math.random() * canvas.offsetWidth;
}

}); }

function animate() { drawRain(); requestAnimationFrame(animate); } animate();

Three.js 做火焰/爆炸粒子(带物理与光照)

真正需要体积感、光影交互、碰撞反馈的火焰或爆炸,必须上 WebGL。Three.js 的 Points + ShaderMaterial 是主流方案,比纯 CPU 粒子(Sprite)性能高得多。

  • 别用 ParticleSystem(已废弃),改用 BufferGeometry + PointsMaterial 构建 GPU 粒子池
  • 火焰需动态顶点着色器:在 vertexShader 中用 sin(time * 2.0) 和噪声纹理扰动 position,模拟升腾扭曲
  • 关键参数:设 material.sizeAttenuation = true 让粒子随距离自动缩放;material.alphaTest = 0.5 避免半透边缘发虚
  • 性能陷阱:每帧修改 geometry.attributes.position.array 并调用 geometry.attributes.position.needsUpdate = true 会卡顿;应预分配足够大的 Float32Array,只更新数值,不重建 buffer

requestAnimationFrame 与粒子生命周期的同步问题

粒子死亡后若不及时从数组中剔除,会导致内存持续增长、遍历变慢,尤其在长时运行的特效中(如后台常驻雨效)。

  • 不要用 splice() 在循环中删除 —— 会跳过下一个元素;改用倒序遍历:for (let i = list.length-1; i>=0; i--)
  • 更推荐“对象池”模式:创建固定长度数组(如 new Array(500)),粒子死亡后标记 active = false,新粒子复用空闲槽位,避免频繁 push/pop
  • performance.now() 替代 Date.now() 计算粒子 age,精度更高(微秒级),避免时间跳跃导致批量死亡

移动端适配和性能断崖点

手机端粒子数超过 300 个就容易掉帧,尤其 Safari 对 Canvas 2D 的 fill/stroke 调用非常敏感。

  • 检测设备:用 navigator.userAgent.includes('Mobile')window.innerWidth 降级粒子数量(比如从 200 → 80)
  • iOS Safari 不支持 WebGL2 的部分扩展,火焰着色器里避免用 textureLodtexelFetch;改用 texture2D + 手动 mipmap 计算
  • 禁止在 touchmove 中触发粒子生成 —— 会阻塞滚动;改用 pointerdown + throttle 控制发射频率

粒子不是堆数量就有质感,关键是运动逻辑是否符合直觉:雨要垂直加速、雪要左右飘、火焰要有上升+膨胀+消散三阶段。所有“特效”背后都是对物理简化的取舍,先跑通单粒子行为,再批量,最后加随机扰动 —— 这比调一堆参数更快定位问题。