如何直接控制粒子,同时防止粒子系统做同样的事情?

问题描述 投票:0回答:3

我有很多影响游戏玩法的简单对象, 成千上万! 嗯,不是数千,而是真的很多。因此,如果我将它们设为GameObjects,则FPS会降低,尤其是在生成它们时。即使有游泳池。我应该尝试不同的方法。

您知道Unity3D中的粒子系统可以非常快速地渲染许多粒子。它还可以自动控制粒子,发射并移除它们。但就我而言,对象的位置和生命周期由游戏逻辑管理,如果没有我的命令,粒子系统不允许做任何事情,甚至重新排序粒子。

我试图使用SetParticles方法来控制粒子。它适用于测试项目,我首先使用GetParticles。我甚至可以将粒子设置生命周期移除到-1,但不能生成新的粒子。它也不会阻止粒子系统控制粒子。

我可以禁用发射,因此不会自动创建粒子。 我可以将粒子速度设置为0,这样它们就不会移动。 我可以将生命周期设置为巨大的数字,因此它们不会被删除。

我有一个Particle实例池,以避免不必要的GC分配。对象在生成时接收对粒子的引用,在更新时更改它,并设置生命周期-1并在删除时将其返回池。游泳池存储了这个:

private ParticleSystem.Particle [] _unusedParticles;
private int                        _unusedCount;
private ParticleSystem.Particle [] _array;

汇集需要_unused数组和计数器,_array存储所有使用和未使用的粒子,并用于SetParticles调用。

这种方法的主要缺点是它不起作用,可能是因为SetParticles不会产生新的粒子。此外,我猜它没有对粒子绘制顺序做任何事情,这就是为什么它不适合子弹地狱游戏,其中子弹模式应该看起来不错。

如何正确禁用粒子的自动控制并正确设置直接控制,产卵和移除?

unity3d particle-system
3个回答
1
投票

您正在寻找的可能是什么

    List<Matrix4x4> matrixes=new List<Matrix4x4>();
    for (...)
    {
        matrixes.Add(Matrix4x4.TRS( position,rotation,scale));
    }
    Graphics.DrawMeshInstanced(mesh,0,material, matrixes);

在每个帧上,您只需更新位置,旋转和比例,并在一个drawcall中获取在GPU上渲染的所有实例(与单独的游戏对象相比,速度相当快)。您可以使用这种方式在一次调用中渲染最多1000个实例


0
投票

创建一个空的GameObject,然后添加ParticleSystem作为孩子。将playOnAwake设置为true。

现在当你需要它时,将GameObject.SetActive设置为true else false

为了让他们每个人使用ParticleSystem.GetParticles,修改它们和ParticleSystem.GetParticles

我希望这是你正在寻找的what

ParticleSystem m_System;
ParticleSystem.Particle[] m_Particles;
public float m_Drift = 0.01f;

private void LateUpdate()
{
    InitializeIfNeeded();

    // GetParticles is allocation free because we reuse the m_Particles buffer between updates
    int numParticlesAlive = m_System.GetParticles(m_Particles);

    // Change only the particles that are alive
    for (int i = 0; i < numParticlesAlive; i++)
    {
        m_Particles[i].velocity += Vector3.up * m_Drift;
    }

    // Apply the particle changes to the Particle System
    m_System.SetParticles(m_Particles, numParticlesAlive);
}

void InitializeIfNeeded()
{
    if (m_System == null)
        m_System = GetComponent<ParticleSystem>();

    if (m_Particles == null || m_Particles.Length < m_System.main.maxParticles)
        m_Particles = new ParticleSystem.Particle[m_System.main.maxParticles];
}

0
投票

在编辑器中创建粒子系统后,我们应该禁用发射和形状,因此只有核心部分和渲染器保持活动状态。

最重要的部分是模拟速度必须为零。粒子系统将不再自动发射,移除或处理粒子。现在只有您的代码管理它们。

我用这个类来控制粒子。它不是将粒子绑定到对象,而是具有用于注册对象的API,在这种情况下为烟雾。此外,它存储粒子的临时数组以避免GC分配和粒子计数,以避免使用粒子系统的particleCount属性。

在我的游戏逻辑调用的Update中,会发生以下情况:

  • 游戏逻辑所摧毁的所有对象都将从列表中删除。
  • 如果对象计数大于数组长度,则调整数组的大小。
  • 如果对象计数大于活粒子计数,则进行_particleSystem.Emit调用。如果我们在没有它的情况下调用SetParticles,则不会出现新的粒子。我们必须先发射它们。
  • GetParticles被称为。简单,但可能不是最有效的解决方案,但它保留了粒子数据。可以通过在阵列创建和调整大小时设置所有粒子数据来优化它。如果您这样做,请删除GetParticles调用并取消注释上面的行。此外,您的游戏逻辑应该更仔细地管理粒子。
  • 对于每个对象,我们让该对象更改粒子。
  • 应删除每个没有对象的粒子,因此它们的生命周期设置为负数。
  • SetParticles更新系统中的粒子。
    public class SmokeSystem {

        private ParticleSystem             _particleSystem;
        private List <Smoke>               _smoke     = new List <Smoke> ();
        private ParticleSystem.Particle [] _particles = new ParticleSystem.Particle[256];
        private int                        _particleCount;


        public SmokeSystem (ParticleSystem particleSystem) {
            _particleSystem = particleSystem;
        }


        public void AddSmoke (Smoke smoke) => _smoke.Add (smoke);


        public void Update () {
            _smoke.RemoveAll (e => e.Despawned);

            if (_smoke.Count > _particles.Length) {
                int newSize = Max (_smoke.Count, 2 * _particles.Length);
                Array.Resize (ref _particles, newSize);
            }

            int count = _smoke.Count;
            if (count > _particleCount) {
                _particleSystem.Emit (count - _particleCount);
                // _particleCount = count;
            }
            _particleCount = _particleSystem.GetParticles (_particles);
            for (int i = 0; i < count; i++) {
                _smoke [i].UpdateParticle (ref _particles [i]);
            }
            for (int i = count; i < _particleCount; i++) {
                _particles [i].remainingLifetime = -1;
            }
            _particleSystem.SetParticles (_particles, _particleCount);
            _particleCount = count;
        }

    }

它不依赖于GPU实例支持,因此它可以在WebGL上运行。

© www.soinside.com 2019 - 2024. All rights reserved.