- PVSM.RU - https://www.pvsm.ru -
Есть игры с таким запоминающимся визуалом, что страшно считать потраченное на его разработку время, взять хотя бы последний God of War или RDR2. А бывают проекты, которые подкупают своей атмосферной, даже если они далеки от ААА. Как пример — RiME не раз хвалили за стиль, звук и историю. А недавно левел-дизайнер игры перешел [1] в команду CD Projekt Red, чтобы работать над Cyberpunk 2077. Еще RiME вдохновила 3D-художника Math Roodhuizen на создание собственного арта.
И на фоне всего этого я наткнулся на ArtStation на гайд по созданию реалистичной воды. Если в прошлый раз [2] речь шла про реку, то в этот раз про стилизованный водопад. В первой части разберем, как создавать «волновой эффект», да еще и прямо в игровом движке. Для удобства все шаги сопровождаются гифками и/или картинками.
Сначала скажу спасибо Саймону Трюмплеру — художнику из Tequila Games, который работал над RiME [3]. Я был еще новичком в шейдерах и VFX, когда нашел его материал [4] и подумал: «Ого, может я смогу сделать так же?». Рекомендую ознакомиться с докладом, чтобы узнать больше о способах создания стилизованных эффектов (таких как огонь, например).
А теперь поговорим про создание водопада. Особенно это будет полезно людям, которые еще не знакомы с системой Shader Graph. Наша цель: научиться новым способам работы и лучше разобраться в шейдерах.
Я буду показывать на примере Unity, но большинство методов применимы и в UE4 — если вы привыкли там работать, то просто повторяйте следом за мной. Для удобства каждый шаг визуализирован гифкой или картинкой.
Итак, вам понадобятся:
Сначала про «волновой эффект», который возникает, когда водопад падает на поверхность. Еще его можно использовать для других целей, например, для создания пульсаций вокруг предметов в воде.
Откройте Unity и убедитесь, что у вас установлен плагин для шейдеров. На момент написания статьи Unity имеет свой собственный Shader Graph, который еще разрабатывается. И пока он не готов, всё же рекомендую использовать Amplify Shader Editor для Unity 2018 или Shaderforge в Unity 2017.
Создайте новый материал и дайте ему имя (у меня это MAT_WaterWrinkles). Затем кликните правой кнопкой мыши на материал в Project Tab и перейдите к Create > Amplify Shader > Surface Shader. При этом новый шейдер автоматически применится.
Шейдер можно выбрать в любое время во вкладке Материалы > раскрывающийся список шейдеров (для Shaderforge будет что-то вроде PBL шейдера). Помните, что шейдер должен быть назван как в списке папок, так и в самом шейдере после его открытия.
Как только вы откроете новый шейдер, то увидите нечто такое:
Не буду писать подробное руководство по использованию Shader Graph, а если вы совсем новичок, то сначала почитайте вводные гайды.
В любом случае, чтобы получить желаемый эффект, сначала нам понадобится обычный Panner. Вот он с тестовой текстурой на плоскости:
Panner перемещает UV-координаты. Убедитесь, что Wrap Mode текстуры установлен на Repeat. В Shaderforge, возможно, придется подключить временный нод к инпуту Panner, у Amplify некоторые из этих базовых значений уже включены в самом ноде.
Итак, у нас есть движущаяся текстура. Но мы хотим добиться вот такого эффекта:
А для этого нужно, чтобы она прокручивалась вот так:
Как видите, структура нода та же самая — Panner просто перемещает UV-координаты в направлениях U и V (или X и Y). Чтобы получить нужное направление панорамирования, мы должны создать пользовательскую сетку с UV. Гифка для наглядности:
Применяя один и тот же материал к другой сетке, мы можем контролировать направление текстуры в 3D-пространстве, когда она двигается в UV-пространстве.
Для усиления эффекта, добавим еще несколько полигонов и исказим UV, чтобы текстура в центре двигалась быстрее, чем по краям. И разместим UV так, чтобы не было видно шва.
Из этого следует важный вывод: хорошие эффекты редко состоят из одной системы и часто представляют собой комбинацию нескольких.
Мы получили текстуру, двигающуюся в нужном направлении с правильной скоростью. UV-развертка размещена так, что перемещение справа налево в UV-пространстве с Panner превращается в движение внутрь и наружу в 3D-пространстве. Чтобы не было швов в текстуре на 3D-модели, UV-развертку надо приснепить (хоткей X для снэпа к сетке) к вершинам текстурного пространства по вертикали. В итоге мы добились желаемого эффекта.
Теперь прозрачность. Начнем с базовых вещей. Многие простые вычисления, которые вы делаете в шейдере, будут иметь значения от 0 (черный) до 1 (белый). То есть 0,5 — это оттенок серого, а 0,2 — оттенок темно-серого. При применении этих значений (в данном случае к каналу Opacity главного выходного нода), вы будете управлять уровнем прозрачности материала. Имейте в виду, что сначала нужно включить эту функцию. В Amplify можно изменить тип рендеринга (в режиме наложения) с непрозрачного на, например, прозрачный. В таком случае мы будем использовать тип рендеринга Transparent Cutout — пиксель, отображаемый этим материалом, либо полностью прозрачен, либо полностью непрозрачен. Это видно на гифке выше — там нет «полупрозрачных» пикселей, отображаемых этим шейдером.
Берем градиентную текстуру с шагом и помещаем ее в шейдер. Здесь она подключается к выходу альбедо (цветному) основного нода.
А тут она подключается к выходу Opacity Mask (этот параметр включается при типе рендеринга Transparent Cutout).
Видно, что градиентная текстура использует черные и белые значения пикселей, чтобы определить прозрачность или непрозрачность. Всё от 1 (белый) до 0,5 (серый) становится непрозрачным, а всё от 0,5 (серый) до 1 (черный) — полностью прозрачным (или вообще не отображается). Opacity Mask создает жесткий отрезок и округляет значения до 0 или 1 в зависимости от того, какое число ближе.
Еще одна текстура в оттенках серого:
Подключена к Opacity Mask:
Идею вы поняли. И догадываетесь, как ее можно использовать:
Вы видите в основном синее изображение, прокручивающееся в Shader Graph. И то, что я использую только R (красный) выход этого нода. Ради оптимизации я упаковал две grayscale-текстуры (текстуры в оттенках серого) в один файл, но это необязательно. Подобные изображения можно упаковать с помощью Photoshop или Substance Designer.
Эффект пульсации — хорошее начало, но можно лучше. Почему бы не наложить друг на друга две grayscale-текстуры, чтобы сделать эффект ряби более рандомным?
Я использую одну и ту же текстуру, но добавляю разные каналы. Прокручиваю их с разной скоростью и немного в разных направлениях. Текстура имеет хороший градиент значений серого, что дает ощущение случайного волнового эффекта.
На следующей гифке есть еще одна вещь, которую мы пока не обсудили — поэтому ваш вариант может выглядеть несколько иначе:
Видно, как, например, пиксель со значением 0,2 (который не рендерится) проходит поверх пикселя со значением 0,4 (который тоже не рендерится) и внезапно становится пикселем со значением 0,6 — поскольку мы используем дополнительный нод (0,2 добавляется к 0,4 и получается 0,6). Добавление этих двух волновых grayscale текстур поверх друг друга с разной скоростью и дает близкий к желаемому эффект.
Вот, чтобы продемонстрировать результат, я добавил grayscale-текстуры друг на друга в Photoshop.
Тем не менее, шов в конце сетки все еще остается отчетливым. А нам нужно получить это:
Вместо этого:
На первой из двух гифок пульсации медленно стихают и становятся меньше, когда они приближаются к краю сетки. Самый простой способ это сделать — использовать vertex color (цвета вершин).
Каждая вершина модели содержит свои данные (например, координаты X, Y и Z), а также цвет, который имеет значение от 0 до 1. Цвет вершинам можно задать и в 3D-редакторе.
Большинство внешних вершин — черные (то есть имеют значение 0). Они становятся белыми (ближе к 1) при приближении к центру. Обратите внимание, вам понадобятся дополнительные Subdivisions, чтобы получить вершины, которые можно раскрасить.
Например, в Maya для раскрашивания можно перейти в меню Mesh Display > Paint Vertex Color и нажать на поле More Options.
Теперь мы можем соединить Vertex Color в нашем шейдере с помощью Multiply.
Я наложил градиент поверх используемых текстур и установил режим слоя на Multiply.
Градиент усиливает значение серого до 0 (черный), поэтому отрендерить пиксели будет сложнее (они же не отображаются ниже значения 0,5). Это приводит к тому, что линии пульсаций сжимаются ближе к краю (цвета вершин в основном выступают в качестве градиента).
Я добавил еще несколько нодов, чтобы контролировать толщину линий пульсаций. Вот полный граф:
Просто поэкспериментируйте со скоростью/направлением прокручивания, настройте текстуру и попробуйте изменить тайлинг, чтобы выжать из эффекта максимум.
Это поможет нам при создании более сложного шейдера — водопада. О нем поговорим в следующей части.
Автор: Никита Гук
Источник [7]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/3d/303646
Ссылки в тексте:
[1] перешел: https://twitter.com/statuses/1074764789509959682
[2] прошлый раз: https://habr.com/company/pixonic/blog/430144/
[3] RiME: https://store.steampowered.com/app/493200/RiME/
[4] материал: https://simonschreibt.de/gat/stylized-vfx-in-rime/
[5] Amplify Shader Editor: https://assetstore.unity.com/packages/tools/visual-scripting/amplify-shader-editor-68570
[6] Shaderforge: http://acegikmo.com/shaderforge/
[7] Источник: https://habr.com/post/434620/?utm_source=habrahabr&utm_medium=rss&utm_campaign=434620
Нажмите здесь для печати.