这是一篇系列教程,在这篇教程里我将带领你一步步地实现一个基于three.js的webgl粒子系统Particle System。

粒子系统主要用来实现如:液体,光,烟雾,爆炸等视觉效果。借助大量的粒子之间的物理运动来模拟现实世界的视觉效果,每个粒子都被赋予了自己的生命周期,速度,加速度等参数,就像是一个训练有素的士兵根据系统发出的指令来完成自己的使命。

下图是我在blender中用内置的粒子系统实现的效果,通过大量的粒子实现液体撞击效果,看到这里你是不是对粒子有了一定的概念了呢。

我们知道通过大量的粒子运动可以模拟出很多物理效果,但这也增加了处理器的计算负担,导致帧率下降。为了给处理器减负,聪明的程序员发明了基于公告牌billboard技术的粒子系统,并在3D游戏中得到了广泛的应用,公告牌系统中每个粒子都是一个面向摄像机的平面贴图,这大大减少了需要计算的顶点数量,而且由于贴图始终面向摄像机,用户也不会有突兀感。

在three.js使用THREE.Sprite来创建面向摄像机的贴图,这次我们Sprite来创建一个简单的粒子效果场景。

先创建200个Sprite对象相对场景中心点旋转,你会看到这些粒子始终朝向摄像机,即使只是一个贴图也不会觉得有什么不自然。

_initParticles() {
    this.particleGroup = new THREE.Group()
    this.particleAttributes = {
      startSize: [],
      startPosition: [],
      randomness: []
    }
    const particleNum =  200
    const particleTex = new THREE.TextureLoader().load('img/spark.png')
    for(let i = 0; i < particleNum; i++) {
      const spriteMaterial = new THREE.SpriteMaterial({ 
        map: particleTex, 
        color: 0xffffff,
        blending: THREE.AdditiveBlending,
        sizeAttenuation: true
      })
      const sprite = new THREE.Sprite(spriteMaterial)
      sprite.scale.set(32, 32, 1)
      sprite.position.set(
        Math.random() - 0.5,
        Math.random() - 0.5,
        Math.random() - 0.5
      )
      sprite.position.setLength(this.params.radiusRange * (Math.random() * 0.2 +0.8))
      sprite.material.color.setHSL(Math.random(), 0.9, 0.7)
      sprite.material.opacity = 0.9
      sprite.material.transparent = true
      
      this.particleGroup.add(sprite)
      this.particleAttributes.startPosition.push(sprite.position.clone())
      this.particleAttributes.randomness.push(Math.random())
    }
    this.particleGroup.position.y = 50
    this.scene.add(this.particleGroup)
 }

点击下图可以在浏览器中查看效果,下次我们正式开始创建粒子系统,下次见!