ThreeJS 精通粒子特效

11 阅读4分钟

本文档涵盖了Three.js中粒子特效的关键概念和实现方法,基于实际代码示例进行讲解。

1. 粒子系统基础

1.1 点材质 (PointsMaterial) 设置

点材质是创建粒子特效的基础,可以通过多种参数配置粒子外观:

// 设置点材质
const pointsMaterial = new THREE.PointsMaterial();
pointsMaterial.size = 0.1;                           // 粒子大小
pointsMaterial.color.set(0xfff000);                 // 粒子颜色
pointsMaterial.sizeAttenuation = true;              // 是否根据相机深度衰减粒子大小
pointsMaterial.sizeAttenuation = true;              // 相机深度衰减

1.2 粒子纹理配置

为了增强粒子的视觉效果,通常会使用纹理:

// 载入纹理
const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load("./textures/particles/2.png");

// 设置点材质纹理
pointsMaterial.map = texture;                       // 纹理贴图
pointsMaterial.alphaMap = texture;                  // 透明度贴图
pointsMaterial.transparent = true;                  // 启用透明度
pointsMaterial.depthWrite = false;                  // 禁用深度写入
pointsMaterial.blending = THREE.AdditiveBlending;   // 混合模式

2. 粒子几何体创建

2.1 使用缓冲几何体 (BufferGeometry)

高效的粒子系统通常使用缓冲几何体来存储大量顶点数据:

// 创建粒子几何体
const particlesGeometry = new THREE.BufferGeometry();
const count = 5000;                                // 粒子数量

// 设置缓冲区数组
const positions = new Float32Array(count * 3);     // 位置数组
const colors = new Float32Array(count * 3);        // 颜色数组

// 设置顶点位置
for (let i = 0; i < count * 3; i++) {
  positions[i] = (Math.random() - 0.5) * 100;      // 随机位置
  colors[i] = Math.random();                        // 随机颜色
}

// 将属性添加到几何体
particlesGeometry.setAttribute("position", new THREE.BufferAttribute(positions, 3));
particlesGeometry.setAttribute("color", new THREE.BufferAttribute(colors, 3));

2.2 从现有几何体创建粒子

可以从现有的几何体(如球体)转换为粒子:

// 创建球几何体
const sphereGeometry = new THREE.SphereBufferGeometry(3, 30, 30);

// 删除UV属性(如果不需要纹理映射)
delete sphereGeometry.attributes.uv;

// 创建粒子系统
const points = new THREE.Points(sphereGeometry, pointsMaterial);
scene.add(points);

3. 星河粒子系统

3.1 基础星河效果

创建具有随机分布的星河效果:

// 生成星河粒子
const generateGalaxy = () => {
  geometry = new THREE.BufferGeometry();
  const positions = new Float32Array(params.count * 3);
  const colors = new Float32Array(params.count * 3);

  // 循环生成点
  for (let i = 0; i < params.count; i++) {
    // 当前的点应该在哪一条分支的角度上
    const branchAngel = (i % params.branch) * ((2 * Math.PI) / params.branch);

    // 当前点距离圆心的距离
    const distance = Math.random() * params.radius * Math.pow(Math.random(), 3);
    const current = i * 3;

    // 随机偏移
    const randomX = (Math.pow(Math.random() * 2 - 1, 3) * (params.radius - distance)) / 5;
    const randomY = (Math.pow(Math.random() * 2 - 1, 3) * (params.radius - distance)) / 5;
    const randomZ = (Math.pow(Math.random() * 2 - 1, 3) * (params.radius - distance)) / 5;

    // 计算最终位置
    positions[current] = Math.cos(branchAngel + distance * params.rotateScale) * distance + randomX;
    positions[current + 1] = 0 + randomY;
    positions[current + 2] = Math.sin(branchAngel + distance * params.rotateScale) * distance + randomZ;

    // 混合颜色,形成渐变色
    const mixColor = centerColor.clone();
    mixColor.lerp(endColor, distance / params.radius);

    colors[current] = mixColor.r;
    colors[current + 1] = mixColor.g;
    colors[current + 2] = mixColor.b;
  }

  geometry.setAttribute("position", new THREE.BufferAttribute(positions, 3));
  geometry.setAttribute("color", new THREE.BufferAttribute(colors, 3));

  // 设置点材质
  material = new THREE.PointsMaterial({
    size: params.size,
    sizeAttenuation: true,
    depthWrite: false,
    blending: THREE.AdditiveBlending,
    map: particlesTexture,
    alphaMap: particlesTexture,
    transparent: true,
    vertexColors: true,                             // 使用顶点颜色
  });

  points = new THREE.Points(geometry, material);
  scene.add(points);
};

4. 雪花粒子系统

4.1 多层雪花效果

创建多个层次的雪花粒子系统:

function createPoints(url, size = 0.5) {
  const particlesGeometry = new THREE.BufferGeometry();
  const count = 10000;

  // 设置缓冲区数组
  const positions = new Float32Array(count * 3);
  const colors = new Float32Array(count * 3);

  // 设置顶点
  for (let i = 0; i < count * 3; i++) {
    positions[i] = (Math.random() - 0.5) * 100;    // 在空间内随机分布
    colors[i] = Math.random();                      // 随机颜色
  }

  particlesGeometry.setAttribute("position", new THREE.BufferAttribute(positions, 3));
  particlesGeometry.setAttribute("color", new THREE.BufferAttribute(colors, 3));

  // 设置点材质
  const pointsMaterial = new THREE.PointsMaterial();
  pointsMaterial.size = size;                       // 不同大小的粒子
  pointsMaterial.color.set(0xfff000);
  pointsMaterial.sizeAttenuation = true;

  // 载入纹理
  const textureLoader = new THREE.TextureLoader();
  const texture = textureLoader.load(`./textures/particles/${url}.png`);

  pointsMaterial.map = texture;
  pointsMaterial.alphaMap = texture;
  pointsMaterial.transparent = true;
  pointsMaterial.depthWrite = false;
  pointsMaterial.blending = THREE.AdditiveBlending;
  pointsMaterial.vertexColors = true;               // 启用顶点颜色

  const points = new THREE.Points(particlesGeometry, pointsMaterial);
  scene.add(points);
  return points;
}

// 创建多层雪花效果
const points = createPoints("1", 1.5);
const points2 = createPoints("xh", 1);
const points3 = createPoints("xh", 2);

4.2 粒子动画

为粒子系统添加动画效果:

function render() {
  let time = clock.getElapsedTime();

  // 旋转动画
  points.rotation.x = time * 0.3;
  points2.rotation.x = time * 0.5;
  points2.rotation.y = time * 0.4;
  points3.rotation.x = time * 0.2;
  points3.rotation.y = time * 0.2;

  controls.update();
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}

5. 渲染器配置

5.1 基础渲染器设置

针对粒子系统优化渲染器:

// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);

// 开启场景中的阴影贴图
renderer.shadowMap.enabled = true;
renderer.physicallyCorrectLights = true;

// 将渲染器添加到DOM
document.body.appendChild(renderer.domElement);

6. 粒子系统优化技巧

6.1 混合模式

使用适当的混合模式提升视觉效果:

// 加法混合,常用于发光效果
pointsMaterial.blending = THREE.AdditiveBlending;

6.2 深度写入控制

控制粒子的深度写入行为:

// 禁用深度写入,避免粒子间的遮挡问题
pointsMaterial.depthWrite = false;

6.3 粒子大小衰减

根据距离调整粒子大小:

// 启用大小衰减,远处的粒子看起来更小
pointsMaterial.sizeAttenuation = true;

7. 控制器和辅助工具

7.1 轨道控制器

添加交互式视角控制:

// 创建轨道控制器
const controls = new OrbitControls(camera, renderer.domElement);

// 设置控制器阻尼,让控制器更有真实效果
controls.enableDamping = true;

// 添加坐标轴辅助器
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);

8. 响应式设计

处理窗口大小变化:

// 监听画面变化,更新渲染画面
window.addEventListener("resize", () => {
  // 更新摄像头
  camera.aspect = window.innerWidth / window.innerHeight;
  // 更新摄像机的投影矩阵
  camera.updateProjectionMatrix();

  // 更新渲染器
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 设置渲染器的像素比
  renderer.setPixelRatio(window.devicePixelRatio);
});

总结

本章详细介绍了Three.js中粒子特效的各个方面,包括:

  1. 粒子系统基础概念
  2. 点材质的配置和优化
  3. 缓冲几何体的使用
  4. 星河和雪花粒子系统的创建
  5. 粒子动画和交互
  6. 渲染优化技巧

通过合理运用这些技术,可以创建出丰富多彩的粒子特效,如星系、雪花、烟雾、火焰等视觉效果。关键在于理解粒子的几何体构建、材质配置以及性能优化方法,从而在保证视觉效果的同时维持良好的运行性能。