1、粒子系统基础:什么是粒子系统、粒子系统的应用场景、Three.js粒子系统概述

什么是粒子系统?

粒子系统,说白了就是「用大量小点来模拟复杂效果」的技术。

我刚开始接触图形学的时候,觉得这玩意儿挺玄乎的。后来自己动手做了一遍,才发现原理其实很简单——你有一堆小点,每个点都有自己的位置、颜色、大小、速度。然后你让它们动起来,就形成了各种炫酷的效果。

每个粒子通常包含这些属性:

  • 位置:粒子在三维空间中的坐标
  • 颜色:可以是固定颜色,也可以随时间变化
  • 大小:粒子的视觉尺寸
  • 速度:运动方向和速率
  • 生命周期:粒子从出生到消亡的时间
  • 透明度:控制粒子的可见程度

你想想看,一个粒子确实没什么好看的。但几千个、几万个粒子同时运动,就能模拟出火焰、烟雾、星空、雨雪……这就是粒子系统的魅力。

核心思想:用大量简单元素的集体行为,模拟复杂自然现象。

粒子系统的应用场景

我在项目中用过不少粒子效果,这里列几个最常见的场景:

场景 描述 粒子数量参考
星空背景 静态或缓慢旋转的星空,常用于太空主题 1000-5000
火焰效果 粒子从底部升起,颜色从黄变红再变透明 500-2000
雨雪天气 大量粒子从天空下落,模拟降雨或飘雪 5000-20000
烟雾/雾气 粒子缓慢扩散,透明度逐渐降低 1000-5000
魔法/技能特效 粒子沿特定轨迹运动,常用于游戏 500-3000
数据可视化 用粒子展示数据分布或流动 10000-100000

嗯,这里要注意——不是粒子越多越好。我见过有人一上来就搞十万个粒子,结果手机端直接卡成PPT。要根据目标平台和效果需求来定。

Three.js粒子系统概述

Three.js 里做粒子系统,主要有两种方式:

1. Points(点云)

这是最常用的方式。Three.js 提供了 THREE.PointsTHREE.PointsMaterial,用起来非常方便。

// 创建一个最简单的粒子系统
const geometry = new THREE.BufferGeometry();
const positions = new Float32Array(1000 * 3);

for (let i = 0; i < 1000; i++) {
  positions[i * 3] = (Math.random() - 0.5) * 100;
  positions[i * 3 + 1] = (Math.random() - 0.5) * 100;
  positions[i * 3 + 2] = (Math.random() - 0.5) * 100;
}

geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));

const material = new THREE.PointsMaterial({
  color: 0xffffff,
  size: 0.5,
  transparent: true
});

const particles = new THREE.Points(geometry, material);
scene.add(particles);

这段代码干了什么?说白了就是:

  • 生成了1000个随机位置
  • 塞进 BufferGeometry 里
  • 用 PointsMaterial 控制外观
  • 最后加到场景中

个人经验:我习惯把粒子位置单独存一份副本,方便做动画更新。直接操作 geometry 的属性虽然也行,但频繁更新容易造成性能抖动。

2. Sprite(精灵)

如果你想让粒子显示为图片(比如星星、雪花),可以用 Sprite。每个 Sprite 是一个始终面向摄像机的平面。

// 使用纹理的粒子
const map = new THREE.TextureLoader().load('star.png');
const material = new THREE.SpriteMaterial({
  map: map,
  blending: THREE.AdditiveBlending
});

const sprite = new THREE.Sprite(material);
sprite.position.set(0, 0, 0);
scene.add(sprite);

不过说实话,几百个 Sprite 还行,上千个就开始吃力了。我建议超过 2000 个粒子还是用 Points 方案。

3. 自定义着色器(进阶)

如果你想要更炫的效果——比如粒子大小随距离变化、颜色渐变、扭曲变形——那就得自己写着色器了。

这个我们后面章节会详细讲,这里先提一嘴:

  • 顶点着色器控制粒子的位置和大小
  • 片元着色器控制粒子的颜色和透明度
  • 可以用纹理给粒子增加细节

避坑指南:我曾经在项目里直接用 PointsMaterial 做了一万个粒子,效果还行。后来客户要求加到五万个,帧率直接掉到 20fps。排查了半天,发现是材质里开了透明混合,而且每个粒子都单独计算了光照。关掉不必要的功能后,帧率回到了 60fps。

所以记住:粒子系统里,能关的功能就关掉。不需要光照就关掉 lighting,不需要深度测试就关掉 depthTest。

性能考量

做粒子系统,性能是绕不开的话题。我总结了几条经验:

  1. 合并几何体:所有粒子共用同一个 BufferGeometry,不要每个粒子单独创建
  2. 使用 BufferGeometry:比普通 Geometry 快得多
  3. 控制粒子数量:移动端建议不超过 10000,PC 端不超过 50000
  4. 关闭不必要的渲染特性:比如阴影、光照、雾效
  5. 使用 LOD:远处粒子可以变小或减少数量

一句话总结:粒子系统就是用「数量换效果」,但别忘了——数量上去了,性能就下来了。找到那个平衡点,才是真本事。

好了,这一章我们搞清楚了粒子系统是什么、能干什么、Three.js 里怎么用。下一章我会带大家手写一个完整的粒子星空效果,到时候咱们边写边聊。