一、作业要求
参考 http://i-remember.fr/en 这类网站,使用粒子流编程控制制作一 些效果, 如“粒子光环”
二、实现效果
三、整体代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Ring : MonoBehaviour
{
public ParticleSystem _particleSystem; // 粒子系统对象。
public int maxParticleNumber = 10000; // 发射的最大粒子数
public float pingPong = 0.5f; // 游离范围
public float particleSize = 0.05f; // 粒子的大小
public float maxRadius = 10, minRadius = 5; // 粒子旋转半径范围
public float particleSpeed = 0.05f; // 粒子运动的速度
private float[] particleAngles; // 每个粒子的位置偏移角
private float[] particleRadius; // 每个粒子的运动半径
private float time = 0;
private ParticleSystem.Particle[] particleArray;
// Start is called before the first frame update
void Start()
{
// 初始化粒子数组、粒子角度数组、粒子半径数组
_particleSystem = GetComponent<ParticleSystem>();
particleArray = new ParticleSystem.Particle[maxParticleNumber];
particleAngles = new float[maxParticleNumber];
particleRadius = new float[maxParticleNumber];
// 初始化粒子系统
_particleSystem.startSpeed = 0;
_particleSystem.loop = false;
_particleSystem.maxParticles = maxParticleNumber;
_particleSystem.Emit(maxParticleNumber); // 发射粒子
_particleSystem.GetParticles(particleArray);
// 初始化各粒子位置
for (int i = 0; i < maxParticleNumber; i++)
{
// 随机生成每个粒子距离中心的半径,同时希望粒子集中于平均半径附近
float midRadius = (maxRadius + minRadius) / 2;
float rate1 = Random.Range(1.0f, midRadius / minRadius);
float rate2 = Random.Range(midRadius / maxRadius, 1.0f);
particleRadius[i] = Random.Range(minRadius * rate1, maxRadius * rate2);
// 设置粒子大小
particleArray[i].startSize = particleSize;
// 随机生成每个粒子的角度
particleAngles[i] = Random.Range(0, 360);
float rad = particleAngles[i] / 180 * Mathf.PI;
particleArray[i].position = new Vector3(particleRadius[i] * Mathf.Cos(rad), particleRadius[i] * Mathf.Sin(rad), 0); // 放置粒子
}
_particleSystem.SetParticles(particleArray, particleArray.Length);
}
// Update is called once per frame
void Update()
{
for (int i = 0; i < particleArray.Length; i++)
{
time += Time.deltaTime;
// 更改粒子角度(一半在逆时针,一半在顺时针,而且速度有10个层级)
particleAngles[i] = (particleAngles[i] + (i % 10 + 1) * (i % 2 == 0 ? particleSpeed : 0 - particleSpeed) + 360) % 360;
// 更改粒子半径(造成粒子波动效果,而且波动是在一定范围内的)
particleRadius[i] += (Mathf.PingPong(time / minRadius / maxRadius, pingPong) - pingPong / 2);
// 设置粒子位置
float rad = particleAngles[i] / 180 * Mathf.PI;
particleArray[i].position = new Vector3(particleRadius[i] * Mathf.Cos(rad), particleRadius[i] * Mathf.Sin(rad), 0);
}
_particleSystem.SetParticles(particleArray, particleArray.Length);
}
}
四、解析
1. 建立对象
建立一个空对象Main,右键点击,选择Effects-Particle System,生成对象Ring用作粒子效果挂载对象,并新建Cube贴图作为背景
2. 制作圆环
脚本中的公有变量:
public ParticleSystem _particleSystem; // 粒子系统对象。
public int maxParticleNumber = 10000; // 发射的最大粒子数
public float pingPong = 0.5f; // 游离范围
public float particleSize = 0.05f; // 粒子的大小
public float maxRadius = 10, minRadius = 5; // 粒子旋转半径范围
public float particleSpeed = 0.05f; // 粒子运动的速度
脚本中的私有变量:
private float[] particleAngles; // 每个粒子的位置偏移角
private float[] particleRadius; // 每个粒子的运动半径
private float time = 0;
private ParticleSystem.Particle[] particleArray;
在start函数中进行初始化:
// Start is called before the first frame update
void Start()
{
// 初始化粒子数组、粒子角度数组、粒子半径数组
_particleSystem = GetComponent<ParticleSystem>();
particleArray = new ParticleSystem.Particle[maxParticleNumber];
particleAngles = new float[maxParticleNumber];
particleRadius = new float[maxParticleNumber];
// 初始化粒子系统
_particleSystem.startSpeed = 0;
_particleSystem.loop = false;
_particleSystem.maxParticles = maxParticleNumber;
_particleSystem.Emit(maxParticleNumber); // 发射粒子
_particleSystem.GetParticles(particleArray);
// 初始化各粒子位置
for (int i = 0; i < maxParticleNumber; i++)
{
// 随机生成每个粒子距离中心的半径,同时希望粒子集中于平均半径附近
float midRadius = (maxRadius + minRadius) / 2;
float rate1 = Random.Range(1.0f, midRadius / minRadius);
float rate2 = Random.Range(midRadius / maxRadius, 1.0f);
particleRadius[i] = Random.Range(minRadius * rate1, maxRadius * rate2);
// 设置粒子大小
particleArray[i].startSize = particleSize;
// 随机生成每个粒子的角度
particleAngles[i] = Random.Range(0, 360);
float rad = particleAngles[i] / 180 * Mathf.PI;
particleArray[i].position = new Vector3(particleRadius[i] * Mathf.Cos(rad), particleRadius[i] * Mathf.Sin(rad), 0); // 放置粒子
}
_particleSystem.SetParticles(particleArray, particleArray.Length);
}
3. 旋转圆环/改变粒子位置
// Update is called once per frame
void Update()
{
for (int i = 0; i < particleArray.Length; i++)
{
time += Time.deltaTime;
// 更改粒子角度(一半在逆时针,一半在顺时针,而且速度有10个层级)
particleAngles[i] = (particleAngles[i] + (i % 10 + 1) * (i % 2 == 0 ? particleSpeed : 0 - particleSpeed) + 360) % 360;
// 更改粒子半径(造成粒子波动效果,而且波动是在一定范围内的)
particleRadius[i] += (Mathf.PingPong(time / minRadius / maxRadius, pingPong) - pingPong / 2);
// 设置粒子位置
float rad = particleAngles[i] / 180 * Mathf.PI;
particleArray[i].position = new Vector3(particleRadius[i] * Mathf.Cos(rad), particleRadius[i] * Mathf.Sin(rad), 0);
}
_particleSystem.SetParticles(particleArray, particleArray.Length);
}
五、心得体会
对粒子系统的几个概念有了更明晰的认识:
粒子 :是粒子系统管理的基本单位。一般它是Material(材料):texture、shader,分别负责形态、光照效果、两个方面。通常,粒子系统包含基础材料库供用户选择。
生命周期 :每个粒子都有自己的生命周期。包括初始化状态、运动变化状态、回收状态。根据归一化生命周期,控制粒子的运动与变化。
渲染 :渲染是定义粒子材料与摄像机之间的关系。主要包括材料面方位、显示顺序、光照等信息。
也通过对粒子光环的实现掌握了一定设计和构建粒子系统的技巧。