前言
经过上一篇文章的洗礼,相信大家已经成功进入粒子动画的大门了。
今天我们就来简单完成一个足够酷炫的动画粒子效果。在这章,我们将对粒子动画做一个初步的探索,其中不会有太多的shader代码,也不会用到太深的数学知识,仅仅是为了达到初步理解粒子动画如何构成的目的。
介绍
本章将完全跳过上一篇文章初学者学习THREE.js的一些心得 - 掘金 (juejin.cn)的所有包含到的基础内容,如果对本章学习感到困惑,请移步至上篇。
本章将讲述项目1的example1
example1:
由于找不到传视频的方式,只好截图了,如果有好奇的小伙伴可以点注脚里链接查看
有了上篇的基础,我们可以清晰感知到,这个动画无非是在一个圆点的效果上,增加了距离,以及圆点样式,以及一个不断向后移动的效果。
我们来一一解决
为了有距离,我们不能再给几何体内使用使用固定坐标,而要采用一种随机生成点位的策略,核心代码如下
const generatePointPosition = (i: number, positions: Float32Array) => {
const x = (Math.random() - 0.5) * 5;
const y = (Math.random() - 0.5) * 5;
const z = (Math.random() - 0.5) * 5;
const distance = Math.sqrt(x * x + y * y + z * z);
if (distance <= 2.5) { //如果距离小于等于半径,则该点在圆内
[positions[i * 3 + 0], positions[i * 3 + 1], positions[i * 3 + 2]] = [x, y, z]; //将该点的坐标存入points数组中
} else {
generatePointPosition(i, positions);
}
}
这段代码生了中心在(0,0,0)直径为5的圆球内任意小点的坐标。函数通过更改i可以给positions数组内任意一组坐标随机产生一个小点,数学逻辑则仅是根据三维坐标生成距离圆心位置。
(相信大家应该都跟我一样早就忘了这种数学公式了。。写的时候多亏了通义灵码补全了公式)。
接着我们仅需要生成count个点位,再把生成的点位放入几何体即可:
for (let i = 0; i < count; i += 1) {
generatePointPosition(i, positions);
}
sphereGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3))
以上我们解决了第一个问题,第二个问题圆点样式。
上篇中我们提到片着色器(fragmentShader)的作用就是给材质的面填充颜色,因此,我们可以直接在ShaderMaterial的片着色器下手。
uniform vec3 uColor;
uniform vec3 eColor;
void main() {
if (distance(gl_PointCoord, vec2(0.5, 0.5)) < 0.4){
gl_FragColor = vec4(uColor, 1.0);
return;
}
if (distance(gl_PointCoord, vec2(0.5, 0.5)) < 0.5){
gl_FragColor = vec4(eColor, 1.0);
return;
}
discard;
}
其中的uniform,我们在上篇中提到是由js传入的参数,这个两个数值类型都是三维向量,具体可以使用new THREE.Color()生成,需要的参数是一个类似#******形式的颜色值(*为[0-9 a-f])。
第一个if判断当前渲染点位(gl_PointCoord)和向量(0.5,0.5)之间的距离是否小于0.4,是则将渲染uColor,并直接返回。
第二个if判断是否小于0.5,是则渲染成eColor,同样返回。
这两步判断可以完成一个类似圆环的图案,最后我们将其他的部分都舍弃掉(discard),注意如果不舍弃,那么将依旧渲染这个色块,默认为黑色(可通过场景的clearColor属性改变)。
最后不断向后的效果实则为移动相机的z轴位置,结合上一章中提到的渲染函数,不难理解以下代码:
const tick = () => {
controls.update()
camera.position.y += (Math.random() - 0.5) * 0.001
camera.position.z += (Math.random()) * 0.01
// Render
renderer.render(scene, camera)
requestAnimationFrame(tick)
}
tick()
其中的y轴随机移动是为了让效果不至于太过生硬
至此我们已经完成了整个example1粒子动画效果,由于想让本文不至于太过枯燥,将在此处结束,如果跟着章节没有完成效果可以到Bayn-Web/three (github.com)查看源码。
Footnotes
-
网站来自这里(learn3d-neon.vercel.app)] ↩