Фотореалистичная графика на уровне ААА в Unity

image-loader.svg

До сих пор распространено мнение о том, что Unreal Engine превосходит Unity в графическом плане, но так ли это в действительности? (Спойлер: нет.)

Такое мнение сформировалось по ряду причин. Первая из них отсылает нас к 2015 году, когда в Unity был доступен лишь встроенный конвейер рендеринга с рядом ограничений. На тот момент добиться сопоставимого с Unreal Engine визуала было очень сложно. Другой причиной является порог входа в Unity: он довольно низкий, а начинающим программистам и дизайнерам совсем не очевидна концепция компонентной системы Unity, что порождает довольно много слухов по сей день.

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

Всем под кат! Далее мы расскажем, как добиться фотореалистичной графики в Unity.

Вместо оглавления:

Основные механизмы улучшения графики
Настройка встроенного конвейера
Настройка универсального конвейера
Подготовка к работе с эффектами универсального конвейера
Работа с эффектами универсального конвейера
Заключение
Бонус: превью эффектов post processing

Основные механизмы улучшения графики

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

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

По компоновке, доступности и удобству использования Unreal выгодно отличается от Unity. Главное преимущество Unreal Engine в том, что постпроцессинг включается по умолчанию, как только вы создаете проект. В Unity постпроцессинг нужно включать отдельно, через специальное окно менеджера пакетов. Для базовой настройки эффектов в Unity доступно несколько конвейеров рендеринга с поддержкой сценариев с предопределенными шаблонами. При использовании HDRP качество изображения, достигаемое в Unity с учетом определенных настроек, о которых пойдет речь ниже, не отличить от качества изображения в Unreal Engine.

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

Настройка встроенного конвейера

При использовании стандартного конвейера рендеринга в Unity вы можете скачать специальный пакет Post Processing через Package Manager. Мы будем использовать универсальный конвейер рендеринга URP версии Unity 2020.3.16f1 LTS (версия с долговременной поддержкой). Но если вы используете встроенный конвейер рендеринга, то его необходимо настроить:

  • Выберем Window → Package Manager и скачаем пакет Post Processing. В папке Assets мы создадим папку Graphics, а в ней создадим папку PostProcess. Теперь нажмем по свободной области правой кнопкой мыши, выберем Create → Post-Process Profile. Создастся файл с соответствующим именем.

  • В иерархии создадим пустой объект. Нажмем правой кнопкой и выберем GameObject → Create Empty, назовем его PostProcessingBox (PPB). Добавим компонент PostProcessLayer на объект камеры, а компонент Post Process Volume к созданному ранее объекту PPB. К нему также добавим компонент Box Collider и активируем параметр isTrigger. Теперь, при условии нахождения камеры внутри границ объекта PPB, PostProcessing будет активен.

  • Создадим специальный слой рендеринга PostProcess. В верхней части выбранного объекта выделим Layer с параметром Default и перейдем в AddLayer. В любом из пронумерованных слоев создадим слой PostProcess.

  • На компоненте PostProcessLayer, который мы добавили к камере ранее, в параметре Layer выберем созданный нами слой PostProcess. Затем добавим этот же слой к объекту PPB. Для того чтобы повысить качество картинки и использовать AO (Ambient Occlusion) по максимуму, необходимо изменить путь визуализации в конвейере рендеринга с прямого на отложенный и включить поддержку HDR. Это можно сделать в настройках проекта, в окне «Качество» (Quality).

Направленный свет Directional Light является аналогом солнечного света. Он может освещать всю сцену, оставаясь единственным источником освещения. Это в свою очередь приводит к проблеме сглаживания перспективы, т.к. теневая карта покрывает большую часть или всю сцену целиком. Cкриншот «бородатой» картинки прилагается.

image-loader.svg

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

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

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

Подробнее о направленном свете в Unity написано здесь.

Настройка универсального конвейера

Универсальный конвейер рендеринга (URP, ранее LWRP) — это готовый конвейер рендеринга Unity с поддержкой сценариев. С помощью URP можно быстро и легко создать оптимизированную графику на различных платформах, от мобильных до высокопроизводительных консолей и ПК.

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

Для начала создадим новый проект в Unity Hub. Нажав на кнопку New, мы увидим различные шаблоны, которые Unity предлагает для начала работы. Выберем URP из предложенных шаблонов (Templates) и нажмем на кнопку Create.

image-loader.svg

URP будет автоматически установлен и настроен.
Unity-проект откроется и в окне иерархии (Hierarchy). Мы увидим простую сцену с объектами главной камеры, освещением постпроцессинга и 3D-моделями, подготовленными в качестве примера.

Нас интересует Post-process Volume, но перед тем как продолжить, проверим, какое цветовое пространство выбрано в Unity.

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

image-loader.svg

Перейдем в File → Build Settings → Player Settings → Other Settings → Rendering и убедимся, что в параметре Color Space* выбрано цветовое пространство Linear. Если выбрано пространство Gamma, то необходимо переключиться на Linear.

image-loader.svg

Подготовка к работе с эффектами универсального конвейера

Вернемся к объекту сцены Post-process Volume. Выберем его и перейдем на вкладку «Инспектор» (Inspector). Здесь отображаются базовые параметры компонента Volume.

image-loader.svg

Компонент Volume можно добавить к любому GameObject, включая камеру, но Unity рекомендует создавать отдельные GameObject для каждого Volume в сцене.
Компонент Volume сам по себе не содержит фактических данных. Он ссылается на профиль в параметре Profile, который содержит значения для интерполяции. Эффекты в профиле Volume по умолчанию скрыты. Чтобы просмотреть, добавить или изменить эти эффекты, нужно нажать на кнопку Add Override (переопределение).

URP в настоящее время не поддерживает настраиваемые эффекты постобработки. Если в вашем проекте используются настраиваемые эффекты постобработки, их нельзя воссоздать в URP.

Перед тем как добавить новый эффект, настроим базовый параметр Mode, который отвечает за область применения текущего компонента постпроцессинга. По умолчанию указано значение Global: все объекты на сцене будут проходить через постпроцессинг. Но мы переключимся на Local и посмотрим, как контролировать постпроцессинг в нужной нам области.

В интерфейсе появится параметр Blend Distance и кнопка добавления коллайдера.

image-loader.svg

Нажмем на нее и выберем из выпадающего списка Box. Компонент Box Collider будет добавлен в нижнюю часть вкладки «Инспектор».

Для параметра Size установим значение »10 10 10».

image-loader.svg

Чтобы увидеть текущую границу постпроцессинга, нужно выбрать параметр Gizmos на вкладке Scene. Границы постпроцессинга будут выделены зеленым полупрозрачным кубом. В параметре Blend Distance выставим значение »3». Поскольку к любому объекту в иерархии можно добавить компонент Volume, мы можем применять различные эффекты постпроцессинга для отдельных участков сцены. Эти эффекты будут интерполировать между собой на расстоянии, заданном параметром Blend Distance.

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

image-loader.svg

Работа с эффектами универсального конвейера

Вернемся к теневым картам и настроим их для нашего универсального конвейера.

Для этого в шапке Unity нажмем на кнопку Edit и выберем Project Settings. Откроется соответствующая вкладка. Выберем из списка параметр Quality и в графе Rendering нажмем на выбранный ассет UniversalRP-HighQuality. В нижней вкладке Project подсветится нужный компонент, нажмем на него и перейдем на вкладку «Инспектор» (Inspector).

image-loader.svg

В открывшейся вкладке настроим параметр Shadows:

  • в Сascade Count укажем 3;

  • в Split 1 укажем 12;

  • в Split 2 укажем 15;

  • в Depth Bias поставим 1;

  • в Normal bias поставим 0.8;

  • ставим галочку на Soft Shadows.

image-loader.svg

В результате получим более четкие тени на переднем и заднем планах с учетом каскада.

image-loader.svg

Давайте добавим новый эффект. Нажмем на кнопку Add Override, в открывшейся панели выберем post-processing, далее выберем Panini projection.

Объект Main Camera имеет параметр Field Of View (поле зрения). По умолчанию этот параметр выставлен в 60 градусов, поэтому объекты по углам сцены в окне Game приобретут эффект дисторсии (растяжения).

image-loader.svg

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

image-loader.svg

Вместо проекции Panini projection можно воспользоваться настройкой физической камеры, включив свойство Physical camera в компоненте Camera. Настройка этой системы выходит за рамки данной статьи.

Вы уже могли заметить, что в эффектах отсутствует затенение Ambient Occlusion, которое, в отличие от прямого освещения, добавляет реалистичности и объема объектам на сцене. Для применения эффекта выберем вкладку Project и перейдем в папку Settings, где лежит профиль для Volume, который мы настраивали выше. Выберем ForwardRenderer.asset и перейдем на вкладку Inspector. Нажмем на кнопку AddRendererFeature и в открывшемся окошке выберем компонент Screen Space Ambient Occlusion. Теперь на вкладке «Инспектор» появится добавленный компонент New Screen Space Ambient Occlusion.

image-loader.svg

Оптимальных параметров для настройки этого объекта нет, они подбираются индивидуально. Мы предлагаем следующие настройки параметров:

  • Source — выберем Depth Normals. Параметр Normal Quality при этом блокируется, он будет доступен только при выборе Depth (в некоторых сценариях с помощью этого параметра можно улучшить качество затенения);

  • Intensity — 1.58;

  • Direct Lighting Strength — 0.217;

  • Radius — 0.1;

  • Sample Count — 4.

Вернемся к настройке постпроцессинга. Выберем PostProcessValue и перейдем на вкладку «Инспектор». Нажмем на длинную кнопку Add Override (через нее мы будем добавлять все остальные постэффекты) и выберем хроматическую аберрацию (Chromatic Aberration). Аберрацию обычно используют для получения эффекта искажения цвета, которое создает реальная камера, когда ее объектив не может объединить все цвета в одну точку. (Эффект, в частности, с завидной регулярностью наблюдается в костюмах главного героя серии игр Crysis.) Если выкрутить параметр Intensity на 1, сможем насладиться этим эффектом во всей красе.

image-loader.svg

Не забываем вернуть значение Intensity в 0.1.

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

Теперь добавим эффект небольшой размытости отдаленных объектов (Depth Of Field).

image-loader.svg

Давайте придадим нашей картинке еще более правдоподобный вид.

Добавим эффект Color Adjustments и настроим его следующим образом:

Теперь повысим яркость в нашей сцене для получения большего динамического диапазона в работе над светом. Перейдем в панель Lighting. Нажмем на кнопку Window в шапке Unity, выберем Rendering → Lighting, в открывшейся вкладке выберем вторую закладку Environment, в разделе Environment Lighting установим значение Intensity Multiplier на 2.

image-loader.svg

Поскольку мы работаем с запеченным освещением, необходимо нажать на кнопку Generate Lighting внизу вкладки. Unity автоматически начнет запекать карту освещения. Перед этим рекомендуем сделать сцену чуть более яркой, установив значение Indirect Intensity на 2.

image-loader.svg

Теперь в окне Hierarchy выберем объект Directional Light и вернемся к вкладке «Инспектор». Установим значение Intensity на 2.

image-loader.svg

Вернемся в Post-Process Volume и добавим семь эффектов:

  • Color Adjustments;

  • Film Grain;

  • Color Curves;

  • Vignette;

  • Bloom;

  • Motion Blur;

  • Lift Gamma Gain.

Vignette — стандартная маска-виньетка, которая затеняет кадр по краям. Для этого эффекта активируем два параметра и установим следующие значения:

  • Intensity — 0.3;

  • Smoothness — 0.4.

Теперь настроим параметры в эффекте Bloom, который отвечает за свечение и блики (например, когда вы смотрите на очень яркий объект вблизи), и посмотрим на результат:

image-loader.svg

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

Давайте настроим Motion Blur:

  • Quality medium;

  • Intensity — 1;

  • Clamp — 0.03.

Так будет выглядеть картинка с эффектом Motion Blur при резком движении камеры вперед:

image-loader.svg

Попробуем поиграть с нашими настройками цветов. В Color Adjustments установим Post Exposure в значение 0.4, а Contrast в значение 10 и опустим Saturation в значение -18.

Теперь в фильтре Film Grain установим Type Thin в значение 2, в параметре Intensity установим 0.2 и в Response выставим 1. Минимальный шум необходим, особенно в темных участках, т.к. мы постоянно его воспринимаем, но не всегда отдаем себе в этом отчет.

В Color Curves выберем параметр Master и нажмем на Override, чтобы поработать с кривыми. Для того чтобы добиться кинематографичности, нам необходимо подрезать информацию в нижней части спектра. Теория цветокоррекции и кривых выходит за рамки этой статьи, поэтому просто создадим ключ в нижней части кривой, сделав двойной клик по кривой, как показано на снимке, и установим для ключа значения 0.044 и 0.066.

image-loader.svg

Предлагаем вам поиграться с параметрами настройки Lift Gamma Gain самостоятельно.

Сравним наш текущий результат с изначальным.

image-loader.svgБонус!

Вы также можете поработать с HDRP, там есть volumetric light и красивый fog. Вкупе с PBR-текстурированием можно получить реалистичный результат, но оставим HDRP для нашей следующей статьи.

Скриншот для затравки:

image-loader.svg

Заключение

Мы узнали о том, как создавать постэффекты и как ими управлять. Смогли сделать качественный визуал, за который не стыдно. В сцену можно было добавить PBR, 3D-модели с системой LOD, использовать VFX Graph для частиц и получить отличные результаты. Пусть это будет вашим домашним заданием.

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

Конвейеры Unity стали гораздо более быстрыми и оптимизированными, но по-прежнему не позволяют добавлять кастомных эффектов, только пресеты для URP. Этот минус обещают исправить, ну, а мы подождем.

SPIN-код автора: 1418–2378

Бонус: превью эффектов post processing

Ниже приведены примеры всех визуальных эффектов, доступных в Post Processing.

image-loader.svg

Окклюзия окружения (Ambient occlusion (AO)) — математическая модель затенения, применяемая в компьютерной графике. Используется для вычисления параметра интенсивности света. Окклюзия окружения затемняет складки и дыры и делает графику в компьютерных играх более реалистичной.

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

Глубина резкости — имитирует объектив камеры, в котором фокус находится в определенной точке, а все, что находится за пределами этой точки, размыто.

Размытие в движении — размывает объекты, которые движутся мимо. Используется, например, для уменьшения внимания к окружению, когда вы фокусируетесь на бегущем персонаже или на машине, проезжающей мимо.

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

Цветовая градация — изменяет и улучшает цвет конечного изображения. Используется для создания настроения или исправления неправильной окраски каких-либо объектов.

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

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

Виньетка — затемняет и обесцвечивает изображение по краям.

Искажение объектива — искажает изображение, имитируя аберрацию оптических систем реальной камеры.

Автоэкспозиция — динамически регулирует экспозицию изображения в соответствии с диапазоном уровней яркости изображения.

Eye Adaptation (Auto Exposure) — эффект привыкания глаз к условиям освещения (например, при переходе из темных зон в светлые).

© Habrahabr.ru