Threejs官例解析,粒子系统(一)

前两天写粒子的时候发现,目前版本(r106)里的粒子都是用THREE.Points来生成的,这个类十分的简单。

这个类本身是用来生成点的,也就是说,用它只是生成了一堆的点,这个类简单到自己的函数只有俩,(即不算父类继承的),这在我眼里根本不能算是粒子系统,只能说有粒子 = = 。

我心里的粒子系统,是要有粒子发射器,粒子控制和管理的,然鹅,一个Point并不够啊~~~!!

Three里面原本应该是有粒子系统的,不知道为什么删掉了,变成了现在的样子。
在这里插入图片描述

好在我左刨刨,右刨刨,在例子里面发现了一个这样的案例。

晕~我刚刚去查官方案例,已经被删除了,我下载的案例包里还是有的,github上的代码也被移除了。难道因为版权么?

在这里插入图片描述
这个和我心里面的粒子系统是比较接近的,当然和大型引擎的没法比,不过自己改改还是可以的,好多参数可以调。
在这里插入图片描述

我看了一下这个JS,核心代码500行,不算多,里面还包括shader,注释,还有一些我注释掉了也没啥变化的代码。可能是机器性能在提升,所以之前能够提升性能现在不明显了么?不是太确定,先留个尾巴吧。

在这个例子里面,主要有两个js,一个是核心处理代码GPUParticleSystem.js,一个调用代码webgl_gpu_particle_system.js。

先看调用代码 webgl_gpu_particle_system.js

调用也不复杂,一个new,两个option,外加update里面的一些更新操作。

先是new一个system出来。

particleSystem = new THREE.GPUParticleSystem( {
 maxParticles: 250000,
 } );

两个option,可以配合GUI来实时改变一些参数。

options = {
 position: new THREE.Vector3(), 
 positionRandomness: .3,
 velocity: new THREE.Vector3(),
 velocityRandomness: .5,
 color: 0xaa88ff,
 colorRandomness: .2,
 turbulence: .5,
 lifetime: 2,
 size: 5,
 sizeRandomness: 1,
 smoothPosition:true
 };
spawnerOptions = {
 spawnRate: 15000,
 horizontalSpeed: 1.5,
 verticalSpeed: 1.33,
 timeScale: 1
 };

宽泛的说,上面一个options 是控制微观粒子为主,下面一个spawnerOptions 是控制宏观系统为主。

position:控制整个粒子系统的运行轨迹

positionRandomness:控制粒子位置的扰动程度,数值越大,扰动的程度越大,数值越小,位置越集中

velocity:这个速度是每个粒子所拥有的速度,代码里有一个maxVel变量为2,个人推测这个值不应该超过这个值,不过超过也不会报错,效果有点,狂野,粒子的速度越大,每一帧的刷新都可能离前一个位置越远,因此粒子间会更加的分散。下面是速度为v3(3,3,3)的效果。

在这里插入图片描述
velocityRandomness:速度的干扰系数

color:粒子颜色值

colorRandomness:颜色值的干扰系数

turbulence:摆尾的干扰值,越大尾巴摆的越欢实。

lifetime:粒子的生命时长

size:粒子大小

sizeRandomness:大小的干扰

smoothPosition:位置平滑开关,如果速度过大,会出现后面的点跟不上前面点的情况,出现明显的断点,如下图,这时候稍微平滑一下有助于改善这种状况,不过亲测效果不是很明显。
在这里插入图片描述

spawnRate:控制显示的粒子的数量,下图分别是1500,和30000的效果。

在这里插入图片描述
在这里插入图片描述
horizontalSpeed:水平移动速度

verticalSpeed:垂直移动速度

速度越大,下一帧的粒子群较上一帧的粒子群位置变换越大,造成走完整个路径的时间缩短,视觉感觉变快,速度过大,可造成粒子断点的现象。如往上数倒数第3张。

timeScale:控制时间的速度,数值大,时间变快,视觉上速度变快,数值小,时间慢,速度慢,小于0会倒退,也很有趣。

更新操作在function animate()里面,主要代码如下:

var delta = clock.getDelta() * spawnerOptions.timeScale;
 tick += delta;

 if ( tick < 0 ) tick = 0;

 if ( delta > 0 ) {

 options.position.x = Math.sin( tick * spawnerOptions.horizontalSpeed ) * 20;
 options.position.y = Math.sin( tick * spawnerOptions.verticalSpeed ) * 10;
 options.position.z = Math.sin( tick * spawnerOptions.horizontalSpeed + spawnerOptions.verticalSpeed ) * 5;
 
 for ( var x = 0; x < spawnerOptions.spawnRate * delta; x ++ ) {

 // Yep, that's really it. Spawning particles is super cheap, and once you spawn them, the rest of
 // their lifecycle is handled entirely on the GPU, driven by a time uniform updated below

 particleSystem.spawnParticle( options );

 }

 }

 particleSystem.update( tick );

delta:clock.getDelta()在每次更新中获得时间间隔,我console的结果是在0.016上下浮动。乘以时间伸缩量“scale”就是当前这帧所需要的时间间隔。

tick: 记录从开始运行到当前帧的总时间。包括时间“scale”在内。

options.position:根据时间和速度进行更新,sin的值域范围在-1到1之间,所以xyz的值分别限定在±20,±10,±5。

看一下这个for循环,是一个很有意思的地方。

spawnerOptions.spawnRate按照默认的配置是在400-600之间,也就是说,每次只更新这些个粒子的位置。还有一些粒子的位置是之前或者之后更新的。

比如说我总共想实例化250000个粒子,每次改变500个粒子的位置,假设500个是一组,那么一共改变500次才能把所有粒子动一遍,而运行到第100次的时候,会出现一条粒子线,前20个会因为过了2秒的生命周期而看不见,20-40的会因为生命周期所剩不多而变得透明,其余的400个会因为还没动而留在原地。(数字只是举例,不准确)大概是这个意思。

如果 spawnRate 这个值变小,那么一组粒子的数量会变少,可能是200个,生命周期一样的情况下,分组总数变多,但是在2秒以内的组数还是那么多,看起来粒子的数量就变少了。

particleSystem.spawnParticle( options ); 用来更新粒子的位置颜色等信息。

particleSystem.update( tick ); 传入总时间,并在GPU中计算每个粒子当前时间的状态。

下一篇会写一些,自己看GPUParticleSystem的体会。先挖个坑~ 哈哈

核心代码部分,请见粒子(二)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值