粒子系统与流动效果

这是3D游戏编程的第八次作业


文章目录

  • 粒子系统与流动效果
  • 说明文档
  • 作业内容
  • 初始化
  • 制作粒子海洋
  • 制作粒子光环
  • 效果展示
  • 遇到的小问题
  • 传送门


说明文档

本次实验制作的粒子效果有两个,分别是粒子光环和粒子海洋
闪光点:
附有详细的制作过程与踩坑经验

作业内容

初始化

  • 设置背景色为黑色:
  • 依次选择Window->Rendering->Lighting
  • 在弹出窗口中选择Enviroment, 并修改其中的Skybox MaterialSun SourceNone
  • 此时场景色已经为黑色,因为已经没有天空盒了,但是还要注意,摄像机的默认背景色为蓝色,所以必须要在设置摄像机背景色为黑色;
    查看Main CameraInspector,将其中的Background更改为黑色:
  • 创建空对象并命名为SeaNRing,在其下面创建两个粒子系统,分别为SeaRing,如下图所示:

制作粒子海洋

粒子系统基本配置

  • 按照下面的模块配截图进行配置
  • 基本配置模块
  • 发射模块
  • 形状模块
  • 渲染器模块
  • 创建代码文件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选项跳出弹窗;
  • 在弹窗中,我们选择ModeBlend,使得各颜色之间的过渡渐变,也即混合。
  • 对于渐变色条,我们在条的上下方均可以新增移动块,按照下图设置为:
  • 渐变条下方颜色配置:
  • 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的粒子系统配置,上面的代码已经完成了配置。
  • 具体的过程我通过代码注释已经写清楚了,就不过多解释,其中加了一个互动就是用户用户可以通过滚轮来调节光环的大小,效果如下:

效果展示

这里将粒子海洋和粒子光环放在一起展示

unity粒子特效调小 unity粒子特效怎么改颜色_ci

遇到的小问题

这次项目遇到了一个非实验过程问题,在此记录下:

  • 许可证到期问题

报错信息:
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’