这一次,要参照I Remember网站开始界面的那个光环,用粒子系统做一个类似的光环,当然,我做的没网站上的那么好看,就,增加一点儿自己的东西吧。
首先,来看一下成品图:
图中有两个环,它们转的方向相反,但每个环的粒子数都是一样的,同时还会有颜色的变化(这里设置了五种颜色轮流变换)。整个环由一个粒子系统生成,通过每一帧设定每个粒子的位置来达到粒子在旋转这一效果。
粒子的位置通过公式:x = cos(t); y = sin(t)来确定。
制作步骤
步骤一:
在场景中建立一个空对象(ParticleSystem),并在对象内新建一个粒子系统(ring):
步骤二:
新建一个C#脚本,命名为myRing,并将其挂载在ring上。
步骤三:
下面,就是用脚本对粒子的行为进行控制。
首先,提供下面的一些共有变量,使得我们可以在外部通过更改这些参数来设定光环的属性。
public ParticleSystem particleSystem; //粒子系统对象
public int particleNumber = 5000; //发射的最大粒子数
public float pingPong = 0.05f;
public float size = 0.05f; //粒子的大小
public float maxRadius = 10f; //粒子的旋转半径
public float minRadius = 4.0f;
public float speed = 0.05f; //粒子的运动速度
另外,我们还需要对每个粒子进行处理,所以,需要存储粒子本身,以及他们的每个粒子的运动半径和位置偏转角。
private float[] particleAngle;
private float[] particleRadius;
private ParticleSystem.Particle[] particlesArray;
在Start函数里面将要获得的组件和需要申请的内存都处理好后,就可以开始对粒子的初始位置进行设定了,通过随机生成粒子的夹角,半径,然后根据圆的极坐标公式表示,就可以将很多粒子排列成一个圆的样子了。
void init()
{
//对于每个粒子
for (int i = 0; i < particleNumber; i++)
{
//随机生成角度
float angle = Random.Range(0.0f, 360.0f);
//换回弧度制
float rad = angle / 180 * Mathf.PI;
//设定粒子的旋转半径
float midRadius = (maxRadius + minRadius) / 2;
float rate1 = Random.Range(1.0f, midRadius / minRadius);
float rate2 = Random.Range(midRadius / maxRadius, 1.0f);
float r = Random.Range(minRadius * rate1, maxRadius * rate2);
//设定粒子的大小
particlesArray[i].size = size;
particleAngle[i] = angle;
particleRadius[i] = r;
//放置粒子
particlesArray[i].position = new Vector3(r * Mathf.Cos(rad), r * Mathf.Sin(rad), 0.0f);
}
}
至于角度那里,为什么要先生成角度制,再转回弧度制,大家可以自己去试验一下,直接用弧度制弄出来的环,放在舞台效果上还是不错的,但并不是我们这里所需要的那种光环。此时Start函数如下:
void Start()
{
particleSystem = GetComponent<ParticleSystem>();
particlesArray = new ParticleSystem.Particle[particleNumber];
particleSystem.maxParticles = particleNumber;
particleAngle = new float[particleNumber];
particleRadius = new float[particleNumber];
particleSystem.Emit(particleNumber);
particleSystem.GetParticles(particlesArray);
init();
particleSystem.SetParticles(particlesArray, particlesArray.Length);
}
到这一步后,我们运行一下,发现,刚开始时,粒子生成的已经是圆环的形状了,如下图,但随后粒子又会散开来。
为了让粒子保持圆环的形状,我们还要在Update函数上作处理,让粒子按一定的方向和角度进行旋转。为了模拟有两个环,且两个环旋转方向不同这一效果,决定将粒子平分为两类,一类顺时针旋转,一类逆时针旋转。此时Update函数如下:
void Update()
{
for (int i = 0; i < particleNumber; i++)
{
if (i % 2 == 0)
{
particleAngle[i] += speed;
}
else
{
particleAngle[i] += speed;
}
particleAngle[i] = (particleAngle[i] + 360) % 360;
float rad = particleAngle[i] / 180 * Mathf.PI;
particlesArray[i].position = new Vector3(particleRadius[i] * Mathf.Cos(rad), particleRadius[i] * Mathf.Sin(rad), 0f);
}
particleSystem.SetParticles(particlesArray, particleNumber);
}
这时,圆环已经有点像样了,生成如下:
但是,现在这样,看起来还是有点死板,于是,我们可以再做下面这些改进:
1、设置不同的粒子旋转的速度不一样;
2、给粒子增加抖动效果
3、给粒子增加点色彩。
步骤四:
使不同的粒子旋转的速度不一样,只需要在粒子速度的增量那里作一点儿处理,使得粒子的速度分为十个级别。处理如下:
if (i % 2 == 0)
{
particleAngle[i] += speed * (i % 10 + 1);
}
else
{
particleAngle[i] -= speed * (i % 10 + 1);
}
而使粒子增加抖动效果,可以使用PingPong方法,该方法可以使得值在范围内来回变动,具体可查看帮助文档。首先,增加一个时间计数器,用来记录粒子的运动时间。
public float pingPong = 0.05f;
private float time = 0;
然后,将下面的代码放入Update的for循环里面:
time += Time.deltaTime;
particleRadius[i] += (Mathf.PingPong(time / minRadius / maxRadius, pingPong) - pingPong / 2.0f);
最后,就是为粒子增加颜色,首先,需要添加一个时钟来记录颜色的维持时间,以方便转换颜色,并且用一个颜色数组来记录所有可变换的颜色。
private Color[] changeColor = { new Color(255, 255, 255), new Color(255, 0, 0),new Color(255, 255, 0), new Color(0, 255, 0), new Color(0, 0, 255) };
private float colorTimeOut = 0;
然后,在Update函数中加入下面两条语句。其中,①语句在for循环外,②语句在for循环内部。
colorTimeOut += Time.deltaTime; //①
particlesArray[i].color = changeColor[(int)(colorTimeOut % 5)]; //②
此时,我们的圆环就算是完成了,如下:
改进:
虽然,圆环已经出来了,但是,我们可以看到,圆环很暗,在红色和蓝色的时候,几乎看不见环了,所以,为了让环清晰一点,我们可以让环发光。这时,只需要用到Glow11插件即可。
首先,得去下载Glow11插件,然后,通过Assets -> Import Package->Custom Package,找到Glow11插件,将其导入。
然后,选定摄像机,在Inspector面板中,在Add Component处,找到Glow11脚本,将其增加到摄像机的Inspector面板中(记得在脚本那里打钩)。
最后,选定粒子系统,将其Renderer处的Material改成Default-Material即可。
这时候再运行,光环就成文章开头那样子了,看起来也舒服了许多。
源代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MyRing : MonoBehaviour {
public ParticleSystem particleSystem; //粒子系统对象
public int particleNumber = 5000; //发射的最大粒子数
public float pingPong = 0.05f;
public float size = 0.05f; //粒子的大小
public float maxRadius = 10f; //粒子的旋转半径
public float minRadius = 4.0f;
public float speed = 0.05f; //粒子的运动速度
private float[] particleAngle;
private float[] particleRadius;
private float time = 0;
private ParticleSystem.Particle[] particlesArray;
private Color[] changeColor = { new Color(255, 255, 255), new Color(255, 0, 0),new Color(255, 255, 0), new Color(0, 255, 0), new Color(0, 0, 255) };
private float colorTimeOut = 0;
void Start()
{
particleSystem = GetComponent<ParticleSystem>();
particlesArray = new ParticleSystem.Particle[particleNumber];
particleSystem.maxParticles = particleNumber;
particleAngle = new float[particleNumber];
particleRadius = new float[particleNumber];
particleSystem.Emit(particleNumber);
particleSystem.GetParticles(particlesArray);
init();
particleSystem.SetParticles(particlesArray, particlesArray.Length);
}
void Update()
{
colorTimeOut += Time.deltaTime;
for (int i = 0; i < particleNumber; i++)
{
time += Time.deltaTime;
particlesArray[i].color = changeColor[(int)(colorTimeOut % 5)];
particleRadius[i] += (Mathf.PingPong(time / minRadius / maxRadius, pingPong) - pingPong / 2.0f);
if (i % 2 == 0)
{
particleAngle[i] += speed * (i % 10 + 1);
}
else
{
particleAngle[i] -= speed * (i % 10 + 1);
}
particleAngle[i] = (particleAngle[i] + 360) % 360;
float rad = particleAngle[i] / 180 * Mathf.PI;
particlesArray[i].position = new Vector3(particleRadius[i] * Mathf.Cos(rad), particleRadius[i] * Mathf.Sin(rad), 0f);
}
particleSystem.SetParticles(particlesArray, particleNumber);
}
void init()
{
//对于每个粒子
for (int i = 0; i < particleNumber; i++)
{
//随机生成角度
float angle = Random.Range(0.0f, 360.0f);
//换回弧度制
float rad = angle / 180 * Mathf.PI;
//设定粒子的旋转半径
float midRadius = (maxRadius + minRadius) / 2;
float rate1 = Random.Range(1.0f, midRadius / minRadius);
float rate2 = Random.Range(midRadius / maxRadius, 1.0f);
float r = Random.Range(minRadius * rate1, maxRadius * rate2);
//设定粒子的大小
particlesArray[i].size = size;
particleAngle[i] = angle;
particleRadius[i] = r;
//放置粒子
particlesArray[i].position = new Vector3(r * Mathf.Cos(rad), r * Mathf.Sin(rad), 0.0f);
}
}
}
有其他更好的光环改进效果,欢迎在评论区中提出来