Threejs中粒子实现【19】

455 阅读2分钟

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


在三维场景中,我们可以通过粒子实现烟花,星空,雨滴等炫酷效果,每颗粒子都是由两个三角面片构成的;本案例实现如封面动图效果;

step 1 创建粒子

材质上sizeAttenuation属性表示粒子是否近大远小效果,默认是打开的

/**
 * Objects
 */
 // 创建geometry
 const geometry = new THREE.BufferGeometry();
// Material
const pointMaterial = new THREE.PointsMaterial({
    // 设置大小
   size: 0.02,
    // 设置颜色
   color: new THREE.Color('#fff'),
    
                        
})
// 设置粒子数量
const count = 5000;
// 存放粒子位置信息
const posAttribute = new Float32Array(count * 3)
// 每一个位置信息中包含 xyz三个轴的坐标,所以存放位置时数组的长度为原有的粒子长度*3
for (let i = 0; i <= count * 3; i++) {
    // Math.random()的随机数为0-1,则Math.random() - 0.5的随机数为-0.5-0.5之间,根据自己需要展示的范围*对应的数字
    posAttribute[i] = (Math.random() - 0.5) * 10
}
// 为geometry设置计算所得的坐标信息
geometry.setAttribute('position', new THREE.BufferAttribute(posAttribute, 3))
// 创建粒子
const point = new THREE.Points(geometry, pointMaterial)
// 添加至场景中 
scene.add(point)

完成步骤一,我们可以得到图下效果

image.png

step 2 为粒子添加合适的贴图

贴图网址:
在这里放了下图贴图下载的网址,按需使用; image.png

材质中几个需要特别说明的属性
depthTest: 深度测试,WGL绘制时,会测试那个粒子更靠前,在其后的粒子不会被绘制,前面的会被绘制,也应用于其他Mesh中;
depthWrite: 有一个叫做深度缓冲区的地方,如果将该属性修改为false,则模型不会进入深度缓冲区中,也不会被深度监听了;
blending: 混合模式,THREE.AdditiveBlending为相加混合,默认为NormalBlending,也就是法线混合;

// 为材质中增加了一些属性
const pointMaterial = new THREE.PointsMaterial({
    // 怕贴图看不清改变了大小
    size: 0.2,
    color: new THREE.Color('#fff'),
    // alphaMap贴图 因为我们的图片是黑白图,用alpha可以实现透明
    alphaMap: texture1,
    // alphaMap贴图捆绑实现
    transparent: true,
    // 修复边界遮挡问题
    depthWrite: false,
    blending: THREE.AdditiveBlending,
  
})

此时效果如下图,我设置了一个❤的贴图

image.png

step 3 为粒子添加随机色

// 颜色也是三位 
for (let i = 0; i <= count * 3; i++) {
    posAttribute[i] = (Math.random() - 0.5) * 10
    colorAttribute[i] = Math.random()
}
// 属性设置
geometry.setAttribute('color', new THREE.BufferAttribute(colorAttribute, 3))
// 需要去除调原有的颜色设置
const pointMaterial = new THREE.PointsMaterial({
   // color: new THREE.Color('#fff'),
   // 打开顶点着色器
   vertexColors: true
})
image.png

step 4 将粒子展开平铺

// 获取clock 只是为了拿到一个稳定的累加数字
const clock = new THREE.Clock();
let num = clock.getElapsedTime()
// 重置Y轴坐标
for (let i = 0; i <= count; i++) {
     let numI = i * 3;
     const x = geometry.attributes.position.array[numI + 0]
     geometry.attributes.position.array[numI + 1] = Math.sin(num+x)
 }
 // 打开位置更新
geometry.attributes.position.needsUpdate = true;

基本效果已经实现 image.png

step 4 为粒子添加自动旋转动画

通过render中方法实现

function renderScene() {
    let num = clock.getElapsedTime()
    // 不断更新y轴旋转值
    point.rotation.y = num * 0.02
    // 更新轨道控制 实现鼠标可操控
    controls.update();
    requestAnimationFrame(renderScene)
    renderer.render(scene, camera)
    }

如果有哪里描述不准确或者有问题,欢迎大佬指正!
(≖ᴗ≖)✧