Unity3D-粒子光圈

参考http://i-remember.fr/en使用unity3d制作白色光圈效果。这里先附上最终效果图:


首先分析一下该网站中的光圈,它是由内外两个光圈一起构成的。内部光圈有缺口,转的速度比较慢,但确实是在顺时针转动。而外光圈则相反,没有缺口,转动的速度也快很多。所以对于这整个效果,分为内外两个部分,代码大致相同。

第一步:基本框架

首先创建一个新项目,这里命名为Halo。将摄像机背景设为全黑之后。添加空游戏对象Halo,它有两个子对象,分别为InnerHalo和OuterHalo,结果如图:


给两个子对象添加ParticleSystem组件,并设置如下数据:

两个对象设置相同,这里就不重复贴图了。

第二步:设置光圈粒子类

创建C#脚本HaloParticle并实现HaloParticle类,方便后续对光圈粒子的处理

public class HaloParticle {
	public HaloParticle(float r = 0, float a = 0) {
		radius = r;
		angle = a;
	}
	public float radius {
		get;
		set;
	}
	public float angle {
		get;
		set;
	}
}

第三步:外光圈的实现

两个光圈的代码大致相同,先从比较简单的外光圈入手。创建OuterHalo脚本,对于外光圈,需要属性包括粒子系统、最大最小半径、粒子总数以及一个HaloParticle数组存粒子状态,如下:

	public ParticleSystem _particle_system;
	private ParticleSystem.Particle[] _particle_array;
	private int _halo_resolution = 3000;
	private float _min_radius = 2F;
	private float _max_radius = 4.5F;
	private HaloParticle[] _halo_particle;
之后在开始时完成初始各个粒子的位置。注意到这里所有的粒子都是贴近扇道中心部分,到边缘时粒子数目较少。所以在使用随机数时应使其在平均半径处概率最高,代码实现如下:

void Start () {
        _particle_system = this.GetComponent<ParticleSystem> ();
        _particle_array = new ParticleSystem.Particle[_halo_resolution];
        _halo_particle = new HaloParticle[_halo_resolution];
        _particle_system.maxParticles = _halo_resolution;
        _particle_system.Emit (_halo_resolution);
        _particle_system.GetParticles (_particle_array);
        for (int i = 0; i < _halo_resolution; ++i) {
                //粒子半径,添加一个偏移量,使粒子集中于平均半径处
                float shiftMinRadius = Random.Range(1, ((_max_radius + _min_radius) / 2) / _min_radius);
                float shiftMaxRadius = Random.Range(((_max_radius + _min_radius) / 2) / _max_radius, 1);
                float radius = Random.Range (_min_radius * shiftMinRadius, _max_radius * shiftMaxRadius);


                //粒子角度
                float angle = Random.Range (0, Mathf.PI * 2);


                _halo_particle [i] = new HaloParticle (radius, angle);
                _particle_array [i].position = new Vector3 (radius * Mathf.Cos (angle), radius * Mathf.Sin (angle), 0);
        }
        _particle_system.SetParticles (_particle_array, _particle_array.Length);
}
这时将脚本添加到外光圈对象,此时效果如下:


下一步得让这玩意动起来,在Update函数中,添加代码使每帧旋转一定角度即可,注意到原网站中速度不是恒定不变的,这里用一个随机数来使旋转速度有一定变化。代码如下:

	void Update () {
		for (int i = 0; i < _halo_resolution; ++i) {
			_halo_particle [i].angle -= Random.Range(0, 1F / 360);
			_particle_array [i].position = new Vector3 (_halo_particle [i].radius * Mathf.Cos (_halo_particle [i].angle), _halo_particle [i].radius * Mathf.Sin (_halo_particle [i].angle), 0);
		}
		_particle_system.SetParticles (_particle_array, _particle_array.Length);
	}
效果如图:


这样外光圈部分基本完成。

第四步:内光圈实现

内光圈和外光圈大体相同。先创建一个InnerHalo脚本并将代码复制进去,考虑到内光圈有两个缺口,这两个缺口在一个角度上,所以只需在初始化粒子位置时,使粒子尽可能向另外的两个角度即π/4和5π/4聚集就好。考虑对称性,只需实现一半,再用一个1/2的概率使角度减少π即可。这里实现[π,2π]。考虑5π/4太麻烦,就实现3π/2再将角度减去π/4即可。代码如下:

//粒子角度,添加一个偏移量,使粒子集中于π/4和5π/4处
float shiftMinAngle = Random.Range(1, (Mathf.PI * 3 / 2) / Mathf.PI);
float shiftMaxAngle = Random.Range((Mathf.PI * 3 / 2) / Mathf.PI / 2, 1);
float angle = Random.Range (Mathf.PI * shiftMinAngle, Mathf.PI * 2 * shiftMaxAngle) - Mathf.PI / 4;
if (Random.Range (0, 100) < 50)
        angle -= Mathf.PI;
稍稍改一下初始数据,使内光圈比外光圈窄,转动速度慢,粒子数目多。之后效果如图:


和原网站中的比较一下,还是挺像的O(∩_∩)O~,唯一就是我的粒子比较少,每个粒子比较大。可是粒子数目已经够多了,表示电脑风扇一直在转。所以就这样吧,如果想要更接近的效果,只要将粒子调多调小一点就差不多了。


版权声明:本文为gunnerczh原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。