Three.js(21)——粒子

318 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第22天,点击查看活动详情 >>

粒子可以被用来创建星星、烟雾、雨滴、灰尘、火焰等等。我们可以使用合理的帧速率来创建数千个粒子。每个粒子都是由始终面向摄影机的平面(俩个三角形)组成的。

创建粒子

创建粒子和创建网格很像,不同的是粒子使用的材质是点材质PointsMaterial和点实例Points。 下面代码为例,当实例化球缓冲几何体时,该几何体的每个顶点都将成为粒子。


/**
 * 粒子
 */
const particlesGeometry = new THREE.SphereBufferGeometry(1,32,32)
const particlesMaterial = new THREE.PointsMaterial({
    //点的大小
    size:0.02,
    //开启尺寸衰减,当相机靠近时粒子变大,当相机远离时粒子变小
    sizeAttenuation:true})
const particles = new THREE.Points(particlesGeometry,particlesMaterial)
scene.add(particles)

微信截图_20220829091626.png

创建500个粒子

需要用到自定义几何体:

const particlesGeometry = new THREE.BufferGeometry()
const count = 500
const positions = new Float32Array(count*3)
for(let i = 0;i<count*3;i++){
    positions[i] = (Math.random()-0.5)*10
}
particlesGeometry.setAttribute('position',new THREE.BufferAttribute(positions,3))

可以得到类似星空的效果:

微信截图_20220829091733.png

颜色

可以通过点材质PointsMaterial的color属性改变粒子颜色:

particles.material.color = new THREE.Color('#bbffaa');

材质

const textureLoader = new THREE.TextureLoader()
const particleTexture = textureLoader.load('./img/particles/2.png')
particlesMaterial.map = particleTexture

可以发现粒子贴图挡住了后面的粒子,因此我们可以设置为将map属性改为alphaMap属性,记得开启transparent。

particlesMaterial.transparent = true
particlesMaterial.alphaMap = particleTexture

可以发现设置为alphaMap后,粒子的边缘还是存在遮挡,这是因为粒子的绘制顺序与它们的创建顺序相同,而WebGL并不知道哪一个在另一个之前。当然有好几种方法可以修复该现象:

1.设置alphaTest

alphaTest是一个介于0和1之间的值,它使WebGL能够知道根据像素的透明度什么时候不去渲染该像素。默认情况下,该值为0表示无论如何都会渲染该像素。

// 将alphaTest设为0.001
particlesMaterial.alphaTest = 0.001

2.设置depthTest

当WebGL绘制粒子时,WebGL会测试正在绘制的粒子哪个更靠前,在其后面的粒子不会被绘制,在其前面的粒子会被绘制,这就造成了混乱。这被称为深度测试,可以通过alphaTest停用depth testing。

// particlesMaterial.alphaTest = 0.001
particlesMaterial.depthTest = false

3.设置depthWrite

正在绘制的深度被存储在一个称为深度缓冲区的位置,作为不测试粒子是否比深度缓冲区中的粒子更近的替代方案,我们可以告诉WebGL不要使用深度测试depthTest去往深度缓冲区中写入粒子。

// particlesMaterial.alphaTest = 0.001
// particlesMaterial.depthTest = false
particlesMaterial.depthWrite = false

4.blending属性

WebGL当前是在一个像素顶部绘制另一个像素,然后我们通过设置blending混合属性为THREE.AdditiveBlending,可以告诉WebGL将像素的颜色添加到已经绘制完的像素的颜色上去,这样不同像素的颜色将会混合到一块而不是说处于前面的像素颜色会覆盖掉后面的像素颜色。

// particlesMaterial.alphaTest = 0.001
// particlesMaterial.depthTest = false
particlesMaterial.depthWrite = false
particlesMaterial.blending = THREE.AdditiveBlending

为每个粒子设置不同颜色

与设置随机位置一样道理,不够这次数组里放的不是位置xyz的值,而是颜色rgb的值,然后几何体通过setAttribute方法设置color属性:

const colors = new Float32Array(count*3)
for(let i = 0;i<count*3;i++){
    ......
    colors[i]=Math.random()
}
particlesGeometry.setAttribute('color',new THREE.BufferAttribute(colors,3))

之后设置材质的vertexColors属性为true开启顶点着色:

particlesMaterial.vertexColors = true

最终效果

微信截图_20220829092756.png