本次作业基本要求是三选一
1、简单粒子制作
- 按参考资源要求,制作一个粒子系统,参考资源
- 使用 3.3 节介绍,用代码控制使之在不同场景下效果不一样
2、完善官方的“汽车尾气”模拟
- 使用官方资源资源 Vehicle 的 car, 使用 Smoke 粒子系统模拟启动发动、运行、故障等场景效果
3、参考http://i-remember.fr/en这类网站,使用粒子流编程控制制作一些效果, 如“粒子光环”
- 可参考以前作业
这次作业我选择完成第一项和第三项。
简单粒子制作
实现效果展示
代码传送门
项目实现过程
- 新建一个粒子系统halo,作为光晕。按照参考资源中的教程修改参数,具体设置如下。重要的属性有:start speed = 0,说明中间部分粒子不移动。start rotation ∈ [-100, 100],说明图像有旋转,产生光晕方向变化的效果。
shape选择box,可以使光晕填充粒子。color over lifetime设置为两侧黑中间白,因为光晕应该是初始暗,中间亮,最后熄灭的。
renderer的material选择参考资源给出的图,因为图是2*2的,所以texture sheet animation的tiles设为x = 2、y = 2。
挂上changeColor.cs。
- 新建一个粒子系统star,作为星光。按照参考资源中的教程修改参数,具体设置如下。
星光应当向四周发射,所以shape选择sphere。星光的颜色变化和光晕一样,从无到有,最后暗淡,所以color over lifetime应当是两侧黑,中间白。星光的大小应该是先大后小,所以size over lifetime的曲线设置为从大到小。
texture sheet animation和renderer的设置和光晕相同,不进行详细解释了。
挂上changeColor.cs。
- 修改mainCamera的transform如下,使背景为灰色更方便观察。
代码解释说明
作用是随着点击改变光晕和星光的颜色。colorA变量表示颜色,当鼠标点击时,改变colorA的值。update函数调用changecolor函数。changecolor函数根据colorA的值改变startColor,当colorA为真时,startColor是粉色,当colorA为假时,startColor是蓝紫色。
public class changeColor : MonoBehaviour
{
private ParticleSystem particleSys;
private bool colorA;
private int time;
void Start()
{
particleSys = this.GetComponent<ParticleSystem>();
colorA = true;
time = 0;
}
void Update()
{
changecolor();
}
void OnGUI()
{
if(Input.GetMouseButtonDown(0)){
time++;
if(time%2 == 0){
colorA = !colorA;
}
}
}
void changecolor()
{
var main = particleSys.main;
if(colorA){
main.startColor = new ParticleSystem.MinMaxGradient(new Color(1.0f, 0.6f, 0.6f));
}
else{
main.startColor = new ParticleSystem.MinMaxGradient(new Color(0.4f, 0.4f, 0.6f));
}
}
}
粒子光环
实现效果展示
代码传送门
项目实现过程
- 新建粒子系统clockwise和anticlockwise。
- 将ParticleHalo.cs挂到clockwise和anticlockwise上,将anticlockwise的ParticleHalo的clockwise设为false,iscollected设为false,colorgradient设置成蓝红蓝。
代码解释说明
- ParticleInfo类:包括粒子的半径、角度、时间。
public class ParticalInfo
{
public float radius = 0f;
public float angle = 0f;
public float time = 0f;
public ParticalInfo(float radius, float angle, float time)
{
this.radius = radius;
this.angle = angle;
this.time = time;
}
}
- ParticleHalo类:
首先定义了粒子系统、粒子数组、粒子信息数组和一系列变量,具体在注释中解释。
private ParticleSystem particleSys; //粒子系统
private ParticleSystem.Particle[] particleArr; //粒子数组
private ParticalInfo[] particles; //粒子信息数组
private float[] radius;
private float[] collect_radius;
private int tier = 10; //层数
private int time = 0;
public Gradient colorGradient; //粒子颜色
public int particleNum = 10000; //粒子数量
public float size = 0.1f; //粒子大小
public float minRadius = 7.0f; //外圈的最小半径
public float maxRadius = 10.0f; //外圈的最大半径
public float collect_MinRadius = 1.0f; //内圈的最小半径
public float collect_MaxRadius = 4.0f; //内圈的最大半径
public bool clockwise = true; //顺时针/逆时针
public float speed = 2f; //速度
public float pingPong = 0.02f; //游离范围
public bool isCollected = true; //内圈/外圈
start函数:实例化粒子系统,初始化各粒子的属性、粒子系统的设定。调用randomlySpread函数,作用是将粒子随机分布到轨道上,具体的实现后面会放上。
void Start ()
{
particleArr = new ParticleSystem.Particle[particleNum];
particles = new ParticalInfo[particleNum];
radius = new float[particleNum];
collect_radius = new float[particleNum];
particleSys = this.GetComponent<ParticleSystem>();
particleSys.startSpeed = 0;
particleSys.startSize = size;
particleSys.loop = false;
particleSys.maxParticles = particleNum;
particleSys.Emit(particleNum);
particleSys.GetParticles(particleArr);
RandomlySpread();
}
update函数:实现粒子的旋转,原理是每个粒子每一帧都加上或减掉一个值,加还是减由clockwise判断。然后区分内外圈,如果是内圈,但半径大于内圈最大半径,需要缩小半径;如果是外圈,但半径小于外圈最小半径,需要增加半径。调用PingPong函数实现粒子的漂浮。调用changeColor函数实现颜色的变化。
void Update ()
{
for(int i = 0; i < particleNum; i++) {
if(clockwise){
particles [i].angle -= (i % tier + 1) * (speed / particles [i].radius / tier);
}
else{
particles [i].angle += (i % tier + 1) * (speed / particles [i].radius / tier);
}
particles [i].angle = (360f + particles [i].angle) % 360f;
float theta = particles [i].angle / 180 * Mathf.PI;
if(isCollected == true){
if(particles [i].radius > collect_radius [i]){
particles [i].radius -= 15f * (collect_radius [i] / collect_radius [i]) * Time.deltaTime;
}
else{
particles [i].radius = collect_radius [i];
}
}
else {
if(particles [i].radius < radius [i]){
particles [i].radius += 15f * (collect_radius [i] / collect_radius [i]) * Time.deltaTime;
}
else{
particles [i].radius += Mathf.PingPong (particles [i].time / minRadius / maxRadius, pingPong) - pingPong / 2f;
}
}
particleArr [i].position = new Vector3 (particles [i].radius * Mathf.Cos (theta), 0f, particles [i].radius * Mathf.Sin (theta));
}
changeColor ();
particleSys.SetParticles(particleArr, particleArr.Length);
}
OnGUI函数:当按下鼠标时,改变isCollected的值,即原本的外圈变成内圈,原本的内圈变成外圈。
void OnGUI()
{
if(Input.GetMouseButtonDown(0)){
time++;
if(time%2 == 0){
isCollected = !isCollected;
}
}
}
RandomlySpread函数:随机生成粒子的外圈半径、内圈半径、角度和时间。
void RandomlySpread()
{
for(int i = 0; i < particleNum; ++i){
float midRadius = (maxRadius + minRadius) / 2;
float minRate = UnityEngine.Random.Range(1.0f, midRadius / minRadius);
float maxRate = UnityEngine.Random.Range(midRadius / maxRadius, 1.0f);
float _radius = UnityEngine.Random.Range(minRadius * minRate, maxRadius * maxRate);
radius[i] = _radius;
float collect_MidRadius = (collect_MaxRadius + collect_MinRadius) / 2;
float collect_outRate = Random.Range (1f, collect_MidRadius / collect_MinRadius);
float collect_inRate = Random.Range (collect_MaxRadius / collect_MidRadius, 1f);
float _collect_radius = Random.Range (collect_MinRadius * collect_outRate, collect_MaxRadius * collect_inRate);
collect_radius[i] = _collect_radius;
float angle = UnityEngine.Random.Range(0.0f, 360.0f);
float theta = angle / 180 * Mathf.PI;
float time = UnityEngine.Random.Range(0.0f, 360.0f);
if(isCollected == false){
particles [i] = new ParticalInfo (_radius, angle, time);
}
else{
particles [i] = new ParticalInfo (_collect_radius, angle, time);
}
particleArr[i].position = new Vector3(particles[i].radius * Mathf.Cos(theta), 0f, particles[i].radius * Mathf.Sin(theta));
}
particleSys.SetParticles(particleArr, particleArr.Length);
}
changeColor函数:实现颜色的变化。根据开始时间、粒子的角度和colorGradient设置每个粒子的颜色。
void changeColor()
{
float colorValue;
for(int i = 0; i < particleNum; i++){
colorValue = (Time.realtimeSinceStartup - Mathf.Floor(Time.realtimeSinceStartup));
colorValue += particles[i].angle/360;
while (colorValue > 1) colorValue--;
particleArr[i].startColor = colorGradient.Evaluate(colorValue);
}
}