Пост эффект что это
Пост-эффекты в мобильных играх
Большинство публикаций по графике для консолей и десктопов рассказывают о чем-то новом, а для мобильных платформ во главе угла всегда стоит оптимизация уже существующего.
Что касается пост-обработки — её волшебное действие на фотографии было открыто задолго до появления первых компьютеров, а её математический и алгоритмический базис, созданный для цифровой обработки изображений, удачно вписался в программируемый конвейер GPU.
Помимо того, что пост-эффекты (точнее — их не очень грамотное использование) являются предметом ненависти среди игроков, они также едва ли не единственный способ быстро и дешево «оживить» и «освежить» картинку. Насколько качественным получится это «оживление» и не обернется ли оно в результате «свежеванием», зависит по большей части от художников.
Слегка «освежеванный» скриншот War Robots.
Как уже было сказано выше, эта статья будет посвящена в основном оптимизации. Для тех кто не в теме — отличным вводным курсом будут книги из серии GPU Gems, первые три из которых доступны на сайте NVidia [1].
Рассматриваемые примеры реализованы на Unity, тем не менее методы оптимизации, описанные здесь, применимы к любой среде разработки.
Оптимальная архитектура пост-обработки
Существует два способа рендеринга пост-эффектов:
В то же время пакетный рендеринг заметно эффективнее, поскольку он экономит общее число обращений к памяти. Последнее наиболее актуально для мобильных платформ, на которых повышенная вычислительная нагрузка сопровождается повышенной же теплоотдачей (кто бы мог подумать). И даже если устройство сумеет выдать требуемую частоту кадров, вряд ли игроку будет комфортно играть, держа в руках горячий «кирпич».
Для наглядности приведу последовательную и пакетную схемы рендеринга пост-эффектов, используемых в War Robots.
Последовательный рендеринг: 8 чтений, 6 записей.
Пакетный рендеринг: 7 чтений, 5 записей.
Пакетный рендеринг для Unity реализован в модуле Post Processing Stack [2].
Последовательность применения пост-эффектов без изменения кода изменить невозможно (но и не нужно), а вот отдельные пост-эффекты отключить можно. Кроме того, в модуле интенсивно используется встроенный в Unity кэш ресурсов RenderTexture [3], так что в коде конкретного пост-эффекта, как правило, содержатся только инструкции по рендерингу.
Ресурсы же пост-эффект запрашивает непосредственно во время рендеринга, и освобождает их по его завершению. Это позволяет организовать повторное использование ресурсов в последующих пост-эффектах, поскольку кэш удаляет только те ресурсы, которые не были востребованы в течении последних нескольких кадров.
Финальный этап в пакетном рендеринге — композиционный эффект, который комбинирует результаты всех предшествующих шагов и рендерит их при помощи мультивариантного «убер-шейдера». В Unity3D такой шейдер можно сделать при помощи директив препроцессора #pragma multi_compile или #pragma shader_feature.
В целом, Post Processing Stack нам понравился, но все же без доработки напильником дело не обошлось. Нам требовался масштабируемый модуль с возможностью добавлять или заменять пост-эффекты (включая препассы), а также модифицировать захардкоженный пайплайн, задающий последовательность рендеринга, и композиционный «убер-шейдер». Плюс ко всему в эффектах были разнесены настройки качества эффекта и его параметры на конкретной сцене.
Оптимизация fillrate
Основной метод рендеринга в пост-процессинге — это блиттинг: заданный шейдер применяется ко всем фрагментам текстуры, используемой в качестве render target. Таким образом, производительность рендеринга зависит от размера текстуры и вычислительной сложности шейдера. Простейший способ повысить производительность (а именно — уменьшение размера текстуры) сказывается на качестве пост-процессинга.
Но если заранее известно, что рендеринг необходим только в определенной области текстуры, можно оптимизировать процесс, к примеру, заменив блиттинг на рендеринг 3D-модели. Разумеется, никто не запрещает вместо этого использовать настройки viewport’а, но 3D-модель отличается от блиттинга увеличенным объемом per-vertex данных, которые в свою очередь позволяют задействовать более «продвинутые» вертексные шейдеры.
Именно так мы поступили с пост-эффектом рассеивания света от солнца [4]. Мы упростили оригинальный препасс, заменив его на рендеринг биллбоарда с текстурой «солнца». Фрагменты биллбоарда, скрытые за объектами сцены, выделялись с использованием полноэкранной маски, которая по совместительству служит нам буфером теней (подробнее о рендеринге теней я расскажу чуть позже).
Справа: буфер теней и маска, которая получается, если применить к нему степ-функцию. Все тексели, альфа которых меньше 1, перекрывают собой “солнце”.
Сглаживание текстуры препасса также выполняется при помощи рендеринга 3D-модели.
Разумеется, мы пошли до конца: финальный проход тоже сделан с помощью рендеринга 3D-модели. И в отличие от предыдущих случаев, которые при желании можно заменить блиттингом во вьюпорт, здесь 3D-модель содержит дополнительные данные (цвет вертекса), которые используются в шейдере эффекта.
Оптимизация динамических теней
Не смотря на вычислительную сложность пост-эффектов, динамические тени зачастую ещё более ресурсозависимы. Связано это не только с вычислительной сложностью соответствующих шейдеров, но и с тем, что для получения сглаженных теней требуется дополнительный полноэкранный проход рендеринга.
Обычно, для расчета затенения для фрагмента изображения с использованием техники Shadow Mapping’а используется фильтр PCF [5]. Однако результат без дополнительного сглаживания дает только PCF с очень большим размером ядра, что неприемлемо для мобильных платформ. Более продвинутый метод Variance Shadow Mapping требует поддержки инструкций аппроксимации частных производных и билинейной фильтрации для floating-point текстур [6].
Для получения мягких теней рендер всей видимой сцены выполняется дважды — в первый раз в offscreen-буфер рендерятся только тени, затем к offscreen-буферу применяется фильтр сглаживания, и после этого на экран рендерится цвет объектов, с учетом влияния тени из offscreen-буфера. Что приводит к двойной загрузке как CPU (отсечение, сортировка, обращение к драйверу) так и GPU.
Как один из вариантов решения проблемы — мы решили избавиться от двойного рендера сцены, не переходя на технику отложенного освещения.
Для начала рендерим изображение в промежуточный буфер в формате RGBA (1). Значение альфы — отношение яркости цвета фрагмента если бы он был в тени, к яркости без тени (2). Затем, используя command buffer, перехватываем управление в момент завершения рендера непрозрачной геометрии, чтобы забрать альфу из буфера. Далее сглаживаем (3), и модулируем сглаженные тени с цветовыми каналами промежуточного буфера (4). После этого возобновляется работа пайплайна Unity: рендерятся прозрачные объекты и скайбокс (5).
Данный трюк ведёт к небольшой деградации цветопередачи в затенённых местах, но хитрости вычислений того, что пишется в альфу позволили снизить это влияние до минимума.
В результате мы получили заметный прирост производительности (10-15%) на устройствах средней производительности (в основном на андроидах), и на ряде устройств уменьшилась теплоотдача. Данная техника — это промежуточное решение, до перехода на отложенное освещение.
Для съемки промо, мы по прежнему используем более качественный вариант, т.к. деградация цветопередачи там нежелательна, а ресурсов PС хватает. Для улучшения мягкости тени в этом случае мы применили следующее: при наложении тени используется формула, учитывающая LDotN, что позволяет добиться более плавного перехода в освещенных местах.
Плата за неё — небольшое выгорание тени в местах, где она при блюре становится не абсолютно черной, но зато в результате получается более плавный переход полутени.
Детализация, отражения и пост-эффекты в GTA V
От переводчика:
Данная публикация является продолжением материала «Как происходит рендеринг кадра в GTA V». Теперь автор рассматривает вопросы детализации, освещения и пост-обработки кадра. Приятного чтения.
Уровень детализации
Если мы говорим об абсолютных преимуществах Rockstar над конкурентами, то показатели уровня детализации продуктов компании, определенно, выше всяких похвал. Лос-Сантос – это целая плеяда всевозможных сцен разной степени детализации/полигональности, причем все данные транслируются в режиме реального времени и это ни на минуту не блокирует экран загрузки. Просто дух захватывает!
Огни ночного города
Все огоньки, которые видны вдалеке, реальны. Вы можете подъехать ближе и увидите фонари, которые излучали свет на расстоянии.
Именно с таким заявлением Аарон Гарбут, один из основателей и арт-директоров Rockstar North, выступил незадолго до релиза игры на PS3.
Так ли это? Давайте рассмотрим вот такую ночную сцену:
Огоньки «До»
Осторожно! Трафик!
Огоньки «После»
Оказывается, так оно и есть: каждое маленькое световое пятно – это квад, визуализированный в виде крошечной текстуры 32х32, подобно той, что вы можете видеть ниже.
Все они плотно сгруппированы в рамках геометрии сцены, но это по-прежнему десятки тысяч полигонов, с которыми приходится работать графическому процессору.
Огоньки
Светокопия огоньков
Тест глубины (пройден / провален)
И речь не только о статической геометрии: фары автомобилей тоже движутся вдоль дороги – изображение обновляется в режиме реального времени. Конечно, на большом расстоянии нет смысла полностью визуализировать модели машин, достаточно и 2 фар, чтобы создать иллюзию движения. Но если вы решили подъехать поближе к одному из источников света, уровень детализации повышается и мы получаем полноценное изображение авто
Низкополигональные графические сетки
Вернемся к кадру, который мы анализировали ранее. Некоторые достаточно обширные области обрабатываются всего за один вызов отрисовки. Так было, в частности, в случае с рендерингом холма на данном изображении:
Холм всего за один вызов команды отрисовки
Так что же это за крошечный холмик вдалеке?
На самом деле, Вайнвуд-Хиллз отнюдь не маленький. Это большой район в несколько квадратных километров с десятками домов и других построек.
На вершине холма расположились Обсерватория Галилео, театр Сизифа, Озеро Вайнвуд. Чтобы создать все эти достопримечательности — вы можете рассмотреть их поближе или просто проехать мимо — потребовались тысячи вызовов отрисовки и бесчисленное множество полигонов.
Но в нашем случае, эта зона находится далеко, а потому представлена низкополигональной версией: всего один вызов отрисовки, задействовавший каких-то 2500 треугольников.
Низкополигональная модель Вайнвуд-Хиллз
Рендеринг производится при помощи одной графической сетки, обрабатывающей данные диффузной текстуры. Даже если и существует какой-то механизм для преобразования графической сетки в низкополигональную версию, полностью автоматизировать процесс невозможно, а потому не удивлюсь, если 3D-художникам из Rockstar приходится потратить не один день, чтобы отрегулировать все вручную.
Еще один пример аналогичного рендеринга в один вызов отрисовки — район Маленький Сеул, объединивший несколько кварталов города.
Низкополигональная модель Маленького Сеула
Имея на руках низкополигональную модель виртуального мира, гораздо проще визуализировать текстуру отражений, которая не требует ни детализации, ни высокого разрешения. Для игр одного уровня детализации обработка кубических текстур окружающей среды в режиме реального времени нередко оказывается весьма дорогостоящей или и вовсе невозможной из-за разнообразия используемых геометрических форм.
Предоставление игровых ресурсов
Создание нескольких версий виртуального мира с разными уровнями детализации, как это сделано в GTA, — непростая и очень трудоемкая задача. Но даже, казалось бы, достигнув своей цели, вы все равно остаетесь на полпути: у вас могут быть гигабайты моделей и текстур на жестком диске, но все они ничего не стоят, пока вы не найдете подходящий способ, чтобы загрузить их в оперативную память или в память графического процессора.
GTA V предоставляет игровой ресурс в режиме реального времени, загружая/скачивая модели и текстуры по мере того, как вы передвигаетесь по карте. Причем возможность пользоваться данным контентом в режиме реального времени и при этом наслаждаться игрой без перебоев, действительно, впечатляет.
С технической точки зрения, сложнее всего было уместить необходимую информацию в памяти консоли, чтобы все еще и работало так гладко, как мы видим [. ]. Мы можем транслировать и компилировать гораздо больше, что позволяет обеспечить более высокий уровень детализации, чем это было в GTA 4.
Конечно, у такого механизма передачи данных тоже есть свои ограничения: например, когда вы выбираете персонажа, камера перепрыгивает с одного участка карты на другой, в этом случае система испытывает перегрузку и, совершенно логично, что ей нужно 5 секунд, чтобы сориентироваться в новых условиях и переключиться. Но в GTA V такой переход обыграли очень эффектно с помощью приближающейся/удаляющейся анимации/окна перевода, и так загрузка экрана вообще не ощущается.
Как правило, когда вы ведете машину, скорость движения достаточно низкая, чтобы пропускная способность системы передачи данных позволила постепенно подгружать доступные обновления. Другое дело самолеты: по меркам потоковых систем они движутся слишком быстро, а потому пришлось существенно снизить их скорость относительно показателей, к которым мы привыкли в реальности. Кроме того, уровень детализации графических сеток, соответствующих сценам полета, гораздо ниже, чем в случае с ходьбой/вождением, что также облегчает передачу данных. Хотя, когда игровой ресурс запрашивает свежие обновления, иногда приходится прибегать к вышеупомянутому трюку. В настройках версии для ПК добавлена специальная опция «Передача данных в высоком разрешении во время полета».
Отражение
Поскольку в сцене, которую я анализировал ранее, воды было немного, давайте подробнее остановимся на визуализации бассейна или океана на примере следующей сцены:
Бассейн
Как мы уже видели, рендеринг сцены производится по стандартной схеме: генерируется кубическая текстура окружающей среды, в основном, она необходима для визуализации объектов, которые отражают окружающую среду.
Так сцена выглядит до рендеринга воды:
До рендеринга воды
Визуализация поверхности воды – отдельная история, которая никак не связана с созданием кубической текстуры.
Карта отражения
Сначала генерируется карта «отражения плоскости». Причем с очень низким разрешением, 240×120, а сам процесс похож на процесс генерации кубической текстуры, но на этот раз создается всего один буфер, в котором есть и лестница, и персонажи.
Сцена визуализируется как бы вверх ногами и только потом, после применения симметрии, можно будет получить правильное отражение.
Карта преломления
Извлекается часть изображения — участки с поверхностью воды — позволяющая создать карту преломления. Благодаря этому впоследствии имитируется эффект преломления: свечение из-под воды.
На этом этапе к «непрозрачности воды» добавляется синева (чем глубже, тем насыщеннее оттенок), а также каустики. Итоговая версия карты в два раза меньше сходного буфера.
Основа
Карта преломления
Комбинирование
Для объединения различных буферов рисуется прямоугольный полигон, который выступает в роли поверхности воды в бассейне. С учетом текстуры рельефа, нормали полигона смещаются пиксель за пикселем, что имитирует легкую рябь.
Для океана же не нормали смещаются, а вся графическая сетка отдельного кадра рисуется вершинами вверх, что имитирует движение волн.
Учитывая нормали отдельных пикселей, пиксельный шейдер анализирует показатели карты отражения и преломления в разных точках, координаты рассчитываются с помощью уравнений Френеля.
Карта отражения, карта преломления и карта рельефа
Вода «До»
И, как итог, получаем следующее изображение:
Вода «после»
Результат приятно радует. В сочетании с удачным эффектом ряби, вода выглядит очень реалистично.
Зеркала
Зеркала визуализируются по той же схеме, что и вода. В этой ситуации все даже гораздо проще, ведь зеркала только отражают свет и здесь не нужно учитывать его преломление.
Зеркальное отражение
В отличие от воды, поверхность зеркала идеально ровная и неподвижная, а потому не так-то просто скрыть весьма низкое разрешение объекта – тексели видны очень хорошо. Повысив параметры отражения в настройках, получаем более высокое разрешение.
Для создания карты отражения требуется дополнительный этап рендеринга сцены, а ведь это задача не из простых. Движок не позволяет запустить этот процесс, если зеркало не видно в дверном проеме или игрок находится слишком далеко от него (в этом случае зеркало напоминает черный квадрат).
Помните, что в карте окружающей среды, которая генерируется в начале каждого кадра, нет ни персонажей, ни машин, а только основные здания и пейзаж?
Как в таком случае фары авто на следующем скриншоте отражаются в мокром асфальте?
Отражения фар
В кадре, который я анализировал в Части 1, это не было очевидным, поскольку был день. Но, по сути, после объединения всех буферов, один за другим отрисовываются фары. Для каждой лампочки высчитывается количество света, излучаемого в другие графические сетки, включая сильное отражение от глянцевых поверхностей, вроде мокрого асфальта.
Фары 0%
Фары 50%
Фары 80%
Фары 100%
Для каждого источника света отрисовывается своя графическая сетка: изначально она похожа на ячеистый октаэдр, но впоследствии шейдер вершин видоизменяет сетку, чтобы она соответствовала форме светового ореола.
Эта графическая сетка не текстурирована, она лишь помогает сгруппировать пиксели внутри светового ореола таким образом, чтобы можно было применить пиксельный шейдер. Шейдер позволит динамически рассчитать освещение в зависимости от глубины пикселя, его расстояния до источников света, его нормалей и наличия зеркальных/глянцевых свойств.
Ниже вы видите светокопию графической сетки, используемой для расчета освещения дороги фонарем.
До построения сетки
После построения сетки
При таком рассмотрении становится очевидным одно большое преимущество отложенного шейдинга по сравнению с прямым: в сцене можно визуализировать большое количество источников света, практически, без помощи пиксельного шейдера, который обрабатывает только пиксели, освещенные теми или иными объектами. При прямом шейдинге приходится рассчитывать воздействие сразу нескольких источников света на фрагмент кадра, даже если он не освещен или впоследствии перекрывается другим фрагментом.
А раз вы до сих пор читаете мой обзор, предлагаю перейти к его завершающей части, посвященной пост-эффектам.
Эффекты пост-обработки
Пост-эффекты применяются после завершения рендеринга сцены, чтобы повысить качество деталей, внести корректировки, создать новую атмосферу…
В Части 1 мы видели, как накладывались отдельные пост-эффекты, в частности, свечение, сглаживание и тональная компрессия. Сегодня поговорим о других эффектах, встречающихся в GTA V.
Блики и световые полосы
Иногда, когда свет проходит через реальную линзу, рассеивание и внутреннее преломление лучей приводят к их искажению.
«Бликами» в этой статье я назвал несколько ярких пятен вдоль одной оси, образованной ярким источником света и центром экрана. Есть также «световые полосы» – лучи от источника света. Такого рода искажения очень распространены в фильмах, и, когда они появляются в игре, создается некоторый эффект «синематичности».
Блики и световые полосы
Как правило, используется 2 способа визуализации таких эффектов:
Основа
Основа + полосы света
Основа + полосы света + блики
Основа + полосы света + блики (сверхчувствительная светокопия)
Движок использует несколько спрайтов для имитации различных эффектов искажения линзы:
Эффекты искажения
И, как итог, мы получаем следующий результат:
Базовое изображение
Базовое изображение + блики
Базовое изображение + блики (светокопия)
В GTA V большое внимание уделяется деталям, и блики не исключение: их размер пропорционален диафрагме камеры. Так что, если вы вдруг посмотрите на солнце, блики сначала увеличатся, а затем, как только диафрагма сузится, уменьшатся. Приведенная ниже анимация прекрасно иллюстрирует данную особенность.
Приятно и то, что если вы перейдете в режим от первого лица, бликов, практически, не будет, ведь теперь вы все видите глазами человека, а не через объектив камеры.
Широкая диафрагма
Узкая диафрагма
Анаморфические линзы
Ночью или при игре на темных участках карты моделируется эффект анаморфических линз: длинные вертикальные или горизонтальные, как правило, синие, полосы. В последнее время незначительные полосы от анаморфических линз получили широкое распространение в практике Голливуда, ведь они нередко появляются в новых научно-фантастических фильмах.
Здесь эффект достигается с помощью спрайтов, так же, как и в случае с солнечными лучами, который мы рассмотрели ранее. Правда, он применяется только на очень ярких, как фары автомобиля, источниках света, направленных прямо в камеру.
Анаморфный эффект «До»
Анаморфный эффект «После»
Глубина резкости
В кино сцена, представленная ниже, выглядела бы немного «искусственной»: все слишком резкое и четкое, а ведь в фильме пейзаж на заднем плане оказывается не в фокусе, слегка размытым.
Базовое изображение
Нужно всего лишь добавить глубину резкости (DoF), размыв области изображения, которые остаются не в фокусе.
Как это сделать? Сначала на основе буфера глубины генерируется карта нерезкости (CoC). Она позволяет вычислить насколько пиксели вне фокуса, а, соответственно, задает и степень предстоящего размытия. Значение CoC отдельного пикселя зависит исключительно от его расстояния до камеры (глубина) и параметров объектива.
Для чего нужны числовые значения?
Все потому что добиться достойной глубины резкости не так-то просто и приходится учитывать множество факторов, применяя к сцене эффект размытия.
Например, вы не хотите, чтобы пиксель вне фокуса на втором плане не перекрывал соседний из фокуса, расположившийся перед ним. А что если стоит обратная задача: нужно, чтобы размытый пиксель переднего плана перекрывал четкий фрагмент, стоящий позади него. Как только дело доходит до размытия пикселей, вопрос не в том, «насколько сильно размывать», приходится также анализировать близлежащие фрагменты, которые могут быть как перед, так и позади исследуемого пикселя, как вне, так и в фокусе… Числовой формат значений CoC заметно облегчает задачу.
На карте CoC, приведенной ниже, я использовал зеленый канал для CoC> 0 и красный канал для CoC