粒子系统与流动效果
这是
3D
游戏编程的第八次作业
文章目录
- 粒子系统与流动效果
- 说明文档
- 作业内容
- 初始化
- 制作粒子海洋
- 制作粒子光环
- 效果展示
- 遇到的小问题
- 传送门
说明文档
本次实验制作的粒子效果有两个,分别是粒子光环和粒子海洋
闪光点:
附有详细的制作过程与踩坑经验
作业内容
初始化
- 设置背景色为黑色:
- 依次选择
Window->Rendering->Lighting
; - 在弹出窗口中选择
Enviroment
, 并修改其中的Skybox Material
和Sun Source
为None
: - 此时场景色已经为黑色,因为已经没有天空盒了,但是还要注意,摄像机的默认背景色为蓝色,所以必须要在设置摄像机背景色为黑色;
查看Main Camera
的Inspector
,将其中的Background
更改为黑色:
- 创建空对象并命名为
SeaNRing
,在其下面创建两个粒子系统,分别为Sea
和Ring
,如下图所示:
制作粒子海洋
粒子系统基本配置
- 按照下面的模块配截图进行配置
- 基本配置模块
- 发射模块
- 形状模块
- 渲染器模块
- 创建代码文件
ParticleSea
,并填入以下代码:
public class ParticleSea : MonoBehaviour {
ParticleSystem particleSystem;
ParticleSystem.Particle[] particlesArray;
public float spacing = 1;
public int seaResolution = 100;
public float noiseScale = 0.1f;
public float heightScale = 4f;
float perlinNoiseAnimX = 0.01f;
float perlinNoiseAnimY = 0.01f;
public Gradient colorGradient;
void Start() {
// 获取粒子系统
particleSystem = gameObject.GetComponent<ParticleSystem>();
particlesArray = new ParticleSystem.Particle[seaResolution * seaResolution];
particleSystem.maxParticles = seaResolution * seaResolution;
particleSystem.Emit(seaResolution * seaResolution);
particleSystem.GetParticles(particlesArray);
}
private void Update() {
for (int i = 0; i < seaResolution; i++) {
for (int j = 0; j < seaResolution; j++) {
float zPos = Mathf.PerlinNoise(i * noiseScale + perlinNoiseAnimX, j * noiseScale + perlinNoiseAnimY);
// 根据渐变色条来取色,参数给的是zpos,所以后面我们可以根据高度调渐变色
particlesArray[i * seaResolution + j].startColor = colorGradient.Evaluate(zPos);
// 加入柏林噪声,使得波动流畅自然
particlesArray[i * seaResolution + j].position = new Vector3(i * spacing, zPos * heightScale, j * spacing);
}
}
perlinNoiseAnimX += 0.01f;
perlinNoiseAnimY += 0.01f;
particleSystem.SetParticles(particlesArray, particlesArray.Length);
}
}
- 设置渐变色:
- 设置渐变色之前,将
ParticleSea
代码添加为游戏对象Sea
的组件,并单击Color Gradient
选项跳出弹窗; - 在弹窗中,我们选择
Mode
为Blend
,使得各颜色之间的过渡渐变,也即混合。 - 对于渐变色条,我们在条的上下方均可以新增移动块,按照下图设置为:
- 渐变条下方颜色配置:
-
0-50%
白色 -
50%-80%
荧光浅青 -
80%-100%
亮粉
- 渐变条上方透明配置:
-
0-30%
全透明,即Alpha=0
-
30%-100%
全不透明,即Alpha=255
那么zops
变量将会在这个百分比区间中来选择。下面给出的是上述配置的图示:
- 查看效果:
经历过上述配置,我们可以看到如下效果:
还是挺好看的这个颜色配置,动图压缩后不太好看,推荐你直接运行我的代码去查看。
- 踩坑点:
在设置背景色为黑色时,我们提到过将Lighting
里的Skybox Material
选为none
,我一开始并不是选择这个,而是选择下面几个: 这就导致出现了一个问题:
可以看到,粒子堆积在了一起,具体原因还有待搜索,因为一开始我是随便选了一个黑色场景的,调试的时候也没想到是这个的原因,所以这里给出踩坑经验。如果要正常运行,还是选择其他的天空盒材质,或者直接None
。
制作粒子光环
创建脚本
ParticleRing
,并填入以下代码:
public class ParticleRing : MonoBehaviour {
ParticleSystem particleSystem; //粒子系统
ParticleSystem.Particle[] particlesArray; //粒子数组
public int count = 3000; //粒子数量
public float size = 0.1f; //粒子大小
public float maxRadius = 15f; //最大半径
public float minRadius = 7f; //最小半径
public float speed = 2f; //初始速度
public float pingPong = 0.02f; //游离范围
public Gradient gradient; //颜色
CirclePosition[] circles; //粒子位置
public float time = 0; //时间
// 极坐标类
class CirclePosition {
public float radius = 0f, angle = 0f, time = 0f;
public CirclePosition(float radius, float angle, float time) {
this.radius = radius; //半径
this.angle = angle; //角度
this.time = time; //运行时间
}
}
void Start() {
// 初始化粒子数组以及坐标数组
particlesArray = new ParticleSystem.Particle[count];
circles = new CirclePosition[count];
// 初始化粒子系统
particleSystem = gameObject.GetComponent<ParticleSystem>();
particleSystem.maxParticles = count;
particleSystem.startSize = size;
particleSystem.Emit(count);
particleSystem.GetParticles(particlesArray);
// 初始化各个粒子的位置
// 计算rate是希望粒子集中在平均半径附近
float midRadius = (maxRadius + minRadius) / 2;
float minRate = Random.Range(1.0f, midRadius / minRadius);
float maxRate = Random.Range(midRadius / maxRadius, 1.0f);
for (int i = 0; i < count; i++) {
//设置半径
float radius = Random.Range(minRadius * minRate, maxRadius * maxRate);
//设置角度
float angle = (float)i / count * 360f;
// 获取角度的弧度表示,便于后面使用cos和sin计算x/y坐标
float theta = angle / 180 * Mathf.PI;
//保存粒子初位置
circles[i] = new CirclePosition(radius, angle, (float)i / count * 360f);
//设置粒子初位置
particlesArray[i].position = new Vector3(radius * Mathf.Cos(theta), radius * Mathf.Sin(theta), 0);
}
particleSystem.SetParticles(particlesArray, particlesArray.Length);
}
void Update() {
// 鼠标滚轮控制最大半径
if (Input.GetAxis("Mouse ScrollWheel") < 0) {
maxRadius -= 0.5f;
if(maxRadius < minRadius + 2f) {
maxRadius = minRadius + 2f;
}
}
if (Input.GetAxis("Mouse ScrollWheel") > 0) {
maxRadius += 0.5f;
if(maxRadius >= 15f) {
maxRadius = 15;
}
}
for (int i = 0; i < count; ++i) {
//粒子角度增加,并锁定角度在0-360之间
circles[i].angle = (circles[i].angle - Random.Range(0.4f, 0.6f) + 360f) % 360f;
float theta = circles[i].angle / 180 * Mathf.PI;
//粒子半径变动
circles[i].time += Time.deltaTime;
circles[i].radius += Mathf.PingPong(circles[i].time / minRadius / maxRadius, pingPong) - pingPong / 2.0f;
//将粒子锁定至最大半径与最小半径之间
if (circles[i].radius < minRadius)
circles[i].radius += Time.deltaTime;
else if (circles[i].radius > maxRadius)
circles[i].radius -= Time.deltaTime;
particlesArray[i].position = new Vector3(circles[i].radius * Mathf.Cos(theta), circles[i].radius * Mathf.Sin(theta), 0);
}
particleSystem.SetParticles(particlesArray, particlesArray.Length);
}
}
- 将代码挂载到游戏对象
Ring
上,注意,我们并不需要去编辑器更改Ring
的粒子系统配置,上面的代码已经完成了配置。 - 具体的过程我通过代码注释已经写清楚了,就不过多解释,其中加了一个互动就是用户用户可以通过滚轮来调节光环的大小,效果如下:
效果展示
这里将粒子海洋和粒子光环放在一起展示
遇到的小问题
这次项目遇到了一个非实验过程问题,在此记录下:
- 许可证到期问题
报错信息:
Assertion failed on expression: ‘m_ErrorCode == MDB_MAP_RESIZED || !HasAbortingErrors()’
Asset database transaction committed twice!
Assertion failed on expression: ‘errors == MDB_SUCCESS || errors == MDB_NOTFOUND’