WillKen's Blog.

3D游戏编程与设计-粒子系统

Word count: 966Reading time: 4 min
2019/11/06 Share

粒子系统

  • 使用粒子流编程控制制作效果 “粒子海洋”+“粒子光环“

  本次作业选择第三项,使用粒子流编程完成一些效果。粒子光环的制作在课上完成的粒子海洋的基础之上。

项目地址

粒子光环的制作

  • 添加GameObject->Particle System。分别命名为ParticleCirclefixed-x、ParticleCirclefixed-y、ParticleCircleSpread。Spread表示颜色加在粒子本身上,不管粒子如何运动其本身颜色不变,从视觉上看,随着粒子运动颜色实现了扩散;fixed表示颜色是按照位置显示的,即粒子在不同的坐标下颜色是不同的,从视觉上看,颜色是固定的。

  • 设置初始位置和粒子系统属性如下。注意给不同的粒子系统对象添加了不同的tag,便于使用一份代码控制三个对象。

ParticleCirclefixed-x ParticleCirclefixed-y ParticleCircleSpread
  • 代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    using UnityEngine;
    using System.Collections;

    public class ParticleCircle : MonoBehaviour
    {
    public ParticleSystem particleSystem;
    private ParticleSystem.Particle[] particlesArray;
    public int particleNumber = 4000;
    public float radius = 4.0f;
    public float[] particleAngle;
    public float[] particleRadius;
    public float maxR = 10f;
    public float speed = 0.05f;
    float time = 0;
    public float free = 0.05f; //粒子浮动的范围
    public Gradient colorGradient;

    void Start()
    {
    //粒子系统的初始化设置
    particleSystem = GetComponent<ParticleSystem>();
    particlesArray = new ParticleSystem.Particle[particleNumber]; //初始化例子数组
    particleSystem.maxParticles = particleNumber; //设置粒子最大数
    particleAngle = new float[particleNumber];
    particleRadius = new float[particleNumber];

    particleSystem.Emit(particleNumber);
    particleSystem.GetParticles(particlesArray);
    //设置粒子初始位置
    for (int i = 0; i < particleNumber; i++) {
    float angle = Random.Range(0.0f, 360.0f); //随机角度
    float rad = angle / 180 * Mathf.PI; //角度和弧度的转换
    float midR = (maxR + radius) / 2;
    //最大最小半径的随机缩放
    float rate1 = Random.Range(1.0f, midR / radius);
    float rate2 = Random.Range(midR / maxR, 1.0f);
    float r = Random.Range(radius * rate1, maxR * rate2);

    particleAngle[i] = angle;
    particleRadius[i] = r;
    particlesArray[i].position = new Vector3(r * Mathf.Cos(rad), r * Mathf.Sin(rad), 0.0f);//为每个粒子坐标赋值
    //沿x轴上色 Spread
    if(this.tag=="spread")
    particlesArray[i].color = colorGradient.Evaluate((int)particlesArray[i].position.x);
    }
    particleSystem.SetParticles(particlesArray, particlesArray.Length);
    }
    void Update()
    {
    for (int i = 0; i < particleNumber; i++) {
    if (i%2 == 0) {
    particleAngle[i] += speed*(i%5+1);
    } else {
    particleAngle[i] -= speed*(i%5+1);
    }
    if (particleAngle[i] > 360)
    particleAngle[i] -= 360;
    if (particleAngle[i] < 0)
    particleAngle[i] += 360;
    particleRadius[i] += (Mathf.PingPong(time, free) - free/2.0f);
    time += Time.deltaTime;
    time %= 100;
    float rad = particleAngle[i] / 180 * Mathf.PI;
    particlesArray[i].position = new Vector3(particleRadius[i] * Mathf.Cos(rad), particleRadius[i] * Mathf.Sin(rad), 0f);
    //沿x轴上色 fixed
    if(this.tag=="fixed-x")
    particlesArray[i].color = colorGradient.Evaluate((int)particlesArray[i].position.x);
    //沿y轴上色 fixed
    if(this.tag=="fixed-y")
    particlesArray[i].color = colorGradient.Evaluate((int)particlesArray[i].position.y);
    }
    particleSystem.SetParticles(particlesArray, particleNumber);
    }

    }
  • 将代码加载在三个粒子系统对象上,并设置参数
ParticleCirclefixed-x ParticleCirclefixed-y ParticleCircleSpread
  • 运行效果

      我们可以看出最大的粒子光环是fix-x,其次是fix-y,最小的是spread

粒子海洋的制作

粒子海洋的制作参考了翻译文章 Unity制作神奇的粒子海洋!

  • 同粒子光环一样,首先添加粒子系统的游戏对象。并设置初始位置等属性
位置 粒子系统属性
  • 代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    using UnityEngine;
    using System.Collections;

    public class ParticleSea : MonoBehaviour {

    public ParticleSystem particleSystem;
    private ParticleSystem.Particle[] particlesArray;

    public int seaResolution = 50;

    public float spacing = 0.5f;
    public float noiseScale = 0.2f;
    public float heightScale = 3f;
    private float perlinNoiseAnimX = 0.01f;
    private float perlinNoiseAnimY = 0.01f;
    public Gradient colorGradient;

    void Start() {
    particlesArray = new ParticleSystem.Particle[seaResolution * seaResolution];
    particleSystem.maxParticles = seaResolution * seaResolution;
    particleSystem.Emit(seaResolution * seaResolution);
    particleSystem.GetParticles(particlesArray);
    }

    public void GetParticles(ParticleSystem.Particle[] particlesArray){
    for(int i = 0; i<seaResolution; i++) {
    for(int j = 0; j <seaResolution; j++) {
    float zPos = Mathf.PerlinNoise(i * noiseScale, j * noiseScale) * heightScale;
    particlesArray[i * seaResolution + j].position = new Vector3(i * spacing, zPos, j * spacing);
    }
    particleSystem.SetParticles (particlesArray, particlesArray.Length);
    }

    }

    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) * heightScale;
    particlesArray[i * seaResolution + j].color = colorGradient.Evaluate(zPos);
    particlesArray[i * seaResolution + j].position = new Vector3(i * spacing, zPos, j * spacing);
    }
    }

    perlinNoiseAnimX += 0.01f;
    perlinNoiseAnimY += 0.01f;

    particleSystem.SetParticles(particlesArray, particlesArray.Length);
    }

    }
  • 将代码加载在粒子系统对象上,并设置参数

  • 运行效果

CATALOG
  1. 1. 粒子系统
    1. 1.1. 粒子光环的制作
    2. 1.2. 粒子海洋的制作