Unity3d 粒子光环制作

这一次,要参照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);
        }
    }
}

有其他更好的光环改进效果,欢迎在评论区中提出来

猜你喜欢

转载自blog.csdn.net/ShenDW818/article/details/80462134