Как сделать красивую графику для игры на Unity

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

Unity как графический движок: преимущества и недостатки

Как сделать красивую графику для игры на Unity

В современном геймдеве есть несколько коммерческих движков. Unity, Unreal, CryEngine, Valve Source. Есть и менее известные, вроде Unigine. У каждого свои преимущества и недостатки. Unity прост в обучении, прост в программировании и прощает огромное количество ошибок новичкам. Его преимущества в использовании языка C # и в открытости системы рендера, о которой и пойдет речь дальше.

Итак, небольшой обзор рендера Unity. Изначально он создавался с оглядкой, да что там с оглядкой, в основном под мобильные платформы, поэтому его сделали максимально гибким и минимально привязанным к какому-то конкретному железу. То есть если очень хочется попользоваться какими-то специфичными функциями от нужной нам железяки — Nvidia или AMD, — не всегда получится.

Из преимуществ: в Unity есть два варианта рендера (в Unity5 три) — forward, deferred, и, для Unity5, legacy deferred (deferred от Unity4). Различие, если кратко, в принципе просчета освещения.

Как сделать красивую графику для игры на Unity

Преимущества и недостатки Unity4

Плюсы:

  • быстрый и достаточно хорошо кастомизируемый графический движок, который работает даже на очень старом РС-шном железе и новых мобильных платформах достаточно быстро;
  • позволяет использовать разные пути расчета в зависимости от задач;
  • неплохо документирован, возможность замены любых стандартных шейдеров (идут в комплекте в исходном коде) на свои — это огромный плюс;
  • батчинг деревьев и их билбордов.

Минусы:

  • сложность системы освещения — недостаточное количество информации в G-Buffer Unity4 делает написание шейдеров освещения для него затруднительным;
  • сложность понимания и взаимовлияния между проходами (хотите узнать, где у вас тень на меше в диффузном шейдере, — а тут не так все просто);
  • ограниченные возможности расширения G-Buffer, ограниченные возможности в deferred-режиме для различных моделей освещения и материалов;
  • система террейна и встроенный конструктор деревьев — очень интересные, но очень нелогичные вещи, заточенные на оптимизацию, но никак не на удобство.

Преимущества и недостатки Unity5

Плюсы:

  • 64 бита. Наконец-то. Можно делать большие уровни и использовать 8К-текстуры;
  • при наличии напильника можно без особой боли перепилить старый проект под новый движок. Если нет лайтмаппинга, разница почти незаметна;
  • возможности GI (global illumination), PBS (physically based shading) из коробки и прочие вкусности, новые PCF-тени (менее жесткие и быстрые);
  • высокая кастомизация — исправление встроенных шейдеров, дописывание своей логики в редактор, возможность использования и расширения разных путей рендера.

Минусы:

  • измененная логика проходов (зависимость попадания источника тени с Z-Buffer: кто не отбрасывает тень, в Z-Buffer не попадает. Чертовски неудобно местами, убран проход Shadow-Collector);
  • встроенные деревья работают очень странно (были непонятные артефакты по контурам веток);
  • обычный deferred не так уж и быстр — при буфере в 192 бита на пиксель скорости не добавляется;
  • все еще в бете, работа GI и лайтмаппинга постоянно дорабатывается.

Как сделать красиво в Unity4

Как сделать красивую графику для игры на Unity

Думаю, читателя больше всего интересует, как быстро сделать, чтобы его игра или проект стал красивым и нарядным. Желательно, сразу и одной кнопкой. Попробуем сделать это в Unity4.

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

1. Определить, где происходит действие — внутри или снаружи помещений. Будет ли использовано большое количество источников света. Если снаружи, и нет множества источников света — проще использовать forward, если внутри или есть много световых источников — deferred. Если свет запекается — почти все равно.

2. Определиться со сменой погоды и временем суток. Если смены нет — все проще. Одно небо в HDR. Если есть — нужно подготовить несколько вариантов неба. Потом написать процедурную смену.

Теперь за работу. Есть несколько наборов пакетов, которые позволяют достаточно серьезно поменять картинку. Первый из них — Marmoset SkyShop. Второй на выбор — Alloy, Lux или Shader Forge. Все эти пакеты шейдеров дают красивую дополнительную картинку для корректного отображения физических материалов. Однако обычно хватает SkyShop.

Третий — Amplify Color, ProFlares или SSAO Pro. Хорошие и профессиональные цветокорректоры, профессиональные блики от линз, и SSAO с дополнительными параметрами (для отключения влияния затенения на туман).

Сразу замечу — все пакеты платные.

Поставьте и подключите SkyShop. Настройте небо и переключите шейдеры сцены, где нужно. Поставьте Lux (если это действительно нужно) и подстройте оставшиеся шейдеры.

Что значит «подстроить» и «подключить»? Во-первых, нужно скачать и установить пакет SkyShop. И, если нет желания смотреть длинные и сложные туториалы, то:

  • зайти в меню Window/Skyshop. Будет добавлен Sky Manager;
  • в редакторе неба выбрать текстуру неба (желательно HDR не более чем 4096х2048, обычно это панорама, но подойдет и кубомап, и прочие);
  • выбрать размеры для получаемой текстуры неба (дифуз) и текстуры отражения для спекуляра (обычно дифуз — 4096, а спекуляр — 256-512);
  • выбрать качество просчета Ultra и просчитать на GPU. Если текстура неба больше чем 4096x2048, поправить коэффициенты фильтров (но крайне не рекомендуется, так как работа с небом в 8К — очень и очень небыстрое дело) нажать кнопку «добавить в сцену»;
  • заменить дифуз и спекуляр шейдера на соответствующие шейдеры Marmoset;
  • заменить террейн-шейдер (если автоматически не был заменен);
  • обновить (нажать refresh) на закладке деревьев в террейн-редакторе;
  • если текущее небо не стало активным, вручную активировать его в объекте SkyManager;
  • настроить влияние неба на освещение сцены в свойствах созданного неба.

Итак, мы активировали IBL-освещение. Для краткого понимания, что это такое: когда-то отражения в воде делали через cubemap от текущего skybox. Вода всегда отражала окружающее небо и ничего больше — очень быстро и очень просто. Этот же подход позже применили для освещения объектов окружающим их skybox. То есть небо и окружение вносит свой вклад в освещение всех элементов сцены, что делает общее впечатление от сцены гораздо более реалистичным.

Установите Amplify Color и настройте цветокоррекцию. Добавим эффекты SSAO Pro (screen space ambient occlusion — дополнительное затемнение в зависимости от геометрии сцены) и SkyShaft (он же GodRays — пробивающиеся лучики солнышка из стандартных пресетов), не забывая указать на источник света, GLobal Fog — и вот картинка уже гораздо веселее.

Вариант добавления отражений — Reflection Manager. Он требует доработки в случае использования со SkyShop. В последних версиях SkyShop есть свой box projection. Однако его использование не всегда просто и «безглючно». Но ребята из Marmoset ошибки постоянно устраняют, поэтому, скорее всего, он уже готов к использованию, и Reflection Manager не понадобится.

3. Определиться с набором «локальных» скайбоксов. В Marmoset есть возможность расстановки регионов и триггеров для локальных скайбоксов. Это позволяет сделать гораздо более натуральным освещение на определенном участке.

Детальный тюнинг

Составляющие картинки

1. Основная составляющая картинки для фотореалистичного рендера — освещение. Если с освещением плохо, убедить игрока полностью не получится. Субъективно, ощущение от освещения — 40% ощущения от картинки. Освещение — сложная тема. Рассмотрим ее подробнее. Для понимания, как это работает, проще рассмотреть пошаговое изменение картинки, при включении всех возможностей, которыми мы хотели бы воспользоваться. Для начала я убрал цвета текстур (albedo), чтобы лучше видеть влияние освещения.

Итак, база:

Как сделать красивую графику для игры на Unity

Здесь нет ничего, кроме контуров геометрии. Включаем один источник света. Да будет свет!

Как сделать красивую графику для игры на Unity

Мы включили источник освещения без теней. Все цвета albedo установлены на 50% серого. Включим тени и изменим цвет на белый.

Как сделать красивую графику для игры на Unity

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

Как сделать красивую графику для игры на Unity

Картинка становится интереснее, однако освещение все еще очень искусственное. Добавим SSAO — систему затемнения на стыках геометрии внутри сцены.

Как сделать красивую графику для игры на Unity

Получается достаточно натурально. А теперь добавим IBL — освещение сцены в зависимости от окружающего неба.

Как сделать красивую графику для игры на Unity

Вот этот коричневатый оттенок — влияние окружающего освещения на картинку. Для лучшего понимания включим цвет на небе.

Как сделать красивую графику для игры на Unity

А теперь сравним, что получится, если мы сменим небо на другое.

Как сделать красивую графику для игры на Unity

Замена неба очень сильно влияет на картинку. В данном случае в IBL-компоненте присутствует и дифузная, и спекулярная составляющие.

Посмотрим на детальный срез технологий и улучшение картинки в черно-белом варианте.

Как сделать красивую графику для игры на Unity

Вот визуальное отличие. Каждая дополнительная технология освещения вносит свою долю реалистичности в картинку. Теперь отключаем IBL и включаем цвет.

Как сделать красивую графику для игры на Unity

Темно и грустно. Попробуем добавить SSAO.

Как сделать красивую графику для игры на Unity

Реалистичнее, но еще темнее. Попробуем увеличить интенсивность источника света.

Как сделать красивую графику для игры на Unity

Вот этот вариант более похож на стандартное освещение Unity4. Либо все темное, либо выглядит очень искусственно и пересвечено. Убираем интенсивность источника, убираем SSAO, включаем IBL.

Как сделать красивую графику для игры на Unity

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

Как сделать красивую графику для игры на Unity

Картинка сильно изменилась. И выглядит очень натурально. Сравнение:

Как сделать красивую графику для игры на Unity

Добавляем постпроцессы.

Как сделать красивую графику для игры на Unity

Здесь присутствуют стандартные постпроцессы: SSAO, Bloom, SunShafts, GlobalFog. Получилось практически то, что нужно. Можно еще добавить по вкусу эффект глубины резкости — для размытия контуров дальних деревьев.

Как сделать красивую графику для игры на Unity

Итак, работа над картинкой завершена. Посмотрим с другого ракурса:

Как сделать красивую графику для игры на Unity

Теперь посмотрим, как работает IBL в сочетании с фотограмметрическими ассетами (подход, широко разрекламированный командой игры Vanishing of the Ethan Carter, которая, впрочем, аккуратно использовала только одну погоду, отсутствие динамических теней и вообще динамического освещения). Фотограмметрические ассеты основаны на восстановлении из фотографии 3D-модели. Более подробно это описано в блоге у «астронавтов», однако для описания использования воссозданных моделей в PBR требуется отдельная статья.

Пока же просто покажем, как модель, воссозданная по фотографиям, чувствует себя среди IBL-освещения. В данном случае я взял модель коряги, восстановленную после фотограмметрирования по 170 фотографиям. Геометрия модели достаточно сложная, однако удалось восстановить её достаточно детально. Затем сделать низкополигональную модель и снять нормали. Скриншоты модели из MeshLab.

Как сделать красивую графику для игры на Unity

Модель в сцене.

Как сделать красивую графику для игры на Unity

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

Как сделать красивую графику для игры на Unity

IBL действует очень хорошо. Стоит заметить, что для натуральных природных вещей спекулярный компонент влияет крайне незначительно, как и френель.

Итак, с базовыми элементами освещения разобрались.

2. Модели — текстуры и геометрия.

Создание хорошей и качественной геометрии и текстур — задачка тоже не из легких. Однако если раньше требовалось специально оптимизировать меши и соединения вершин, то сейчас все несколько упростилось. Напомню, что в картинке по-прежнему максимум 2 млн треугольников и до 2 тысяч drawcalls для PC. Если вы делаете шутер и хотите 60 и более FPS — и того меньше. Не забываем модный нынче PBR и текстурки для него в моделях.

Замечу, что Marmoset SkyShop в Unity4 использует не совсем полную поддержку PBS, однако в большинстве случаев ее хватает с головой. Также стоит определиться, какой подход для создания текстур и материалов вам более удобен. Сейчас их два — металлик и спекулярный.

Unity5 официально поддерживает оба подхода, однако SkyShop поддерживает урезанный спекуляр-подход. Для металлик-подхода можно использовать другие пакеты шейдеров, однако их совместимость с IBL от SkyShop периодически оставляет желать лучшего. Разница в подходах детально описана здесь. Где найти модели.

3. Если игра на природе — позаботьтесь о деревьях, траве, кустах. Тут, как и с освещением. Долгая история. Особенно в Unity.

4. В некоторых играх важно не забыть о воде. Речной, озерной, океанской. Динамической или статической.

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

5. В постэффектах сложно соблюсти правильные пропорции.

Многие увлекаются DOF, bloom и прочими вкусностями. Рекомендации — хороший туман и ленсфлар с SSAO. Bloom по вкусу, но лучше не переборщить. Для линейного цветового еще tonemapping. Обычный GlobalFog и SSAOPro неплохо сочетаются.

6. Тени. В Unity они есть, очень неплохие из коробки. Можно не трогать (неужели тут что-то все-таки можно не трогать?).

7. Небо. Проще всего использовать один или несколько статических скайбоксов в Marmoset. Так как если делать IBL, то динамическое небо резко становится несколько проблемным.

Улучшаем картинку — практические советы

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

Для десктоп-систем стоит ориентироваться на два вида — офисные и игровые. Офисные компьютеры более слабые, имеют встроенные видео-подсистемы. Игровые или домашние обычно несколько более продвинуты.

Чтобы получить хорошую картинку, нужно обратить внимание на два фактора — drawcalls (в Unity5 — batches), и миллионы треугольников в сцене. Для офисных систем это, в идеале, около 1 тысячи drawcalls и 1 млн треугольников. Для игровых — 1,5-1,8 тысяч drawcalls и 1,5-2 млн треугольников (или даже больше).

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

Первым делом уменьшаем количество геометрических фигур. Для уменьшения треугольников используем LODs, oclussion culling, правильно настраиваем появление billbords-деревьев и pixel error в террейне. Следим, чтобы количество треугольников не сильно менялось в зависимости от угла зрения.

Затем занимаемся drawcalls. Здесь есть два варианта — уменьшение количества используемых в сцене материалов и батчинг мешей — объединение геометрии различных статических мешей в одну. Сильно оптимизировать стоит только если очень хочется заморочиться. Можно просто взять один из компонентов из Asset Store, который неплохо это делает. Однако важно помнить, что для успешного объединения меши должны разделять один материал. Хорошо справляется с задачей Advanced Foliage System, но он не совсем совместим с Marmoset.

Все это можно увидеть в информации Stats на панели Game.

Как сделать красивую графику для игры на Unity

В Unity Pro также есть профайлер, который позволяет посмотреть, что именно рендерится дольше всего или вызывает задержку — CPU, GPU, или что-то еще.

Итак, мы оптимизировали геометрию и материалы. Следует предостеречь от использования двусторонней геометрии (автозашивание — создание второго слоя геометрии, для листьев, например). Используйте шейдеры для односторонней геометрии, иначе рискуете столкнуться с Z-fighting — стробированием близко стоящих элементов геометрии, или их теней.

Тени. Включение теней добавляет два drawcalls на каждый материал с тенью. Один на прием тени, один на отбрасывание. Итого, включение теней умножает количество drawcalls на два в Unity4. В Unity5 проход приема теней отключен, потом drawcalls меньше. Динамические тени следует использовать аккуратно, существенно уменьшив расстояние их появления.

Для красоты теней и ускорения стараемся использовать lightmapping, если у нас статическое освещение. Что это значит — считаем карты для освещения и AO везде, где можем. Marmoset SkyShop упрощает и ускоряет настройку статического освещения для вариантов «локального» неба. При использовании статического освещения получаем очень неплохую скорость. Например, в Ethan Carter все освещение статическое. И теней нет совсем. Вывод — правильный выбор освещения ускоряет картинку, но может сделать атмосферу грустной и невеселой (освещение без теней и солнышка).

Природа. При использовании террейн-paint деревья билбордятся, трава тоже, drawcalls, соответственно, существенно понижается. Однако надо помнить, что более четырех видов травы ведет к артефактам (траву Unity «засовывает» в атлас, а размер атласа небольшой).

Деревья и трава будет использовать специальные hidden-шейдеры, странные и неудобные в замене. Деревья — это вообще больная тема. Частично решает ее покупка Nature Pack 2.1 в Asset Store или деревьев от Forst и AFS-пакет. Если хочется совсем красиво для Unity4 — делаем деревья в SpeedTree, красим вертекс-колором в Maya или Max, добавляем «шаталки» для шейдеров Marmoset (потребуется руками его дописать) — и вот, картинка просто великолепная (ну и месяц-другой работы очень недешевых художников, плюс денежка за SpeedTree и шейдерному программисту за модификацию Marmoset). Вывод — для массива лучше пользоваться покраской террейна, для точной расстановки — использовать геометрию.

Подключили Marmoset, расставили «локальные» пробы неба, и смотрим, как все стало замечательно. А, ну да, поставили на просчет lightmapping, и ложимся спать. Потому что всё это совсем не быстро.

Подключаем воду, если нужно. Вода — тема бесконечная, но Unity-вода очень даже неплохая.

Подключаем эффекты. Все, что подключили и настроили, ослабляем чуть больше чем вполовину. Рекомендуется поставить SSAO (подпилить, чтобы через туман не пролезал — или просто купить SSAO Pro), GlobalFog (подпилить, чтобы не пролезал через воду), SunShafts стандартный, ToneMapping (если HDR), и далее — по желанию. Можно также настроить Amplify Color и Motion Blur, Bloom, Dirt Lenses и Lens Flares.

Настройки картинки для постпроцессов — это отдельная история.

Как сделать красивую графику для игры на Unity

Здесь, например, стандартный SSAO, Bloom, SunShafts (Blur 3), Depth Of Field (DX11) с Bokeh. Но в постпроцессах главное правило — не переборщить, и не совать всё что есть, без разбора.

Засада поджидает с фларами — они работают на Raycast-физике, и все, что не коллайдится, игнорируют. Добро пожаловать в создание коллайдеров на все деревья и веточки, и проблемы с листиками. Хотел найти коллайдеры на основе буфера глубины — но ничего хорошего так и не нашел. Причина там более глубокая, повод для отдельной статьи.

Эффекты едят производительность. Особенно SSAO и прочие. Если используется deferred, можно поставить antialiasing постэффектом — так как MSAA нормально работать не будет. Но встроенные antialias-фильтры не слишком хороши. Посмотрели производительность эффектов, ненужное выбросили.

В итоге получили неплохое освещение — lightmapping + dynamic + shadows + soft shadows (осторожно, мягкие тень кушают производительность). Если поставили Marmoset — получите отличный IBL с переключаемыми зонами, хиленький и не очень честный PBR (ограничение архитектуры буфера глубины и нормалей в Unity4), и все это достаточно неплохо смотрится и почти не тормозит даже на достаточно слабых компьютерах.

Если хочется совсем быстро, можно заменить десктопные шейдеры Marmoset на их мобильные аналоги. В этом случае IBL-компонента будет считаться в вертексном, а не пиксельном шейдере, что существенно быстрее, но менее качественно. Но все равно красивее, чем из коробки.

С использованием нехитрого подхода можно получить графику, по качеству не сильно уступающую первому Crysis («шаталки» растительности, вертексная покраска, IBL, SunShafts, translucency и прочее — с точностью до констант скопированы в Unity). А это уже неплохо, и даже очень быстро бегает. Код шейдеров для модифицированного SSAO, GLobalFog и прочие будут выложены в отдельной статье позже.

Вот и все, продолжение следует.

Приложение

Принципы rendering paths для Unity4 и 5

Forward позволяет быстро рассчитывать четыре источника света per pixel, еще до четырех в режиме per vertex, и еще два в режиме сферических гармоник. В случае первых четырех на каждый, кроме первого, используется свой дополнительный проход.

Deferred позволяет получить очень большое количество источников света, которые не отбрасывают теней. Ограничение — в варианте Unity4 в базовых шейдерах deferred доступно только освещение по схеме Blinn-Phong.

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

Deferred в Unity5 состоит из:

  • diffuse color (rgb);
  • specular color (rgb);
  • smoothness (a), была заменена на roughness позже;
  • world normal (rgb, 10.2);
  • emission/light — Floating Point 16, если включен HDR;
  • Z-buffer: depth.

Итого — 160 бит на пиксель без HDR, 192 бита на пиксель с HDR. 4 MRT (MRT — это текстуры, в которые происходит расчет различных частей буфера) — 32 бита, кроме светового в HDR режиме (64 бита). «Толстый» и, скорее всего, не финальный вариант.

Требует OpenGL ES 3.0 на мобильных платформах и не работает на старом РС-железе (десятилетней давности). Для сравнения в Crysis 3.0 — 96 бит на пиксель MRT3 (D24S8, 32,32).

#игры#unity

18 комментариев

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

14
Ответить

Люди пишут про индустрию туда, где им самим приятнее читать об индустрии) К слову, трюкам, фишкам и особенностям Unity возможно будет уделено еще немало внимания в будущем...в процессе обсуждения эта идея, если срастется - скоро сообщим)

4
Ответить

У нас тут самый что ни на есть геймдев!

5
Ответить