Всем привет! Данная статья является продолжением начатого ранее цикла на тему разработки моей инди-игры «Hail to the Rainbow». Первую вступительную часть можно найти по ссылке. В данной же части я хочу рассказать о визуале игры, создании 3d контента и аспектах, связанных с материалами, шейдерами и некоторыми техническими приемами.
Пользуясь случаем, для тех, кто следит за игрой, хотелось бы сделать заметку по поводу предстоящего релиза. Ранее в Steam был приблизительно указан первый квартал 25 года. Но опыт с демкой показал, что столь объемный проект требует более тщательной проработки и тестирования. Хочется все довести до ума без спешки и стресса. Поэтому сроки придется немного сместить. Думаю, перенос несущественный, но каких-либо точных предположений озвучивать не буду, чтобы не вводить в заблуждение. Далее по по теме статьи.
Для начала стоит уточнить еще раз некоторые вводные, касательно среды разработки, версии движка, системы рендера. Проект создается в Unity 2019 на Built-in Render Pipeline. Я с большим скрипом перехожу на новый софт, в практике есть неприятный опыт, когда смена движка ломала проект и требовала много времени на переработку. Поэтому, когда 5 лет назад я начинал работу в 19 версии, я предполагал, что скорее всего буду доводить дело на ней же. Мне приятнее и быстрее работается с проверенным и освоенным инструментом.
3D контент
«Hail to the Rainbow» — мой первый проект столь крупных масштабов. На данный момент по последним тестам время прохождения составляет около 9–10 часов. Поэтому, объемы 3d контента, моделей предметов, сооружений и персонажей весьма велики. Наибольшая часть моделей создавалась самостоятельно, но некоторый процент — это купленные ассеты, а также заказанные на аутсорсе. Есть модельки, с которыми мне помогала супруга, за что ей огромное спасибо. Тем не менее, процент подобного контента небольшой, порядка 5-6%, в основном это предметы окружения, некоторая техника, бытовые предметы. Цифра очень приблизительная, не знаю, как это достоверно посчитать.
Основные подходы
Работая самостоятельно над моделями, я использовал два основных подхода. Крупные объекты, стены, здания, столбы, контейнеры и тд. моделировались и текстурировались чаще всего текстурными атласами и тайлами. Некоторые атласы включали в себя группу разных поверхностей, бетон, ржавые металлические элементы, кирпичи, деревянные части.
Мне нравится такой метод тем, что на один объект в этом случае можно нанести всего один материал, он не имеет составных частей и успешно батчится, что полезно для оптимизации. Почти для всех крупных объектов, и, конечно, для зданий создавалась специальная развертка для лайтмаппинга. Я стараюсь делать развертки вручную, поскольку так можно добиться более экономичной компоновки UV островков. Также, для большинства поверхностей использовалось два слоя текстур, основное покрытие и Detail, затайленная мелкая фактура, зернистость, трещины и т.д. Некоторые здания я делал с помощью заготовок – секций из цокольного этажа, базового этажа и крыши. Таким образом было удобно регулировать высоту.
Второй подход — объекты с индивидуальным набором текстур. Как правило, такой тип объектов создается по стандартному алгоритму: моделирование Low Poly модели, моделирование High Poly, запекание карт Normal map, Ambient Occlusion и проработка материала в Substance Painter. Обычно такая процедура применяется к важным объектам, пропсам, которые игрок может рассмотреть с близкого расстояния, технике, оружию, интерактивным объектам и, конечно же, к персонажам. Модели людей, роботов, техника, автомобиль главного героя — все они проходили полный цикл проработки. В этом случае накапливается большое количество тяжелых текстур, Base Color, Normal, AO, Roughness и т. д., поэтому иногда я делал исключения и для экономии пользовался одним набором текстур под разные задачи. Например, для одной из моделей робота я создавал несколько вариантов голов, и использовал один и тот же материал, перераспределяя островки UV на новые области.
На скриншоте ниже представлен стандартный набор текстур, обычно я помещаю Roughness в альфа-канал Albedo карты, а маски, типа AO и Metallic в разные каналы одного файла (зеленая текстура).
Занятно, что, по моим наблюдениям, во многих крупных проектах иногда используется упрощенный текстуринг без создания индивидуальных карт. Например, в Alien Isolation на многих модулях интерьера заметно использование одних и тех же материалов, без уникальных фасок и деталей непосредственно на текстурах. Полагаю, этот метод позволил значительно сэкономить на ресурсах, хотя, качество при таком подходе ощутимо падает.
Лоды
Важным аспектом работы с моделями стало создание лодов — упрощенных мешей. По мере увеличения числа объектов полигонаж в кадре может иметь высокие значения, особенно при использовании реалтайм освещения. Для оптимизации сложных моделей я обычно заготавливал 3–4 экземпляра лодов. К примеру, исходная модель дрона главного героя имеет 3 тысячи полигонов, последующие же лоды имеют 1900, 1200 и 700 полигонов соответственно. Зачастую, последний лод я вообще превращал в прямоугольник, цилиндр, или простейший шар.
Если же речь идет о деревьях и кустах, в качестве последнего лода использовался примитивный меш из двух плейнов, сложенных крест-накрест. Вообще, тема упрощенной геометрии для лодов или задних планов сцен очень занимательна. Иногда с помощью плоских задников выстраиваются целые городские кварталы. Это очень напоминает декорации в театральных постановках.
В целом, с деревьями было достаточно много экспериментов. На некоторых локациях с большим количеством Draw Calls и реалтайм освещением я использовал интересный прием, у сложных моделей деревьев выключались тени и добавлялся специальный упрощенный меш, который служил источником тени, но сам не отрисовывался. Также, для оптимизации на мешах отключался параметр приема Light Probes, в этом случае объекты с большей вероятностью батчатся и отрисовываются за один вызов.
Роботы и люди
Работа с персонажами всегда является сложной и ответственной задачей. Я понимал, что детальную проработку большого количества человеческих персонажей, да еще и их анимации, я не потяну. Поэтому в большинстве сцен людей я показывал в качестве флешбеков с замазанными лицами. По сюжету это были оцифрованные воспоминания главного героя - Игната, в которых лица он практически не помнит из-за травмы. Основное внимание в работе я уделил самому протагонисту. По сравнению с предыдущими проектами полигонаж ощутимо возрос, в модели Игната около 30 тысяч треугольников (раньше было около 10т.). Я задействовал около 15 костей для управления мимикой персонажа. В игре нет сцен, где он разговаривает, но, благодаря костям, можно отобразить ряд основных эмоций героя.
Для выразительности, также, в шейдере кожи были задействованы маски для создания мимических морщин. Еще одной интересной деталью образа Игната стало использование многослойного шейдера для его шапки, что позволило имитировать шерстяной материал.
С роботами дела обстояли несколько проще, с технической точки зрения их создание аналогично созданию любого другого пропса. Основным нюансом было продумывание костей для риггинга, чтобы некоторые суставные элементы более-менее корректно себя вели во время анимаций. Например, для гидравлических поршней нужно было использовать связки костей с кинематикой, чтобы детали имели верное положение и вектор движения.
Концепты роботов и их назначения в мире игры достаточно тщательно продумывались. Часть из них имеют промышленное назначение, являются автоматами для работы на фабриках, инженерами и погрузчиками. Некоторые относятся к военной области, а некоторые имеют вполне антропоморфное строение и относятся к социальной сфере, например, задействованы в образовательных процессах. По ссылке можно поглядеть демонстрационный ролик с одним из роботов.
Шейдеры поверхностей
Большую часть шейдеров я создавал на базе встроенного PBR Standard. Добавлял дополнительные параметры, маски, новые слои, которые позволяли имитировать рандомные пятна проглядывающего бетона на стенах, например. Важным дополнением была отрисовка снега на поверхностях объектов. Процедурно на основе координат мирового пространства создавалась маска, которая проецировалась на все более-менее горизонтальные полигоны. К слою снега добавлялась также текстура шума для эффекта сверкающих точек-бликов.
Некоторые шейдеры были дополнены масками и настройкой цвета для отдельных участков. Это позволило окрашивать объекты в разные цвета, используя одну и ту же базовую карту Base Color.
Шейдеры растительности
Для большинства деревьев я решил написать свои шейдеры, чтобы понимать их принцип работы и полностью контролировать. Для листвы я использовал программу обработки света ToonRamp, аналогичную примеру из Unity туториала. Данный алгоритм позволяет имитировать сквозное прохождение света сквозь поверхность листвы, что вполне соответствует тому, как освещается реальная растительность. Для данного шейдера, а также шейдера стволов деревьев была также использована маска шума в пространстве мировых координат, с помощью которой в определенных зонах работал ветер, изгибающий верхушки деревьев и ветки. Для высокой травы использовался похожий шейдер, однако он дополнительно получал координаты положения персонажа в пространстве. В этой области вертекс программа смещала вершины травы вниз, ближе к земле, для создания эффекта контакта с игроком, а также для того, чтобы камера не так очевидно проходила сквозь геометрию. Схожий принцип был применён и для автомобиля, чтобы трава не проходила сквозь кузов и не появлялась в салоне. Для подстраховки, ближе к центру салона трава полностью уводилась в прозрачность.
Террейн и следы
Большой пласт работы был связан с материалом террейна и отрисовкой следов от автомобиля и персонажей. Я не преследовал цели создать мега‑детализированные деформационные следы аналогично Last of Us 2 или RDR2. Готовые решения со сторов меня не очень интересовали, поскольку хотелось самостоятельно вникнуть в процесс и отработать технологию.
Сперва я планировал с помощью скрипта менять рельеф террейна в реальном времени, но лично у меня метод оказался чрезвычайно тяжёлым для системы и ощутимо съедал Fps. Второй вариант, который пришёл в голову — рисовать в реальном времени белые пиксели на черной процедурной текстуре и использовать её для смещения вершин в шейдере террейна. Но и этот вариант показался мне не очень удачным.
Ещё одним вариантом, который в итоге неплохо себя зарекомендовал, стало создание дополнительной ортографической камеры, которая бы снимала нашу сцену сверху, с полностью чёрным фоном и лишь одним активным слоем. На самой сцене активные объекты, вроде главного героя и его машины отрисовывают за собой объекты Trail Render, которые подобно шлейфу тянутся за родительским объектом. Время жизни у них не бесконечно, поэтому через некоторое время след постепенно начинает исчезать. Сами трейлы видны только нашей специальной камере, которая сверху всё это снимает примерно 10–15 раз за секунду.
Далее полученная текстура передаётся в шейдер террейна и используется как карта высот для смещения вершин. Я немного поэкспериментировал и добавил также влияние этой маски на другие каналы шейдера, альбедо, окклюжн и тд. В месте следа поверхность немного затенялась и проявлялся более выраженный рельеф.
Схожий метод отрисовки в дальнейшем был использован и для шейдера воды, следа от лодки и разводов от персонажа.
Еще одним интересным методом построения окружения стал блендинг некоторых мешей с террейном. Это особенно полезно для создания сугробов, камней и разной дополнительной геометрии ландшафта, которая намного лучше смотрится с плавными переходами в сам террейн. Здесь мне пришлось прибегнуть к помощи ассета Terrain Blending, но с некоторыми изменениями. Плагин генерирует карту высот нашего ландшафта и в шейдере создает плавный переход. Используется одна и та же текстура в мировых координатах, в результате чего переход между геометрией становится слабо различим. Я также добавил использование такими объектами той же лайтмапы, что и у самого террейна (лайтмапа проецируется сверху). Это позволило избежать постоянного перезапекания света в случае изменений.
Декали, кромки, фаски
Интересное наблюдение - за годы работы начинаешь полноценно понимать некоторые визуальные приемы, применяемые в графике. Да, много полезной информации можно извлечь и из уроков в короткие сроки, но именно глубинно какие-то фишки понимаешь только со временем и опытом.
Для примера можно взять чудотворную силу декалей, кромок, углов. Наблюдая за реальными референсами, понимаешь, что вокруг нас почти нет идеально ровных прямых линий (если только в свеже отстроенных зданиях). Любой угол стены и конструкции имеет хоть и незначительные, но все же искривления, повреждения, сколы. Стена здания никогда идеально ровно не стыкуется с асфальтом, всегда есть трещины, бугры, какой-то мусор, забившийся в угол.
И с опытом, работая над локацией, такие вещи очень бросаются в глаза. Добавление хоть небольших, еле заметных погрешностей очень преображают картинку. Для части геометрии на ровных углах я создавал специальные накладки с альфа шейдером. Это были либо просто закругления и сколы, либо имитация заштукатуренного уголка.
Аналогичным образом работают и простые декали. Всяческие надписи, граффити, мусор на асфальте и трещины ощутимо дополняют картину, делают ее более живой и детализированной. Также, декалями иногда удобно маскировать швы и переходы между разными материалами и геометрией.
Пожалуй, на этом все. На самом деле, нюансов и технических интересностей намного больше, но все это сложно уместить даже в рамках нескольких частей, поэтому я стараюсь сосредоточиться на основных приемах. Следующая часть будет посвящена освещению и эффектам, тема достаточно объемная и интересная, поскольку в каждом проекте имеются свои индивидуальные особенности и методы.
Всем спасибо за внимание, с наступающим Новым Годом!
oreordaz
Во, все хотел тебя расспросить о подобных деталях, а ты в итоге взял и расписал) Спасибо)
NoskovSS Автор
:)