Дизайн системы частиц?

Я разрабатываю свой собственный движок системы частиц, это для учебных целей, я действительно не хочу использовать существующий движок.

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

Я думал о классе "Particle System",

этот класс будет содержать следующие ссылки:

particleList: список частиц, которые составляют систему.

systemEmitter: системный эмиттер для частиц, класс эмиттера должен иметь возможность выполнять несколько методов излучения частиц, например, излучать из линий, точек, случайным образом испускающих из многоугольника. Также этот класс должен выполнять управление выбросами, например, излучать в направлении точки, вдали от точки, в направлении и времени, чтобы испускать.

particleController: управляет, например, вращением вокруг точки, переменными размерами частиц, цветами различных частиц, областями вокруг системы, с которыми частицы реагируют по-разному, обнаружением столкновения (с другими объектами или внутри частиц, если это становится необходимым).

Particle Renderer: отвечает за рисование этой системы, переменные типы смешивания, текстуры частиц, типы частиц, такие как треугольники, круги, пользовательские...

Эти четыре элемента будут составлять класс частиц частиц. Некоторым FX может потребоваться более одной системы частиц, например Fire FX, может использовать одну систему для огня, одну систему для дыма и одну систему для искры.

Это то, что я имею в виду, но мне очень хотелось бы знать, хорошо ли этот подход к дизайну, или если вы видите, что я что-то упускаю или могу/должен делать что-то другое. Я не думал о каком-то простом способе "сэкономить" FX, например, о том, как лучше всего сказать мой движок, "нарисовать огонь", "привлечь взрыв", "рисовать фонтан" и т.д., Возможно, хранить информацию об FX в xml файлах будет хорошей идеей и т.д.

Мнения действительно приветствуются, и, как я уже говорил, я действительно хочу построить это, вместо использования другого движка, для изучения причин.

Ответ 1

Эта настройка должна быть прекрасной. Надеюсь, что вы думаете о том, какие данные будут составлять частицу, которая будет в классе частиц. Вам нужно будет иметь только самые необходимые вещи, поэтому вам нужно только читать/писать как можно меньше памяти при запуске системы.

Что касается управления данными, это должно быть довольно простым. Я бы предложил вариант xml и двоичного формата для загрузки. поэтому вы можете легко настраивать материал во время разработки (и не иметь инструмента). Как только у вас есть инструмент или сделана настройка, я бы преобразовал xml в двоичный файл для быстрой загрузки.

Вам также может понадобиться класс менеджера, который обрабатывает создание и обновление этих систем частиц. Это также позволит вам использовать другие функции, которые связаны со всеми вашими системами. Некоторые примеры этого ограничивают количество систем частиц или частиц, которые можно управлять по соображениям производительности или иметь плоскость столкновения, которую должны учитывать все системы.

Вы упомянули об этом для образовательных целей, и в этом отношении эти вещи довольно ничтожны (но важно, если вы должны использовать это в игре, которая является тяжелой частицей).

Я предполагаю, что это использует API, например DirectX или OpenGL для рендеринга. В этом отношении у меня бы были эффекты частиц, которые имеют общий пул памяти для вашей информации о вершинах. Это значительно облегчает скорость рендеринга. Я также буду следить за границами области, затронутой системой частиц, для использования с отбором усеченного конуса (AABB или Circle).

Огромная часть обновления системы частиц - это то, как атрибуты переходят от одного значения к другому. Чем более динамичным вы можете сделать интерполяцию значений, тем лучше ваши эффекты могут выглядеть. Просто линейная интерполяция может быть достаточно хорошей, но может быть лучше иметь динамический граф, который используется для интерполяции значений. Например, вместо перехода от 0 до 255 синих в секунду, может быть здорово перейти от 0 до 128 за 0,2 секунды, а затем 128-255 за 0,8 секунды. Добавление этого параметра значительно увеличит возможности просмотра ваших эффектов.

Кроме того, я думаю, у вас есть довольно хорошая идея о том, что вы хотите сделать. Ваше упоминание о том, как создавать разные типы частиц, говорит о том, что вы правильно думаете об этом. Я видел, как люди делают двигатели с частицами, просто сосредотачиваясь на рендерингх квадранта. Наличие возможности испускать 3D-геометрию действительно делает вещи великолепными. Вы также можете подумать (если у вас еще нет), чтобы ваша система могла отображать информацию о модели и динамически разделять ее на отдельные частицы, которые будут излучаться. Фактически, взламывание модели выглядит намного лучше, чем отображение некоторых частиц взрыва и исчезновение объекта или его переключение в поврежденное состояние.

Ответ 2

Просто некоторые идеи для оптимизации простых частиц 2D-спрайтов.

Хорошей идеей является отправка всех частиц в массив вершин /VBO и использование вершинного шейдера для обновления своих позиций с течением времени. Это замечательно, если у вас есть простое движение, которое можно легко описать, используя математическую формулу где x(t) и y(t) (то есть они зависят только от времени).

Еще одна отличная идея - использовать точечные спрайты вместо треугольников и квадрациклов. Это должно сократить требуемую полосу пропускания на трубопроводе до четверти.


В моем космическом симе я применил самый тривиальный подход: частицы отправлены как текстурированные квадратики с помощью glBegin()/glEnd(). Они сбрасываются в текущий "сектор" как отдельные объекты и полностью независимы от времени сброса. Это самая примитивная, глупая и идиотская вещь, и она ответственна за значительное снижение производительности, тем более что я выполняю итерацию через объекты через векторный итератор STL и отправляю каждый из них последовательно.

Вам нужно рассмотреть, сколько частиц вы хотите, и что вы хотите от них делать. * Вы хотите, чтобы они реагировали на окружающую среду и сталкивались? Затем вам нужно обновлять обрабатываемые CPU и данные, отправляемые снова и снова. * Они просто летают в самой глупой манере? Тогда вы сможете уйти с отправкой всех частиц в виде VBO и TBO и обновить их в шейдере.

Удачи!


Обновлен для связи с комментарием # 1 от пользователя: -)

Что бы я сделал, это использовать принцип KISS. Это означает: класс ParticleEmitter, содержащий массив вершин, массив скоростей и STL vector с примерами простых коллайдеров, таких как плоскость, сфера, треугольник. Кроме того, у вас есть "глобальный" * STL vector с коллайдерами. Затем обновите скорости в соответствии с коллайдерами.

Аналогичным может быть и аффекторы (гравитация, ветер и т.д.): еще один вектор STL в ParticleEmitter с аффекторами и другой "глобальный" STL vector с аффекторами.

Аппекторами и коллайдерами будут классы, которые реализуют affectParticle(particle_t*). где struct particle_t { float x,y,z; float vx,vy,vz; }. Я бы сохранил структуру POD и запускал обновление в ParticleEmitter::update().

Однако, если вы используете это на iPhone, может ли это быть чрезмерным? Возможно, вы можете уйти от того, что вы уже реализовали? Я понятия не имею, как мой дизайн может повлиять на результаты тестов, но для меня это кажется достаточно разумным, если вы держите частицу, коллайдер и счетчик обратного отсчета, потому что похоже, что он может масштабироваться примерно с n*c+n*a.

Это всего лишь мои ad-hoc мысли, и как я лично его реализовал. Возможно, ваш дизайн или другие люди будут лучше: -)

* "Глобальный" под кавычками, потому что, вероятно, имеет смысл использовать любое разбиение пространства, которое вы используете.

Ответ 3

Я реализовал такой же хороший дизайн для своего собственного движка на С++. Я не использовал ссылки и шаблонные политики (стратегии - читайте Alexandresku "Современное С++ Desing" ). Статический полиморфизм дает лучшую производительность.

Ответ 4

Я хочу сделать несколько комментариев в соответствии с моим опытом.

  • Традиционно большинство частиц использует AOS (Array of Struct) для хранения атрибутов частиц. Но это не может быть лучшим решением. Использование представления SOA (Struct of Array) даст вам большую гибкость для добавления атрибутов каждой системы частиц. Кроме того, вам будет намного проще улучшить производительность с помощью SIMD с помощью SOA. Например, сделав 4 частица вместе, используя инструкции SSE.
  • положение, в котором происходит выброс частиц, является только инициализацией одного атрибута частицы. Когда вы излучаете частицы, вам, вероятно, нужно инициализировать другие атрибуты, такие как время жизни, скорость и т.д. Вы можете абстрагировать все эти функции как инициализаторы. Для позиции у вас может быть инициализатор диска, инициализатор коробки и т.д.
  • Некоторые современные системы частиц принимают концепцию события. Система частиц может генерировать событие (например, дождь сталкивается с рельефом), а другая система частиц может прослушивать и выполнять некоторые действия (например, выбросить всплеск).

Кстати, я считаю, что лучший способ - изучить дизайн существующего приложения/промежуточного программного обеспечения, а также эксперименты.