Оптимизация VFX для игровых движков

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

Оптимизация VFX для игровых движков

Баланс качества и производительности

Для начала, стоит сказать, что есть существенная разница между эффектами для ПК, мобильных устройств и консолей. Так, на ПК можно дать волю фантазии и особо не сдерживать себя в «тяжести» и крутости эффектов. Использовать разные шейдеры, плагины.

Оптимизация VFX для игровых движков

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

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

Итак, сперва нужно уяснить, что у вас за игра. Будь то скроллер с самолётиками, файтинг, 2D-платформер, 3D-аркада, гонки, карточная игра, шутер. Для каждого варианта будет своё оптимальное количество частиц на экране одновременно. Скажем, для карточной игры вроде Hearthstone их будет очень много, и они будут постоянно висеть на экране. Следовательно, их нужно делать лёгкими, из малого количества частиц. В файтинге на экране не особо много чего происходит, поэтому тут вполне можно сделать крупные, тяжёлые эффекты. Но лучше этим не увлекаться, если то же самое можно сделать проще и легче.

Кстати, этот вопрос вы должны задавать себе постоянно, пока работаете над проектом. Как я могу сделать это проще и легче в плане нагрузки на CPU и GPU, сохранив при этом качественный визуальный результат?

Следующий шаг — это поинтересоваться у главного программиста, на какое минимальное референсное устройство ориентируется проект. И какие его характеристики в плане количества полигонов одновременно на экране при минимум 30 fps (на консолях 24-25 — минимальная планка, с которой можно пройти апрув Sony и MS), количества доступной памяти под текстуры, поддерживает он те или иные кастомные шейдеры.

Бывают ситуации, когда на Android и iOS одни и те же шейдеры могут работать по разному или не работать вообще. Особенно часто это бывает с купленными в сторах ассетами эффектов, которые так любят новички. Там всё красиво и просто, но у многих юзеров на их смартфонах и планшетах не работает.

Как мы видим, простор для работы ощутимо сузился, и шаг влево или вправо может обернуться багами, артефактами, розовыми квадратами на устройстве игроков. Поэтому я рекомендую стараться использовать дефолтные шейдеры Unity. Из кастомных лучше брать проверенные временем и другими проектами. И совсем уж боярское решение — иметь под рукой программиста по шейдерам, который при первой необходимости перепишет и все исправит. Или god like вариант — писать их самому.

FumeFX в действии

Оптимизация текстур

Для отображения любого эффекта нужно что-то показывать. И это что-то — текстуры. Они являются самой важной, значимой и сложной частью эффектов. Текстура назначается на материал, материал назначается на систему частиц. Можно с помощью drag'n'drop перетащить материал из папки и бросить его на партикл систем (далее сокращенно ПС). На текстурах мы рисуем всё, что нам нужно, всё, что хотим показать в эффекте. Искры, звёздочки, лучи, круги, спрайты дыма. Основные правила создания текстур для эффектов следующие:

Делаем почти всегда только чёрно-белое изображение. Сохраняем в PNG с прозрачностью. Белая текстура на прозрачном фоне — оптимальный вариант. Иногда бывают нужны серые изображения, белое с серым. Чёрные — почти никогда. Чёрную картинку нельзя привести ни к какому цвету, а все градации серого — можно, в том числе и к чёрному. В ПС можно выставить любой цвет, так что, например белая звезда может быть жёлтой, красной, зелёной, какой угодно. Не нужно делать на каждый случай отдельную звезду определённого цвета. Одна белая подходит на все случаи.

Желательно, но не обязательно, делать разрешение текстуры, кратное степени двойки. А именно 32х32, 64х64, 128х128, 256х256, 128х32, 64х256 и так далее. Во-первых, это позволяет включать в свойствах текстуры компрессию и уменьшать её вес. А во-вторых, такие текстуры легче делить на одинакового размера кадры, если создавать анимированные текстуры. По сути, это последовательность кадров, которая идет слева направо и сверху вниз. Так же, как мы читаем любой текст.

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

А можно сделать все это в одной ПС с одним материалом и одной текстурой. В системах частиц Unity есть возможность проигрывать секвенцию кадров, как я уже упомянул раньше. Играть можно последовательно всю секвенцию или по одному ряду. В том числе и случайный ряд. Рядом считается горизонталь в которой находятся кадры. В атласе 8 на 2 будет два ряда по восемь кадров в каждом.

В случае со снежинками оптимально сделать 1 на 4. То есть четыре ряда по одному кадру в каждом. Таким образом, ПС будет случайно выбирать любой ряд, в котором будет одно уникальное изображение снежинки, и показывать его. И так много раз. Так мы достигаем экономии в материалах, текстурах, упрощаем работу с настройками до одной ПС вместо четырёх и получаем разные снежинки. Как рассчитать кол-во кадров в атласе? Как расположить ряды и кадры в них? Делайте это заранее — до того, как собираете сложный много кадровый атлас. Чтобы не получалось текстур вроде 2048 на 32. Для этого собираем эффект с однокадровым изображением, убеждаемся в достаточной длительности жизни частиц и уже тогда делаем нужное количество кадров в атласе.

Расчёт примерно такой: одна секунда жизни частицы — это 30 кадров, значит оптимально сделать атлас из 32 кадров — 8 на 4, четыре ряда по восемь кадров в каждом. Допустимо понизить частоту кадров до 24, в крайнем случае до 20 за секунду. Меньше — и глаз будет видеть отчётливые «тормоза». Нужно снижать длительность жизни частицы. Для коротких эффектов вроде огня хорошо подходят 8-16 кадровые секвенции. Всполохи быстры по своей природе, так что их длительность вполне можно делать 0,3-0,5 секунды, что примерно и равно 10-15 кадрам.

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

Делаем минимально возможный размер текстуры. Например, для искры можно использовать 16 на 16 или 32 на 32. Для белого квадрата вообще достаточно 8 на 8. И визуально разницы не будет, если сделать его 1024 на 1024.

Для так называемого гало (halo), разблюренного круга, который имитирует свечение вокруг объекта, в большинстве случаев достаточно 128 на 128. Нет смысла делать 512 на 512 или больше. Делайте всегда такой маленький размер, чтобы не было видно пикселизации (пиксельной кромки изображения). Нужно ещё учитывать, что те же гало-текстуры являются универсальными и используются многократно в разных эффектах одного проекта. И размер частиц с ними может быть от самого маленького до во весь экран. Даже в этом случае 128 на 128 вполне достаточно, если хорошо сделать текстуру.

Ещё частый случай, когда изображение вытянутое, например, молния, и занимает пространство 64 на 256. Нет смысла делать квадратный кадр 256 на 256, оставляя по краям огромные пустые места на текстуре. В версиях Unity 5.0+ появилась возможность задавать размер билборда по сторонам. Так что проблема решается просто созданием вытянутого билборда. Экономим место на текстурах. Не оставляем пустое пространство без дела.

Оптимизация материалов и шейдеров

Здесь мало что зависит от самого художника по эффектам, если он не является одновременно и специалистом по шейдерам, и не делает их сам. В Unity 2018 анонсирован встроенный аналог известного и популярного ассета Shader Forge. Шейдеры можно будет собирать, как конструктор, набирая нужные функции и настраивая их без особых знаний в программировании.

Что же касается встроенных дефолтных шейдеров, то я рекомендую использовать шейдеры mobile>particles и прочие из вкладки mobile при работе с эффектами для мобильных устройств. Вроде как они чуть лучше оптимизированы для этого. Но ничто не мешает использовать и другие, полноценные шейдеры, идущие в комплекте с движком. Я частенько использую не мобильный шейдер Particles>Multiply (Double).

Старайтесь не плодить много материалов. Это пагубная практика. При действительной необходимости — да, добавляйте новый материал. Но старайтесь группировать текстуры в атласы, как я упоминал выше и назначать все это на один материал.

Например, вполне можно сделать атлас, где будут несколько вариантов гало с разной прозрачностью и интенсивностью «свечения» и, использовав один материал, уже в самой ПС вызывать нужный кадр.

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

Так же нередки случаи конфликтов ресурсов проекта и подобных «конструкторов». Ведь авторы делают их, чтобы продавать, а не чтобы они работали у всех идеально. Часто удается обойтись хорошо сделанной иллюзией на дефолтных шейдерах. Поэкспериментируйте с движением, появлением, прозрачностью в настройках ПС. Часто интересный результат получается случайно. И уже на его основе можно сделать интересный эффект. Если других вариантов нет — тогда используйте. Но помните об упомянутых рисках.

Очередной всеми любимый смерч

Оптимизация количества частиц на экране

Большие частицы против маленьких. Количество частиц на экране напрямую влияет на производительность: чем их больше, тем она хуже. Так же очень важен размер частицы. В настройках ПС даже есть ограничение, которое по дефолту равно 0,5. Сто частиц размером 5 миллиметров каждая будут намного меньше нагружать процесс рендеринга, чем те же сто частиц, но уже в половину экрана каждая. Да, площадь полупрозрачных изображений на экране очень сильно влияет на производительность. Об этом вам скажет любой программист.

Суть примерно в следующем: GPU приходится очень много просчитывать накладывающиеся друг на друга полупрозрачные слои. И чем их больше, тем сложнее просчёт. И если их площадь близка к общей площади экрана, то расчётов приходится делать больше, чем для маленьких частиц. Ведь нужно рассчитать, как будет выглядеть то, что находится за этими большими полупрозрачными частицами. Поэтому используйте их очень аккуратно и всегда старайтесь свести их количество и время жизни к минимуму. Другими словами, сделать дым на пол экрана лучше из 200 небольших частиц, чем из 40-50 больших. Визуально будет одинаково, зато производительность не просядет.

Используем время жизни частиц полностью. Бывают случаи, когда нужно сделать плавное пропадание частиц. И некоторые нехорошие господа делают это, срезая прозрачность частицы в середине её жизненного цикла. После этого она не видна на экране, но фактически GPU продолжает её рендерить. Это видно, если включить режим Wire (сетка). Так делать — просто позор. Вместо срезания видимости на середине жизни используйте вдвое меньшее время жизни, и срезайте видимость в конце. Визуально выглядит так же, но частиц в два раза меньше.

Меши как частицы. В ПС Unity есть возможность эмитить не только билборды, но и меши. Это полезно, когда нужно сделать какие-то части эффекта геометрией. Например, разлетающиеся доски или осколки после взрыва. Билборд имеет всего два треугольника, а меш может быть тяжёлым в плане полигонажа. Помните об этом и используйте меши оптимального полигонажа и количества — и только тогда, когда это действительно необходимо. Например, вместо полноценных сфер-мешей по сотне-другой треугольников можно эмитить отрендеренный вид меша на билборде.

Ориентация билбордов в пространстве. Тоже очень полезная фича, которая позволяет сэкономить немного частиц. Бывает полезна при статичной камере, например в 2D-проектах. В этом контексте под статичной камерой имеется ввиду, что она не использует третье измерение, не поворачивается вокруг персонажа, а имеет строго закреплённое положение, так что всё происходящее на экране мы видим под заданным углом.

Для подобных случаев лучше использовать ориентацию билбордов Local в свитке Render в настройках ПС. А эмитить их только в двух плоскостях эмитерами типа Circle, Edge, а не Sphere, Hemisphere. Это позволяет меньшим количеством частиц добиться заполнения пространства. Поскольку все они будут повернуты в камеру и не будут улетать по оси Z вглубь экрана от камеры. Все они будут видны, что позволит снизить их количество по сравнению с тем, если бы часть частиц просто улетала внутрь экрана, закрытая другими частицами, более близкими к камере. Экономия небольшая, но все же экономия.

А ещё эта ориентация в некоторых случаях позволяет избежать частого артефакта в играх — заметного пересечения с другими объектами. Такое часто можно увидеть, когда частицы «пересекаются» с землей, где половина отсекается резкой границей. Например, дым от шин в гонках. Есть вариант использовать Soft Particles шейдер, но он чуть больше влияет на производительность, чем обычные шейдеры Particles и Mobile>Particles.

Для 3D-проектов со свободной камерой чаще всего приходится использовать ориентацию билбордов View или Face. Они всегда смотрят в камеру. Вариант Face будет смотреть только в активную камеру. И если вы используете две или больше камер одновременно, то лучше не использовать такую ориентацию. Могут возникнуть проблемы.

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

Летающий лев-медведо-тигр

Трейлы (trails)

Трейл — след, хвост за частицей. С некоторых пор трейлы перестали быть отдельным бесполезным компонентом и стали частью ПС Unity. У них появились дополнительные настройки, позволяющие их действительно использовать.

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

За количество сегментов отвечает очень важный параметр — Minimum Vertex Distance. Он напрямую влияет на производительность при использовании тейлов. По дефолту он равен 0,2, что очень много. Из подсказки можно понять, что он отвечает за то, через какое расстояние будет добавлен новый сегмент трейла. Другими словами, трейл длиной в два сантиметра будет состоять из сегментов, которые находятся друг за другом через каждые 0,2 пикселя. Поднимая этот параметр до 10, мы сокращаем количество сегментов в 50 раз. А если учесть, что частиц с трейлами может быть не один десяток на экране — мы срезаем огромное количество полигонов и улучшаем производительность. Правило использования трейлов такое: чем ровнее движение частиц, тем меньше сегментов трейла нужно. Чем хаотичнее движение частиц, тем сегментов трейла нужно больше.

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

Нередко эффективнее использовать не встроенный в ПС трейл, а создать sub-emiter, где каждая частица одной ПС будет сама выступать в роли эмитера и испускать частицы. Их общее количество можно жёстко контролировать, что тоже хорошо сказывается на производительности.

Вообще, лучше стараться избегать трейлов в «тяжёлых» мобильных проектах, где много всего на экране, в том числе и эффектов. Используйте трейлы очень взвешенно и обдуманно. К таким же «тяжёлым» фичам в ПС Unity относится Noise. Он позволяет создавать красивые перемещения частиц, но уж очень прожорлив на вычисления. Отлично подойдёт для ПК-эффектов.

Холодное пенное хлещет в невидимый бокал. Взгляд с пола

Источники света

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

Нужно помнить, что шейдеры particles и mobile particles невосприимчивы к источникам света — он на них просто не влияет. Не затемняет и не осветляет. Шейдер всегда одинаково выглядит, что в темноте, что при освещении. Это свойство и позволяет сделать иллюзию засвета, освещённого пространства вокруг огня, костра, факела, фонаря. А нагружать GPU ещё и расчетом света от эффектов — явно лишнее. Для ПК-эффектов всё же, думаю, можно использовать ИС. Но всегда лучше посоветоваться со своими программистами на этот счёт.

Дружная семья фаерболов

Эффекты для UI (элементов интерфейса)

Эффекты для интерфейса создаются по тем же принципам и правилам, что и обычные эффекты, но с одним нюансом. Вы не можете разносить части эффекта по дальности и близости к камере. Другими словами, у вас пропадает третье измерение и остаётся всего два. И весь эффект превращается, буквально, в один слой, в котором нельзя как-то управлять очередностью частиц средствами настроек ПС.

В своей работе я использую скрипт, который вешается на каждую ПС, превращая её в подобие спрайта. И очередность перед камерой выстраивается обычной иерархией объектов и ПС на сцене. Что ниже стоит в списке, то ближе к камере. Объекты выше по иерархии будут находиться как бы за впереди стоящими.

Скрипт называется UI Particles — его мы вроде бы нашли где-то в сторе.

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

Порядок в проекте

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

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

Одна папка на все материалы избавит вас от дубликатов и позволит быстро мониторить уже готовые материалы для реюза на других эффектах. То же самое с текстурами. Например, имеем текстуру Halo01.png. Для неё делаем материал mobile>particles additive и называем его Halo01_Add. По аналогии делаем материал mobile>particles alpha blended и называем его Halo01_AB. Теперь мы всегда с ходу можем понять и использовать нужный материал, не просматривая весь список по сто раз. Это очень помогает, когда проект большой и счёт материалов и текстур идёт на сотни.

Во вторых, именуйте все файлы осмысленно. Никаких Material01, Material02. Если это звёзды, то так и пишем Star01_Add. Если какие то сплэши или лучи — тоже именуем понятно: Splash01, Rays01, Beams01 и так далее. Это не только сэкономит массу времени и облегчит работу лично вам, но и другой художник по эффектам сможет быстро понять, что к чему в этом проекте.

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

Эти три простых правила сэкономят массу времени и ресурсов проекта, а выполнять их не сложно, когда привыкнете.

Относитесь к каждому эффекту, как к маленькому и уникальному проекту. Старайтесь придумывать новые способы изобразить одни и те же действия. Например, разные типы и стилистики молний, огня, дыма. Чем больше разнообразных текстур у вас в проекте, тем более красивыми смотрятся эффекты.

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

Спросите себя, нравится ли вам то, что видите? Используйте различный софт для создания реалистичных, анимированных эффектов. Не зацикливайтесь на одном фотошопе. Чем больше у вас знаний и навыков, тем легче придумывать и создавать новые эффекты! Нет предела совершенству.

180180
79 комментариев

Жаль вот только, что такая годнота в оффтопе, а не в геймдеве!

30

При написании нет возможности выбрать геймдев. Такой вот сайт про геймдев :)

44

Перенесут завтра.

Комментарий недоступен

Спасибо за материал. Как обычно - очень круто)

>Используйте различный софт для создания реалистичных, анимированных эффектов.Например, какой?

2

After Effect, FumeFX, 3dsmax, Maya и тд.

2

Для меня эффекты как были, так и остаются какой-то магией.

14