糖尿病康复,内容丰富有趣,生活中的好帮手!
糖尿病康复 > 粒子编程初试——粒子光环制作

粒子编程初试——粒子光环制作

时间:2020-02-01 01:14:30

相关推荐

粒子编程初试——粒子光环制作

写在前面

实验参考博客:感谢指导! Unity3D学习笔记(9)—— 粒子光环Unity3d——ParticleSystem粒子光环堂上编程练习(有错误,仅作参考):Unity制作神奇的粒子海洋!

实验步骤

首先回顾粒子海洋的制作过程:

添加空对象并且添加粒子系统的部件简单调整一下粒子部件中的粒子材料(选个默认粒子材料就好,不要让其为空)写代码编程,挂到空对象上。并且将粒子系统部件拖入代码的公共变量中去。添加颜色渐变部件,手动修改颜色。。。。

所以其实对于粒子系统部件,我们不需要太多的操作,大部分的变化都是在代码中完成的,只要清楚各个属性对应的api。

粒子光环制作

首先添加一个空对象,并且添加部件ParticleSystem,然后简单设置一下属性:

还有发射器Render的属性,这里最重要就是选择材料!选择材料!选择材料!不然的话就会出现一堆粉紫色的小方块,不免太难看了:

至于其他的属性可以先不用管,我们开始编程:

粒子光环的属性

public ParticleSystem myparticleSystem;private ParticleSystem.Particle[] particleArray;private SingleParticle[] points;public Gradient grad;int count = 1000;public float size = 0.5f;public float minRadius = 3.0f;public float maxRadius = 6.0f;public bool rotate_way = false; // 决定圈扩大还是缩小private float rotate_speed = -1; // 颜色旋转速度(正负代表方向)public float speed = 0.5f; // 速度参数private float time = 0;

ParticleSystem myparticleSystem

首先最重要肯定是粒子系统本身,没有这个类又谈何粒子编程呢?ParticleSystem.Particle[] particleArray

其次是粒子数组,保存了每一个粒子的状态,这里需要规定一个数量count,也就是数组的大小,我设置为了1000.SingleParticle[] points

由于是光环,所以每个粒子的位置肯定需要一定规律地排序,而不是随机乱跑,所以这里记录了每个粒子对于整个光环的状态,两个最重要的属性角度与半径,因为每个粒子都是绕中心点运动,所以运动轨迹会有一个半径,运动到什么地方呢?就需要角度来记录。这里用到自己定义的一个类SingleParticle,稍后会说明。Gradient grad

颜色渐变器,Unity自带的渐变器,只要选定颜色变化的区间就能在有一段渐变的夜色。还有一些比较杂的变量属性:粒子大小,光环内径外径,转圈速度,旋转方向等。

粒子的位置属性:

public class SingleParticle {public float angle;public float radius;private float x = 0.0f;private float y = 0.0f;public void CalPosition() {float temp = angle / 180.0f * Mathf.PI;y = radius * Mathf.Sin(temp);x = radius * Mathf.Cos(temp);}public SingleParticle(float angle, float radius) {this.angle = angle;this.radius = radius;}public float getX() {return x;}public float getY() {return y;}}

主要是靠角度和半径来估算粒子所在的xy平面的面积,xy坐标就是靠基本的数学三角函数来计算出来。其中定义了一些外面能够调用的方法。

粒子系统初始化

在Start函数中,首先设置粒子系统的一些基本属性,如粒子数目等,这些需要在一开始就规定好并且不再改变。

void Start () {// myparticleSystem = this.GetComponent<ParticleSystem>();particleArray = new ParticleSystem.Particle[count];points = new SingleParticle[count];var m = myparticleSystem.main;m.startSpeed = 0;m.startSize = size;m.maxParticles = count;myparticleSystem.Emit(count);myparticleSystem.GetParticles(particleArray);Init();}

注意到代码第一行,对于粒子系统的赋值,我们可以直接通过GetComponent的方法来获取挂载在同一对象上的部件,但是这里我们用手动拖的方式,给脚本得公共变量赋值,好像更有体验感一点

然后就是各种初始化,新建一个粒子位置的数组,由于我们数量设置了1000,所以数组长度就是1000,除了这个数组外,还有粒子系统中的真正的粒子数组,设定size、最大粒子数、发射器发射数量,设置完之后还需要使用粒子系统Get一下,才能真正设置成功了。

这里有一个点值得注意的,就是旧版本里面通常使用ParticleSystem.startSize来设置,但是在新版中,需要先获取用一个变量获取ParticleSystem.main,再对main的startSize、maxParticles 进行设置。

其中,Init的函数就是作为粒子位置的初始化:

private void Init() {int i;for (i = 0; i < count; i++) {float midRadius = (minRadius + maxRadius) / 2.0f;float minRate = Random.Range(1.0f, midRadius / minRadius);float maxRate = Random.Range(midRadius / maxRadius, 1.0f);float radius = Random.Range(minRadius * minRate, maxRadius * maxRate);float angle = Random.Range(0.0f, 360.0f);points[i] = new SingleParticle(angle, radius);points[i].CalPosition();particleArray[i].position = new Vector3(points[i].getX(), points[i].getY(), 0f);}myparticleSystem.SetParticles(particleArray, particleArray.Length);}

通过内径和外径,中间划分一个分截,粒子分别在这两个部分中随机分布,角度则是360度随机。

然后就是每次Update时候的变化了:

void Update () {int i;int level = 10;for (i = 0; i < count; i++) {if (i % level < 3 || i % level > 6){points[i].angle -= rotate_speed * (i % level + 1) * speed;} else {points[i].angle += rotate_speed * (i % level + 1) * speed;}points[i].angle = (points[i].angle + 360.0f) % 360.0f; points[i].CalPosition();float value = Time.realtimeSinceStartup % 1.0f;value -= rotate_speed * points [i].angle /360.0f;while (value > 1)value--;while (value < 0)value ++;particleArray[i].startColor = grad.Evaluate(value);particleArray[i].position = new Vector3(points[i].getX(), points[i].getY(), 0.0f);}myparticleSystem.SetParticles(particleArray, particleArray.Length);}

每次更新都需要循环遍历1000个粒子,对于每个粒子的状态都做一次改变,像角度颜色等。具体操作如下

利用取模的方式将1000个粒子分为10层,每一层转动的角度(相当于速度)都略微不一样,然后又将整体分成3部分:第一部分和第三部分是同一个方向旋转,第二部分是另一个方向旋转。使得整体的转动效果不太单一。当然最后需要对增加后的角度取模,以免溢出360度,或者小于0度。最后利用粒子位置的类中的方法,算出xy坐标。然后是颜色的改变,首先我们需要利用渐变器进行颜色的调整,其实这一步也依然是可以通过代码来调整的,但是跟前面说的一样,~~增强体验感(其实是麻烦)~~使用手动调整的方法。首先看下渐变器的基本操作:

这个就是主体部分,可以看到一个类似进度条的东西,上下都有一些点,其中上方的点表示透明度的渐变(可以理解为亮度的变化),下方的点是颜色的选择,添加点只需要在对应空白的地方点击一下,删除点就需要点中某个点按删除键即可。

然后需要更改颜色就需要点击下方的color栏,然后选择适合的颜色,全部选择完毕之后就可以看到两个颜色点之间自动渐变。透明度也类似。

调整好之后就可以通过代码来选择其中的颜色,从0~1就是开始的颜色到最后的颜色了。

所以我们的想法是不仅颜色随着角度的变化而变化,而且要随着时间的变化而变化,所以需要对时间进行一个估算,以上代码中:

float value = Time.realtimeSinceStartup % 1.0f;value -= rotate_speed * points [i].angle /360.0f;while (value > 1)value--;while (value < 0)value ++;

这部分就是来计算的,首先利用实时时间,也就是程序运行的时间模上一个浮点数(注意是模浮点数,这样得出来的结果才会是浮点数),得到一个区间内的数,这里模1.0,说明颜色变化会在一秒内跑一圈,如果是模比一大的数,还需要进行归一化处理,也就是模多少就除以多少。

然后还需要加上当前角度归一化的结果,最后利用一个循环加减令其最终结果在0~1之间。用Gradient渐变器的Evaluate获取对应的颜色最后,最关键的一步当然就是将这些计算出来的颜色,和位置设置到粒子本身中去,SetParticles函数就是这里使用的。

好了大功告成之后看看效果吧~

基本效果

就看到光圈在转呀转~ 转呀转~

其实仔细看的话还是能够看到有的粒子慢有的粒子快,还能分出顺时针和逆时针变化。

改进版本

既然光转圈不过瘾,那么就来个放大缩小吧,转着转着就放大,有转着转着缩小,总比光转有趣多了吧。

那么就需要先利用几个变量来帮助我们:

public bool rotate_way = false; // 决定圈扩大还是缩小private float rotate_speed = -1; // 颜色旋转速度(正负代表方向)private float time = 0;

这是之前就定义了可是没有怎么用到的变量,首先需要知道什么是否放大,什么时候缩小,其次旋转的速度是可变的,就不会呆板的转圈,有必要还可以反方向转动。至于时间的话,作为一个计时器用,决定了放大缩小的时间。

好下面就来写代码吧!

在Update的开头加入以下代码:

time += Time.deltaTime;if (time < 10) {if (time < 5) {rotate_way = false;rotate_speed += 0.01f;}else {rotate_way = true;rotate_speed -= 0.01f;}} else {time = 0;rotate_speed = -1;}

总时长为10,然后分成两段,一段是放大,一段是缩小的,在此期间,旋转速度也做一点变化,随着时间增加或者减少,但是这个没有固定的变化规律,也就是说不一定增加的量和减少的量能够统一(值得改进),所以在每段时间结束的时候都需要进行一个reset处理,也就是将旋转速度回归原始状态,至于光环的大小就不一定了。。。

在对粒子属性的循环中,加入以下代码:

if (i % level > 5) {float tmp = rotate_way? 1 : -1;points[i].radius += tmp * 0.05f;}if (i % level <= 5) {float tmp = rotate_way? 1 : -1;points[i].radius += tmp * 0.052f;}

依然是将粒子分成两部分(还是熟悉的配方,不知道为什么这么执迷于分层),然后一部分圈半径改变的速度快一点,一部分改变得慢一点,其实差别不大,因为差别大了的话会出现断层的现象。

添加完之后看看效果:

感觉好很多了,不过这里有一点问题就是圈的扩大缩小过程是不对称的,而且因为是Update函数中计时执行,所以不同电脑也会有变化细节,但是总体的变化是一定的,就是放大缩小,然后转~~。

添加粒子轨迹

做到这里感觉还是不太好看,于是就自己东搞搞西搞搞,然后想到了轨迹这个东西,也就是说,让我们的粒子加上一条尾巴,看起来会不会好看一点呢?

首先在粒子系统的Render属性里面,添加轨迹材料(别忘了设置,不然就是很丑的粉紫色长条):

然后再轨迹的选项里,调整一下参数:

重点调整一下轨迹与粒子的大小比例,还有轨迹寿命,也就是轨迹能拖多长。

设置好之后就运行看看效果吧。

看起来酷炫多了!

最后总结一下,其实这个编程有一些bug,也就是之前提到了变化过程不是对称的,也就是有的变化不可逆,可能变着变着就和原来的有很大区别了,这也是需要不断调整参数,不断研究的一点,不过鉴于粒子编程太多可钻研的了,同时也有大量的资源、插件可使用,这一点也不必太担心吧。

如果觉得《粒子编程初试——粒子光环制作》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。