Как напрямую контролировать частицы, не позволяя системе частиц делать то же самое? - PullRequest
0 голосов
/ 17 апреля 2019

У меня есть много таких же простых объектов, которые влияют на игровой процесс, тысячи из них! Ну, не тысячи, а действительно много.Так что, если я сделаю их 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 не создает новых частиц.Кроме того, я думаю, что он ничего не делает с порядком рисования частиц, поэтому он плохо подходит для игр с пулями, где паттерны должны выглядеть красиво.

Что нужно сделать, чтобы правильно отключить автоматический контроль частици правильно настроить прямое управление, с порождением и удалением?

Ответы [ 3 ]

1 голос
/ 17 апреля 2019

То, что вы ищете, может быть

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

В каждом кадре вы можете просто обновлять позиции, повороты и масштабы, и получать все экземпляры, отображаемые на GPU, за один вызов (чертовски быстро по сравнению сотдельные игровые объекты).Таким способом вы можете отобразить до 1000 экземпляров за один вызов

0 голосов
/ 19 апреля 2019

После того, как мы создали систему частиц в редакторе, мы должны отключить излучение и форму, чтобы активными оставались только основная часть и средство визуализации.

Самая важная часть в том, что Скорость моделирования должна бытьнуль.Система частиц больше не будет испускать, удалять или обрабатывать частицы автоматически.Только ваш код теперь управляет ими.

Я использую этот класс для управления частицами.Вместо привязки частицы к объекту у нее есть API для регистрации объектов, в данном случае - дым.Кроме того, он хранит временный массив для частиц, чтобы избежать выделения GC и количества частиц, чтобы избежать использования свойства particleCount системы частиц.

In Update, которое вызывается моей игровой логикой,происходит следующее:

  • Все объекты, которые были порождены игровой логикой, удаляются из списка.
  • Если число объектов превышает длину массива, размер массива изменяется.
  • Если количество объектов больше, чем количество живых частиц, будет сделан вызов _particleSystem.Emit.Если мы назовем SetParticles без этого, новые частицы не появятся.Сначала мы должны их испустить.
  • GetParticles называется.Простое, но, вероятно, не самое эффективное решение, но оно сохраняет данные частиц.Его можно оптимизировать, задав все данные частиц при создании и изменении размера массива.Если вы это сделаете, удалите GetParticles call и раскомментируйте строку выше.Кроме того, ваша игровая логика должна управлять частицами еще более осторожно.
  • Для каждого объекта мы позволяем этому объекту изменять частицу.
  • Каждая частица без объекта должна быть удалена, поэтому их время жизни установлено наотрицательное число.
  • 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;
        }

    }

Он не зависит от поддержки создания экземпляров графического процессора, поэтому он будет работать на WebGL.

0 голосов
/ 17 апреля 2019

Создайте пустой GameObject, затем добавьте ParticleSystem как дочерний элемент. Установите playOnAwake в true.

Теперь, когда вам это нужно, установите GameObject.SetActive в true else false.

. Для получения каждого из них используйтеParticleSystem.GetParticles, измените их и ParticleSystem.GetParticles.

Я надеюсь, что это то, что вы ищете.

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];
}
...