Unity学习——粒子系统(Particle System)
内置粒子系统(Bulit-in Particle System)
Unity内置粒子系统允许你在Unity支持的平台中产生特效。
- 可以使用 C#脚本来与系统和脚本中的粒子个体交互。
- 粒子系统能使用Unity的底层物理系统,故可以和场景中的 Colliders交互。
使用内置粒子系统
内置粒子系统使用组件,所以在场景中放置一个粒子系统就是添加一个预先制作好的 GameObject(GameObject->Effects->Particle System)或添加这个组件到已存在的 GameObject中(Component->Effects->Particle System)。因为组件十分复杂,所以Inspector被分为许多可折叠的子部分或组件,分别包含一组相关属性。此外,你可以通过Inspector中的Open Window按钮,使用单独的Editor窗口,同时编辑一个或多个系统。
当一个有 Particle System的 GameObject被选中时,Scene视图就会包含一个小 Particle Effect面板,面板中有一些简单的控制,用于可视化你对的系统设置做出的改变。
Playback Speed允许你加速或减慢粒子模拟,因此你可以马上看到后续状态。Playback Time表示系统开始运行的时间,它取决于 Playback Speed。Particle Count表示系统目前有多少粒子。
随时间变化的属性
许多粒子乃至整个粒子系统的数值属性都能随着时间而变化。Unity提供几种不同的方法来指定变化的发生:
- Constant:属性值在它的生命周期中保持固定。
- Curve:值由曲线/图指定。
- Random Between Tow Constant:两个固定值,定义了值的上下界。实际值在范围内随着时间随机变化。
- Random Between Two Curves:两条曲线,定义了在值的生命周期中的一个给定点的上下边界。当前值在范围内随机变化。
当你设置属性为 Curve或 Random Between Two Curves,Particle Curves Curves编辑器会出现在Inspector的底部。
要编辑曲线,点击并拖动端点来改变曲线。
Particle System Curves编辑器有两个按钮: - Optimize:将曲线拟合成四个或更少的keys来构建一个被称为多项式的快速求值器,这比读取未经优化的曲线更有效。
- Remove:删除选中的曲线。
点击选中key旁边的齿轮,并选择其中一个选项,可以编辑粒子系统 play曲线的方式。 - Loop:在粒子生命周期中 play曲线特定次数。比如说,如果你画一条曲线,让粒子大小上下变化,你可以让它循环几次,在粒子死亡前让“上下”动画发生多次而不是一次。
- Ping Pong:与Loop类似,但是是在持续震荡中使曲线前后变化。
- Clamp: 将落在粒子时间范围的粒子查询限制为曲线的第一个或最后一个值。
Start Color属性有以下几个选项:
- Color:所有粒子初始颜色都为设置的颜色。粒子在它们的生命周期中可以更改颜色。
- Gradient:粒子系统发射粒子,粒子在梯度开始和梯度结束时颜色都为设置的颜色。梯度线代表粒子系统的生命周期;粒子系统从与粒子系统时间相对应的梯度点选择颜色。
- Random Between Tow Colors:粒子系统在两个给定的颜色的一个随机线性插值中选择起始粒子颜色。
- Random Between Tow Gradients:粒子系统从每个给定的梯度点中选择一个颜色,该梯度点对应于系统当前的阶段。起始粒子颜色是在这两个被选中的颜色中使用随机线性插值选取的。
- Random Color:与 Gradient模式类似,粒子从定义好的梯度中选择初始颜色。但是粒子系统不是基于粒子系统当前处于的阶段选择的,而是完全随机。当 enabled后,你可以选择一系列颜色,并为每个颜色附上选取概率。
为了计算最终的粒子颜色结果,粒子系统在每个通道中将不同模块的颜色属性相乘。
当你把粒子设置为 Gradient颜色是,Gradient编辑器会出现:
- Mode:决定粒子颜色设置是否被混合。
- Color:展示当前在 Gradient中被选中的key的颜色。使用它能编辑那个梯度位置的颜色。
- Location:显示被选中的key在 Gradient中的位置。
- Presets:允许你保存 Gradient设置。点击 New来使当前这一系列值 为Gradient预设值。
每个通道中不同组件的颜色属性相乘,以计算最终粒子颜色结果。
动画绑定
所有粒子属性都可以被 Animation系统所用。
要访问粒子系统属性,必须要有一个 Animator组件(Project视图: create->Animator Controller)与粒子系统的 Gameobject相关联。还需要添加 Animation Controller和 Animation(Project视图: create->Animation)。
为了动画化一个粒子系统属性,打开包含选定 Animator和Particle System的 GameObject的 Animation窗口,点击 Add Property来添加属性。
点击右边的➕就可以添加了
创建简单的爆炸
你可以使用粒子系统来构建爆炸效果。其核心在于,一个爆炸就是例子向外爆发,但是你可以对它做一些修改,以使其看起来更加真实。
粒子时间线
一个简单的爆炸会产生向各个方向迅速扩展的火球。初始的爆炸有巨大能量,很热(ie, 亮)且移动的很快。能量回迅速消散,导致火焰扩展逐渐变慢,并慢慢冷却下来 (ie,亮度降低)。最终,当燃料烧光后,火焰也会完全消失。
爆炸粒子是最为典型地拥有短暂生命周期的粒子,你可以在它的生命周期中改变几个不同的属性以模拟此效果。粒子会以高速开始移动,然后因为它远离爆炸中心,速度会马上降低。当然,它的颜色也会由开始的亮到暗,最终完全消逝。最终,在它的生命周期中减小粒子尺寸能够产生火焰在燃料耗尽时扩散的效果。
实现
首先,创建默认粒子系统对象(menu: GameObject -> Effects -> Particle System),然后到它的 Shape模块并设置 shape为 Sphere(radius:0.5)。Standard assets中有一个 包含ParticleFireball材质的粒子很适合用于爆炸(Assets -> Import Package -> ParticleSystems)。你可以使用 Renderer模块将这个材质应用于系统。因为 Renderer打开了,所以 Cast Shadows和 Receive Shadows应该关闭,因为爆炸火焰是发光而不是吸收光。
目前可以看到这个系统看上去就像是有很多 fireballs从一个中心点散发出来。当然,爆炸应该一次性产生许多粒子。在 Emission模块,你可以设置 Rate值为0,并添加一个 Burst,时间为 0。在爆炸中的粒子数目由爆炸规模和强度决定,最初50就够了。在 Particle System组件(与你的 GameObject同名),设置系统的 Duration和粒子的 Start Lifetime为 2秒。
你也可以使用 Size Over Lifetime模块来构建火焰消耗燃料的效果。使用 "缓降"来设置size曲线(ie,size从100%开始并减少到0)。要使火焰暗淡并消逝,使用 Color Over Lifetime模块,设置梯度:左边从白色开始,右边以黑色结束。Fire Add材质为渲染使用了额外的着色器,所以暗淡的颜色属性也能控制粒子的透明度;因为颜色逐渐变为黑色,火焰将会变得完全透明。不仅如此,因为粒子会相互覆盖,所以附加的材质允许粒子亮度“添加”在一起。这有助于当爆炸开始时,粒子靠得很近时的明亮闪光的效果。
就目前来看,爆炸已在形成,但它就像是在太空中发生的一样。粒子在消失前被抛出,并以常速移动一段距离。如果你的game是在太空中,那么这可能就是你需要的效果。然而, 一场发生在大气层内的爆炸将会被大气抑制并放缓。使用 Limit Velocity Over Lifetime模块并设置 Speed为 3.0,Dampen为0.4,你应该能看到爆炸强度变小了。
最后需要注意的是因为粒子将会远离爆炸中心,它们的形状会变得更易辨认。特别地,看到所有粒子都有相同的大小和旋转,很明显,每个粒子都重用相同的图形。避免这种情况的简单方法是为粒子的大小和旋转增加一些随机变化。在Particle System组件,点击 Start Size和 Start Rotation右边的小箭头,设置为 Random Between Two Constants。对于旋转,设置为 0 - 360,对于大小,设置 0.5 - 1.5。可以看到粒子图形的重复不再那么明显了。
用法
在测试阶段,打开 Looping属性,就可以反复观看爆炸动画。但是在最终game中,应该关闭此属性。当一个有潜在爆炸可能性的物体(油箱)要设计爆炸时,你需要添加 Particle System组件到该物体上,且 Play On Awake属性 disabled。这样就可以根据需要从脚本中启动爆炸效果。
void Explode() {
ParticleSystem exp = GetComponent<ParticleSystem>();
exp.Play();
Destroy(gameObject, exp.main.duration);
}
对于其他情况,爆炸发生在撞击点。如果爆炸源于某个物体(如 手榴弹),你就可以在短暂时延或它与目标接触后调用上面的 Explode函数。
// Grenade explodes after a time delay.
public float fuseTime;
void Start() {
Invoke("Explode", fuseTime);
}
// Grenade explodes on impact.
void OnCollisionEnter(Collision coll) {
Explode();
}
当爆炸实际上来源于一个在游戏中没有实际表现的物体时(比如说,高速飞行的炮弹),你可以在合适的地方实例化爆炸。你可以从光线投射(raycast)中决定接触点,比如说:
// On the explosion object.
void Start() {
ParticleSystem exp = GetComponent<ParticleSystem>();
exp.Play();
Destroy(gameObject, exp.main.duration);
}
// Possible projectile script.
public __GameObject__ explosionPrefab;
void Update() {
RaycastHit hit;
if (Physics.Raycast (Camera.main.ScreenPointToRay (Input.mousePosition), out hit)) {
Instantiate (explosionPrefab, hit.point, Quaternion.identity);
}
}
从车辆产生烟雾
轿车和其他车辆都会产生烟雾,因为要将燃料转化为动力。你可以使用 Unity的内置粒子系统来添加废气。
粒子时间线
烟雾是从排气管中迅速冒出的,但在与空气接触后就会变缓。当它变缓后,就会传播开来,并变得很模糊,直到消散在空气中。因为派出的气体很烫,当它穿过冷空气时应该会上升。因为这些因素,想要构建真实效果,排烟粒子应该遵循以下规则:
- 起始时,它不应该宽过管道,且随着时间推移,会逐渐变大。
- 起始时,它应该是部分透明,并且因为与空气混合,会逐渐变为完全透明。
- 从动力学角度看,粒子应该开始的很快且迅速变慢,同时会轻微上浮。
实现
Shape模块
首先,设置 Shape为 Cone,Angle属性为 0。“cone”实际上就是圆柱形管道。
接下来,Radius属性值取决于车轮排气管的大小。可以使用 Scene视图中的 radius Gizmo来匹配车辆模型的排气管半径。半径影响了许多属性设置,比如说粒子半径和发射率。本例假设的车辆为遵守 Unity标准尺寸约定的轿车,一个世界单位为 1米,因此半径约为 0.05米。
Renderer 模块
为了烟雾的可视化,Unity的 Standard Asset package包含了用于烟雾粒子的图形。
设置 Renderer模块的 Material属性为 ParticleSmoke Materials。对于黑烟,使用 ParticleSmokeBlack,对于白烟,使用 ParticleSmokeWhite。
Main 模块
默认的生命周期5秒对于排出的烟来说太长了。 Main模块就是 Particle System组件最上面的那个模块,其名字与 GameObject相同。在这个模块中设置 Start Lifetime 为2.5秒; Simulation Space为 world,当车辆移动时,world simulation space能让烟雾环绕在它产生地的周围。设置 Gravity Modifier为 -0.1,负重力效果能导致烟雾粒子上升,就像它们是由热气组成的一样。最后,点击 Start Rotation右边的小箭头选择 Random Between Tow Constants,设置值为 0-360。
Color over Lifetime 模块
在这个阶段,烟雾粒子看上去就较为真实了。下面就要令它能随着时间消散。Enable并打开 Color Over Lifetime模块,点击 Color属性的颜色选取器。在 Gradient Editor窗口,点击右边顶部,并设置alpha为0,顶部控制 alpha,底部控制颜色。现在你应该能看到烟雾粒子在 Scene中逐渐消散了。
Size Over Lifetime 模块。
除了消散,烟雾还应该增加尺寸。Enable并打开 Size Over Lifetime模块,点击 Size曲线,在Inspector底部的曲线编辑器中将左边的手柄垂直移动,使粒子起始大小等于实际大小的一小部分。你选择的大小取决于排气管,但是略大于管道能得到更好的效果。最后哦,使用Scene视图中的粒子系统仿真来看看烟雾效果。
Force over Lifetime 模块
最后,烟雾应该在它消散时变得缓慢。Enable并打开 Force over Lifetime 模块。设置 Space为 Local。设置 力的 Z部分为负值,来表示力应该推动粒子回去(此系统在物体局部空间中沿 Z轴排出粒子)。本例使用 -0.75.
用法
在你确定排气粒子系统的位置后,首先应该将它作为主车辆的子 GameObject。这能让它跟随车辆运动。对于只需要效果且没有改变的简单应用来说,你可以 enable Play On Awake和 Looping属性。然而,你可能想要改变属性,比如说排放率。改变排放率能提升真实性,因为引擎工作的越快,排放出的烟雾越多,但是他也会导致烟雾粒子传播开来。一辆低排放率的高速车辆,就会产生明显的“阵阵”烟雾效果,这极为不真实。
你可以从脚本简单地改变排放率。如果你在脚本中有一个代表引擎转速或车辆速度,你可以简单地用一个常熟乘上此值,并将结果赋给 ParticleSyetem的 emissionRate属性上。
// C#
using UnityEngine;
using System.Collections;
public class PartScriptTestCS : MonoBehaviour {
public float engineRevs;
public float exhaustRate;
ParticleSystem exhaust;
void Start () {
exhaust = GetComponent<ParticleSystem>();
}
void Update () {
exhaust.emissionRate = engineRevs * exhaustRate;
}
}