粒子系统

粒子系统


Github项目地址

由于实现效果比较简单,就不录制视频了

在开始我们的实验之前,我们先简单了解一下粒子系统每一个属性的含义和效果。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mucdzpkX-1572969535448)(pics/particle.png)]

  • Duration:系统运行的时间长度(如果勾选Looping则表示粒子发射周期)。
  • Looping:如果启用,系统将在其持续时间结束时再次启动,并继续重复该循环。
  • Prewarm:如果启用,则将系统初始化为已完成一个完整的周期(仅在还启用了循环的情况下才起作用)。
  • Start Delay:一旦启用,系统开始发射之前的延迟(秒)
  • Start Lifetime:粒子的初始寿命
  • Start Speed:每个粒子在适当方向上的初始速度
  • 3D Start Size:如果你想单独控制每个轴的大小,则启用
  • Start Size:每个粒子的初始大小
  • 3D Start Rotation:如果要单独控制每个轴的旋转,则启用
  • Start Rotation:每个粒子的初始旋转角度
  • Randomize Rotation Direction:使某些粒子沿相反方向旋转
  • Start Color:每个粒子的初始颜色
  • Gravity Modifier:缩放在 physics manager 中设置的重力值。 零值将关闭重力。
  • Simulation Space:控制粒子是在父对象的本地空间(随父对象移动),在世界空间中还是相对于自定义对象(随您选择的自定义对象移动)处于动画状态。
  • Simulation Speed:调整整个系统的更新速度。
  • Delta Time:在“ Scaled ”和“ Unscaled ”之间选择,“Scaled ”使用时间管理器中的Time Scale ,“Unscaled”将忽略它。这对于出现在“暂停”菜单上的“粒子系统”很有用。
  • Scaling Mode:选择如何使用Transform中的Scale。 设置为 HierarchyLocalShapeLocal 仅应用“粒子系统”变换比例,忽略任何父级。 Shape 将比例应用于粒子的起始位置,但不影响其大小。
  • Play on Awake:如果启用该选项,则在创建对象时“粒子系统”将自动启动。
  • Emitter Velocity:选择“粒子系统”如何计算“继承速度”和“发射”模块所使用的速度。 系统可以使用刚体组件(如果存在)或通过跟踪 Transform 组件的运动来计算速度。
  • Max Particles:一次系统中的最大粒子数。 如果达到极限,则将除去一些颗粒。
  • Auto Random Seed:如果启用,粒子系统每次播放时都会看起来不同。 设置为false时,每次播放时系统都是完全相同的。
  • Random Seed:禁用自动随机种子时,此值用于创建独特的可重复效果。
  • Stop Action:当所有属于系统的粒子都完成后,就可以使系统执行一个动作。 当一个系统的所有粒子都死亡并且其寿命已经超过其持续时间时,就确定该系统已停止。 对于循环系统,仅当通过脚本停止系统时才会发生这种情况。
  • Culling Mode:配置“粒子系统”在屏幕外时是否仍将在每帧进行模拟。
  • Ring Buffer Mode:控制如何从“粒子系统”中删除粒子。

剩余的其他模块可自行到官方文档查看

Emission module / Shape Module / Velocity over Lifetime module / Limit Velocity Over Lifetime module / Inherit Velocity module / Force Over Lifetime module / Color Over Lifetime module / Renderer module

……

简单粒子制作

  • 按参考资源要求,制作一个粒子系统,参考资源

    结果截图

    制作过程:

    根据参考资源,我们将其分为两部分,一部分为光晕,一部分为星光

    • 光晕

      首先选择粒子材料并设置渲染

      这里使用参考资源所提供的Material资源,可以看到该Material中有4个纹理贴图

      mat

      于是我们在设置Renderer Module的Material之外,还要添加Texture Sheet Animation Module,并设置Tiles为 2 * 2 , 表示纹理在X(水平)和Y(垂直)方向上划分的平铺数量,还要设置Frame over Time恒为2

      set1

      设置运动与发射器

      • 设置运动状态色彩变化

        设置Color over Lifetime

        set2

      • 设置Shape

        由于我们的光晕是不动的,所以设置Shape为半径为0的Sphere或者长宽高为0的Box

        set3

      • 设置Emission和Main Module

        这里我们主要设置粒子的大小,刷新时间(这里由于我自己设的显示效果总是不好,所以参考了参考资源的数值),旋转角度(光晕是旋转的,所以设置为在0-90内随机旋转)

        set4

    • 星光

      选择粒子材料并设置渲染

      这里和光晕一样,就是Frame over Time设置为恒为1(星星图案)

      选择运动与发射器

      • 设置Color over Lifetime

        set5

      • 设置Size over Lifetime

        set6

      • 设置Emission和Main Module

        这里设置一下速度和刷新时间即可

        set7

  • 用代码控制使之在不同场景下效果不一样

根据课堂例子的改编,可以简单实现一个根据亮度不同产生不同数量的星光的效果

using UnityEngine;
using System.Collections;

public class PartScriptTestCS : MonoBehaviour {

    public float lightness;
    public float defaultRate;

    ParticleSystem Stars;

    void Start () {
        Stars = GetComponent<ParticleSystem>();
    }

    void Update () {
        Stars.emissionRate = defaultRate * lightness;
    }
}

完善官方的“汽车尾气”模拟

由于本次实验重点在于粒子系统,这里我就直接在Scene中放入预制,而不是代码生成了

  1. 首先我们先导入官方资源包(Unity2018.2之后的版本不再自带对应版本的Standard Asset),但我们可以到Asset Store中下载

    asset

  2. 然后导入,但是我们不需要导入所有,选择如下

    package

  3. 然后在Asset Store里添加了一些修饰场景的预设

  4. 我们可以发现,Standard Asset里面的Car是自带ParticleSystem的,不过这是实现轮胎打滑/刹车时的轮胎效果,我们可以参考一下,这里我们还要注意一下,WheelEffects脚本中寻找ParticleSystem组件用的是transform.root.GetComponentInChildren<ParticleSystem>(),所以要避免和这个脚本发生冲突

    首先先新建一个尾气的粒子系统

    设置如图

    setting

    effect

    接下来,我们编写汽车碰撞的脚本(挂载到Car上)

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    namespace CarSimulate{
        public class CheckCollide : MonoBehaviour{
            public float degreeOfDamage{get;set;}
    
            private void OnCollisionEnter(Collision other) {
                //Get the speed of this car when collision happens
                float speed = this.gameObject.GetComponent<Rigidbody>().velocity.magnitude;
                //The degree of damage is proportional to the speed of the collision
                degreeOfDamage += speed;
                //Debug.Log("degreeOfDamage:"+degreeOfDamage);
            }
        }
    }
    

    然后编写根据当前车的速度以及碰撞程度修改粒子的效果

    速度(可从已有得CarController获取)越快,每次发射得粒子越多

    碰撞越多,尾气消失(Alpha = 0)得越晚

    public float engineRevs;
    public float degreeOfDamage;
    public float exhaustRate = 10f;
    
    ParticleSystem exhaust;
    
    CarController carController;
    CheckCollide checkCollide;
    
    
    
    void Start () {
        exhaust = GetComponent<ParticleSystem>();
        carController = this.transform.parent.parent.gameObject.GetComponent<CarController>();
        checkCollide = this.transform.parent.parent.gameObject.GetComponent<CheckCollide>();
    }
    
    
    void Update () {
        //The faster the speed, the more particles are emitted
        engineRevs = carController.Revs;
        //Debug.Log("Revs:"+engineRevs);
        exhaust.emissionRate = engineRevs * 100f + exhaustRate;
        Debug.Log("Rate:"+exhaust.emissionRate);
    
        degreeOfDamage = checkCollide.degreeOfDamage;
        float colorRatio = (degreeOfDamage % 400.0f) / 400.0f % 0.8f + 0.2f; //Avoid colorRatio greater than one and less than 0.2
        var col = exhaust.colorOverLifetime;
        col.enabled = true;
    
        //The more collisions, the longer the exhaust exists
        Gradient grad = new Gradient();
        grad.SetKeys( new GradientColorKey[] {new GradientColorKey(Color.white, 0.0f), new GradientColorKey(Color.white, colorRatio), new GradientColorKey(Color.white, 1.0f) }, new GradientAlphaKey[] {new GradientAlphaKey(1f, 0.0f),new GradientAlphaKey(0.5f, colorRatio), new GradientAlphaKey(0f, 1.0f) } );
    
        col.color = grad;
    }
    

    结果截图:

    当汽车少量碰撞之后静止

    answer

    当汽车少量碰撞运行

    answer

    当汽车大量碰撞静止

    answer

    当汽车大量碰撞运行

    answer

使用粒子流编程控制制作一些效果, 如“粒子光环”

根据外文翻译Unity制作神奇的粒子海洋制作粒子光环效果

要实现的内容:

  • 创建粒子系统和数组
  • 分配粒子位置
  • 使所有元素能很好地流畅的循环运动
  • 颜色
  1. 一个粒子系统、一个粒子数组、粒子的数量和实现颜色变化的Gradient

    游戏开始时创建一个存放所有粒子的数组。设置最大粒子数量。在后边两个步骤中生成所有的粒子并将它们放入数组。

    public class ParticleHalo : MonoBehaviour{
    	public int particleCount = 1000;
        
        private ParticleSystem particleSystem;
        private ParticleSystem.Particle[] particleArray;
        private ParticlePos[] particlePos;
        
        private void Start() {
            particleSystem = GetComponent<ParticleSystem>();
    		//创建一个存放所有粒子的数组
            particleArray = new ParticleSystem.Particle[particleCount];
            particlePos = new ParticlePos[particleCount];
    		//设置最大粒子数量
            var main = particleSystem.main;
            main.maxParticles = particleCount;
    		//生成所有的粒子并将它们放入数组
            particleSystem.Emit(particleCount);
            particleSystem.GetParticles(particleArray);
    
            setParticlePos();
        }
    }
    
  2. 分配粒子位置

    现在已经有了创建粒子的系统,并且已经在particlesArray配置好了 ,接下来要做的是遍历每一个粒子并为其分配一个唯一的位置。

    这里我们另外定义一个结构体用来存储粒子的位置信息,这是便于后面的旋转操作

    public class ParticlePos{
        public float angle{get;set;}
        public float radius{get;set;}
    
        public ParticlePos(float _radius,float _angle){
            this.angle = _angle;
            this.radius = _radius;
        }
    }
    
    public float minRadius = 4.0f;
    public float maxRadius = 7.0f;
    
    private void setParticlePos(){
    
        for(int i = 0;i<particleCount;i++){
            float radius = Random.Range(minRadius,maxRadius);
            float angle = Random.Range(0f,360f);
    
            particlePos[i] = new ParticlePos(radius,angle);
    
            particleArray[i].position = new Vector3(radius*Mathf.Cos(angle),0f,radius*Mathf.Sin(angle));
        }
    
        particleSystem.SetParticles(particleArray,particleArray.Length);
    }
    

    接下来我们还需要配置一下ParticleSystem,这一步就在Inspector中完成了……

    setting2

  3. 旋转操作

    在Update函数中为角度angle添加一个随机的增量

    private void Update() {
    
        for(int i = 0;i<particleCount;i++){
            particlePos[i].angle = (particlePos[i].angle + Random.Range(0.001f,0.006f) % 360f);
    
            particleArray[i].position = new Vector3(particlePos[i].radius*Mathf.Cos(particlePos[i].angle),0f,particlePos[i].radius*Mathf.Sin(particlePos[i].angle));
        }
    
        particleSystem.SetParticles(particleArray,particleArray.Length);
    }
    
  4. 颜色

    使用 Gradient 变量,然后根据半径使粒子呈现不同颜色

    在Update中添加

    public Gradient colorGradient;
    
    private void Update() {
        ...
        particleArray[i].startColor = colorGradient.Evaluate((particlePos[i].radius - minRadius)/(maxRadius-minRadius));
        ...
    }
    

结果截图

demo

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值