Search Unity

Модули системы частиц — FAQ

, 20 апреля, 2016

В Unity 5.3 появилась возможностью настраивать модули системы частиц с помощью скриптов. Понимаем, что кого-то новые возможности скриптинга могут смутить. Чем же может быть полезен такой способ?

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

Доступ к модулям

Пример

Ниже приводится пример изменения атрибута Rate (частота) модуля Emission (испускания частиц).

Те, кто уже знаком с .NET, могут заметить, что мы берем конструкт, задаем ему значение, но не назначаем его обратно системе частиц. Как вообще система частиц примет эти изменения, что это за магия такая?

Всего лишь интерфейс

Модули системы частиц в Unity полностью принадлежат той части движка, которая написана на C++. Вызов системы частиц или одного из ее модулей на самом деле адресован стороне, написанной C++.
В сущности, модули системы частиц представляют собой ее атрибуты. Они зависят от системы частиц, и мы никогда не меняем их принадлежность и не делаем их общими с другими системами. Поэтому даже при наличии возможности взять модуль и использовать его в скрипте он все равно будет всегда принадлежать одной и той же системе.

Чтобы было понятнее, давайте подробнее рассмотрим предыдущий пример.
Система получает запрос на создание модуля испускания частиц, движок создает новый конструкт EmissionModule и задает ему единственный параметр — система частиц, которой он принадлежит. Это необходимо, потому что для доступа к свойствам модулей необходима система частиц.

Когда мы задаем частоту, для доступа к модулю и непосредственной настройки используется переменная m_ParticleSystem. Следовательно, нам более не потребуется возвращать принадлежность модуля системе частиц, поскольку он всегда остается ее частью и все изменения применяются мгновенно. Поэтому все, что делает модуль — это вызов системы, которой он принадлежит. Сам модуль представляет собой лишь интерфейс для внутренних компонентов системы частиц.
Во внутренних модулях хранятся соответствующие свойства, в них же содержится информация о состоянии, поэтому они не могут принадлежать или быть отнесены к нескольким разным системам частиц.
Если вы хотите применить свойства одной системы к другой, то вам лучше скопировать только значения, а не весь класс, поскольку это сокращает обмен данными между частью на C++ и частью на C#.

MinMaxCurve

Класс MinMaxCurve часто используется в свойствах модулей, чтобы описывать изменения значений во времени. Класс поддерживает 4 режима; давайте рассмотрим, как использовать эти режимы в скриптах.

Константы

Самый простой режим, использует только одно-единственное и постоянное значение. Это значение не меняется со временем. Один из способов задать свойство в скрипте — задать скалярную величину.

1

Доступ к константе происходит следующим образом:

Случайное значение между двумя константами

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

1

Доступ к двум константам модуля реализуется так:

Кривая

В этом режиме значение атрибута будет меняться по кривой. Использование кривых из MinMaxCurve в скрипте таит несколько подводных камней.
Во-первых, если вы попытаетесь считать атрибут curve, использующий один из режимов с кривыми, то получите следующее сообщение: «Режимы, использующие переменное значение, не поддерживают чтение кривых частицы из скрипта».
В силу особенностей сжатия кривых в движке доступ к классу MinMaxCurve невозможен, если он не использует один из двух константных режимов. Это не очень-то приятно, но мы работаем над решением этой трудности. Причина заключается в том, что система не хранит AnimationCurve, а выбирает один из двух путей. Если кривая простая (не больше 3 опорных точек, две из которых находятся на концах), то мы используем оптимизированную многочленную кривую, которая обеспечивает большую производительность. Если кривая сложнее, то мы используем стандартную неоптимизированную кривую. В окне Inspector неоптимизированная кривая будет показана с маленькой иконкой в правом нижнем углу, за которой скрыто предложение оптимизировать эту кривую.

Оптимизированная кривая

1

Неоптимизированная кривая

1

Несмотря на невозможность доступа к кривой из модуля в скрипте, мы можем решить проблему, сохранив собственную кривую и применяя ее к модулю при необходимости, примерно так:

Случайное значение между 2 кривыми.

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

1

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

Производительность

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

Упрощаем задачу

Считывание кривых из класса MinMaxCurve

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

Перевод модулей из конструктов в классы

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

Пример:

И в заключение

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

33 replies on “Модули системы частиц — FAQ”

Have you guys thought about extracting some useful classes to be used in other non-particle related cases?

I could imagine a lot of places, e.g. in the AI, where I would need «a random value between two curves». And benefiting from optimized 3-key curves never sounds wrong… not all animation curves are imported from 3DMax with 50+ keyframes ;)

Not sure if this is the place to ask, but in the event that MinMaxCurve becomes modifiable from script, will they be usable in custom inspectors for non-particle related things?

Any plans about the shader side ?

Would it be possible to add a special case where a custom geometry shader could be used to display particles ? So the mesh generated by shuriken could only contains a vertex for each particle (+ all interesting data to be used in the shader)

And in the current state, do you think passing particles data (age, lifetime, size, etc…) to the shader to be something doable ?

I can provide a bit more information on that.

In 5.5, we are hoping to introduce a Vertex Streams feature to the Renderer Module. You will be able to choose exactly what gets sent to your shader (positions, colors, velocities, rotations, lifetime information, etc). This should allow you to do a wide variety of custom shader-based effects.

Additionally, you will be able to set custom particle data from script, and pass that to your shaders too. So, to give an example, you could tag particles with a custom property to represent the «health» of each particle, and then use that in your script logic, or in your shader, or both.

You’ll need to be comfortable writing your own shaders in Unity, to be able to make the most of this feature, but in its basic form, it will finally allow you to properly use the Standard Shader to create normal mapped particles, by including the Tangent Stream.

Hi Karl,
These new changes are welcome, but would it be possible to _please_ have someone fill out the documentation with stub example usages for the Shuriken-related classes/structs/etc. on the Script Reference?

Thanks for the post. The struct mechanism was a little confusing to me at first as well. Will the classes in a future version simply be references to a private member variable then? I assume so from your post, but just wanted to make sure it wasn’t allocating a wrapper every time the property was accessed.

Why have I been seeing GetComponent() in a lot of Unity articles lately? Is this a new version of the method I have not seen, which has no parameters or generic parameters? Thanks!

Never mind. I realized it was because C# can infer the generic parameter type. Sacrifices a little clarity for brevity in this case, I suppose. =)

It’s actually plain old generic GetComponent , but since angle brackets have a special meaning in HTML this gets rendered incorrectly. And apparently no one ever proofreads these posts, so there.

Hi ! I like this article, this clarifies a lot of things with Particle System Scripting.

I downloaded the new Unity 5.4 beta and it was said that there are new ways to deal with Particle System events in the code, but I can’t found the documentation related to this.
Can you tell me where ?
Thank you !

I wonder why «Random between two Constants» isn’t faster than «Random between two Curves». I also wonder why «Random between two Constants» is so much more expensive than «Constant». Finding a random point between two constants doesn’t sound like an expensive feature.

Comments are closed.