Эта статья про работу в программе Blender и является продолжением статьи, в которой я рассказал про её интерфейс и управление. Там же на примере рассматривал как добавить базовые фигуры в рабочую область в объектном режиме (и трансформировать их там), а затем изменить в режиме редактирования (добавить, объединить или отрезать их части).
Сам программный пакет Blender весьма обширен и включает в себя множество функций для разных задач: моделирование от скульптур для 3D печати до физических симуляций, красивые рендеры, анимация, спецэффекты, причём всё это для 2D и 3D в совершенно разных стилях от угольных штрихов до фотореализма. Большинство задач можно достигнуть несколькими способами. В своих статьях я буду затрагивать максимально тот функционал, который использую для решения различных задач, применимых к созданию игр: создание и манипуляции с 3D моделями, создание материалов и скелетная анимация, а также различные аспекты связанные с экспортом.
В этой части цикла статей особое внимание уделим материалам и всему, что с этим связанно.
Когда мы добавляем Мэш (любой объект имеющий грани), то он сделан из материала по-умолчанию (свето-серый матовый пластик). Есть несколько вариантов как можно сделать желаемый нами материал (или текстуру):
- Просто изменить материал по-умолчанию (например сделать его более гладким и поменять цвет на серый - вот полированный металл).
- Наложить картинку в качестве текстуры или использовать PBR-текстуру, имитирующую все параметры материала (кстати, я как-то рассказывал как можно самому такую нарисовать - поглядите, там немного, но интересно).
- Использовать программную генерацию текстуры с помощью шейдеров. В сети есть потрясающие примеры как люди рисовали в блендере целые солнечные системы с бесконечной детализацией атмосферы и поверхности планет, используя только программную генерацию текстур и просто несколько сфер, висящих в пустоте.
В блендере любой материал - это шейдер с установленным набором параметров, поэтому эти подходы по-сути последовательное усложнение одного и того же, в чём сейчас мы и убедимся после детального рассмотрения.
Параметры шейдера
Выберем любой объект или грань(и), а затем создадим ему новый материал во вкладке Material (на скриншоте видно где найти это вкладку). После добавления материала под списком материалов будут параметры шейдера для его настройки (на втором скриншоте и далее в статье будет в статье также будет показано как редактировать их используя ноды).
Новый материал заменит тот что был по-умолчанию (будет таким же, но позволит себя настроить). По-умолчанию используется шейдер Principled BSDF и его можно очень гибко настроить под свои нужды и при желании получить эффект любого материала: светящийся газ, свечной воск (с эффектом подповерхностного рассеивания света), вода итд. Далее приведу основные параметры шейдера. По ссылке на документацию есть примеры как что влияет для наглядности и полностью дублировать тут не буду - аналогично будут называться параметры в большинстве других шейдеров (в большинстве графических программ):
Base Color - Основной цвет поверхности. Определяет цвет, который будет восприниматься как диффузный.
Subsurface - Контролирует интенсивность подповерхностного рассеивания света (SSS), создавая эффект, при котором свет проникает внутрь объекта и рассеивается.
Subsurface Radius - Определяет глубину и цвет рассеивания света для подповерхностного эффекта. Измеряется в виде коэффициентов RGB.
Subsurface Color - Цвет подповерхностного слоя материала.
Metallic - Указывает, насколько материал похож на металл (0 — диэлектрик, 1 — металл).
Specular - Определяет уровень зеркального отражения.
Specular Tint - Изменяет цвет бликов, добавляя оттенок базового цвета материала.
Roughness - Указывает, насколько поверхность гладкая или шероховатая (0 — идеально гладкая, 1 — очень шероховатая).
Anisotropic - Контролирует степень анизотропии, создавая вытянутые блики, как на полированных поверхностях.
Anisotropic Rotation - Определяет угол вращения анизотропного блика.
Tangent - Управляет направлением тангенциального вектора для анизотропии.
Sheen - Добавляет мягкий эффект рассеянного блеска для ткани или подобных материалов.
Coat - Добавляет дополнительный слой глянца, имитируя лакокрасочное покрытие.
IOR (Index of Refraction) - Определяет показатель преломления материала (применяется при использовании Transmission).
Transmission - Контролирует прозрачность материала.
Emission - Цвет и интенсивность свечения материала.
Alpha - Определяет прозрачность материала (простая прозрачность без учёта преломлений, рассеиваний итд).
Normal - Подключение нормалей для управления направлением поверхности (обычно через Normal Map).
Displacement - Смещения вершин поверхности относительно меша.
Цвет, шероховатость и другие параметры могут быть как у самого материала так и отдельных параметров, например лака, но по контексту понятно как повлияют на конечный вид.
Давайте попробуем сделать металлическую тару на которой будет лежать кубик льда. Добавим два объекта (в первой части статьи рассказывалось как в три шага сделать подобную форму меша как тарелка у меня в примере) и по-отдельности добавим на них новые материалы и настроим их.
Настройка тарелки: Base Color: серо-синий, Metallic: 1.0, Roughness: 0.1–0.3.
Настройка куба: Base Color: белый, Transmission: 1.0, Roughness: 0.1-0.3, IOR: 1.31 (значения преломления света можно подбирать, а можно просто найти в интернете, вот самые популярные: IOR воды - 1.33, IOR льда – 1.31, IOR стекла – 1.52, IOR алмаза – 2.42), Transmission Roughness: 0.1–0.2, Specular: 0.6-0.8, Specular Tint: очень светло-голубой, Subsurface 0.1–0.3.
Освещение
Я не планировал подробно рассказывать про настройку освещения в этой статье, но понять правильно ли мы сделали материал и посмотреть как оно будет друг с другом выглядеть не затрагивая эту тему никак нельзя. Обратите внимание на раздел Viewport Shading в правом верхнем углу. До этого мы работали только с формой объектов и переключались между Wireframe и Solid. Режим Material Preview (использует быстрый движок рендеринга Eevee) показывает приблизительно как будет выглядеть материал, что понятно из его названия. Режим Rendered (может использовать движок рендеринга на Cycles с "облегчёнными" настройками, если переключить в соответствующей вкладке) показывает конечный вид сцены с учётом всех настроек материалов и освещения (тени, отражения, шероховатости итд). Всё время работать в режиме Rendered мне начинает быть проблематично с ростом сложности моделей даже с относительно мощной видеокартой.
Выглядит не очень-то похоже, не так ли? Зададимся вопросом: а можем ли мы быть уверены, что с точечным источником света в бесконечной серой пустоте оно будет выглядеть не так? Для имитации естественного окружающего освещения применяют HDRI-текстуры. Это лучше чем просто сделать равномерную амбиентную (заполняющую, не отбрасывающую тени) подсветку или несколько огромных невидимых светящихся плоскостей.
Сначала выберем и скачаем подходящую нам текстуру на любом сайте с бесплатными hdri-текстурами, например, зимний день на улице, небо чистое, но с небольшими облачками, местность открытая.
Перейдём в Shader Editor или переключимся сразу в рабочую область Shading (наверху интерфейса программы), там он открыт одновременно с превью результата.
Переключим Shader Type с Object (если в текущий момент выделен какой-то объект, то его настройки материала будут представлены в виде нод) на World. На экране будут видны две ноды с настройками мира. По контексту понятно что они делают: левая передаёт серый цвет на пространство мира (справа). Этот пример хорошо иллюстрируют принцип работы нод: входы слева, выходы - справа, соединяем нужные входы и выходы - работает.
Теперь передадим скачанную нами HDRI-текстуру вместо сплошного цвета. Для этого кликнем правой кнопкой мыши (или через меню) и выберем Add (можно как и в других местах при добавлении использовать Shift+A) ->Texture->Environment Texture, там Open. И соединим выход Color с соответствующим входом ноды Background.
Дальше возникает вопрос расположения горизонта и смещения центра. Для правильной ориентации надо связать координаты плоских точек картинки с координатами 3D окружения. Для решения этой задачи добавим две ноды:
Во-первых соединим выход Vector->Mapping со входом (Vector) ноды Environment Texture.
Во вторых добавим в самое начало цепочки Input->Texture Coordinate и соединим его выход Generated (автоматически генерировать наложение текстуры на сферу, окружающую мир) со входом Vector ноды Mapping.
Для нашей задачи этого уже достаточно. Если вы захотите поменять угол теней - поменяйте параметры в ноде Mapping. При желании добавьте ноды с цветовыми эффектами между выходом ноды с текстурой и входом Background. Как и любому другому источнику света при необходимости можно добавить силы света с помощью параметра Strength. Чтобы потом не переходить в редактор нод когда будете настраивать освещение сцены можно пользоваться вкладкой World -> Surface -> Shader.
В описанном выше примере мы вручную добавили ноды для настройки маппинга текстуры, но большинство пользователей Blender'a так не делает, а пользуется официальным аддоном Node Wrangler. Чтобы его установить надо просто поставить соответствующую галочку в меню Edit -> Preferences -> Add-ons. После этого появится соответствующая вкладка в Shader Editor и станут доступны его функции, в том числе добавить маппинг для текстуры (Ctrl+T). В старых версиях этот аддон добавлял ноду для просмотра промежуточного результата, но сейчас предлагается по Ctrl+Shift+LBM смотреть вывод (того на чём кликнули) на Material Output, поэтому при использовании этого инструмента надо держать открытым Viewport.
Запекание текстуры из готовых материалов
Можно сделать несколько материалов для одной модели и применить их к соответствующим граням. Для этого надо выделить необходимые грани, выбрать применяемый материал и нажать кнопку Assign.
Такой подход оказывает дополнительное преимущество, например, если вы потом импортируете домик из примера в Unity, а там программно создадите 100 его экземпляров меняя например размеры и цвет стен (в нужном диапазоне) при этом сохраняя остальные цвета неизменными.
Я периодически пользуюсь вот этим лайфхаком когда надо запечь текстуру из раскрашенного описанным выше способом объекта, или из объекта, на который уже наложена текстура. Мне оно пригождается чаще всего когда надо сделать одну и ту же модель с уменьшающейся детализацией. Повторять описанное в приведённой заметке не буду - посмотрите, чтобы знать что так можно. Учтите что если форма не идеально совпадает, то и результат тоже не идеален (посмотрите в галерее как криво перенеслись материалы в текстуру).
При работе с текстурами мне удобно использовать рабочую область UV Editing, но это не обязательно - многие делают всё это в основной рабочей области или в Shading. Так как домик у нас очень просто раскрашен, то мы можем сделать как нам надо вручную в режиме Texture Paint.
Если вы не будете выбирать цвета вручную, а будете использовать инструмент Eyedropper (как у меня на скриншоте), то вы можете выбрать цвет как с модели, так и с текстуры. Выбранный с модели цвет будет таким же, как он виден в текущий момент на экране (то есть зависеть от освещения), поэтому лучше брать с текстуры (если конечно вы сами не поставите галочку в скрытой области Image -> View as Render). Так как чаще всего для такой задачи вы даже не будете пытаться запечь текстуру, а сразу начнёте раскрашивать, то можете предварительно открыть картинку с текстурой другой модели, референсом или заранее заготовленной палитрой. Для этого надо будет отделить ещё одну область и там открыть файл с образцами цветов в режиме Image Editor.
Текстура из фото
Для описанной выше задачи UV-развёртка была не важна, мы создали её автоматически (подписал на скриншоте как это сделать в рабочей области UV Editing), а со сплошными цветами масштаб и взаимное расположение граней не играет особой роли. Совсем другое дело, если у нас есть только текстура или даже просто картинка, с которой мы хотим взять текстуру. Для примера я нашёл картинку в интернете и хочу "натянуть" её на куб, чтобы сделать модель такого же. Этот пример для демонстрации инструментов - в сети полно качественных развёрток ящиков с оружием и я бы рекомендовал воспользоваться одной из них для решения конкретно этой задачи.
Создадим куб и растянем его на свой вкус. Создадим ему материал и укажем ему вместо цвета Image Texture (в соответствующей ноде выберем нашу картинку). Эту же картинку выберем в качестве развёртки в UV Editor'e.
Затем сместим вершины на развёртке так, чтобы убрать искажения и правильно выбрать фрагменты картинки в качестве текстуры. У меня на рисунке видны только три стороны ящика, поэтому для противоположных сторон я выбрал те же самые фрагменты и развёртка "сложилась" пополам.
Фотореалистичные модели
Для маленьких простых моделей этого достаточно, но для объектов ближнего плана лучше использовать качественную PBR-текстуру. Скачаем такую на любом сайте с бесплатными PBR-текстурами. Я в заметке о самостоятельном создании PBR-текстур приводил пример с корой дерева, поэтому сейчас для примера как её применить в Blender - используем такую же.
В пакете PBR-текстур несколько карт, которые вместе дадут интересующий нас эффект. Для возможности настройки влияния той или иной карты, я вставлю между выходом текстуры и соответствующим входом шейдера дополнительные ноды. Это не обязательно, но просто соединять вход с выходом мы уже научились раньше.
На скриншоте видно как я подключил карты. Обратите внимание, что для текстур не связанных с цветом выбран Color Space -> Non-Color. Карту Ambient Occlusion объединил через Mix Color (в режиме Multiply) с текстурой цветов.
Всех карт может не быть, но даже имея одну только текстуру с цветами (albedo) с помощью преобразований можно получить желаемый эффект для другой карты. Например можно для исходной текстуры взять выход Fac (или Saturation уменьшить до нуля 0), а затем используя разные настройки Brightness/Contrast подобрать приемлемые значения высоты и шероховатости, предполагая что в большинстве случаев у коры дерева более тёмное в глубине, а то что совсем на поверхности - более гладкое.
Если присмотреться к результату, то можно увидеть что автоматическая развёртка портит эффект. Если ствол дерева или ветка будет иметь более сложную форму, то это начнёт бросаться в глаза. Для того чтобы минимизировать этот эффект надо выставить швы текстуры вручную. Так как со сложной формой со всех сторон вряд ли получится идеально совместить края текстуры, то делать это лучше с наименее заметной стороны. Я отмечаю швы, представляя в голове как модель развернётся (подобно картонной коробке) по ним.
Для того, чтобы отметить шов последовательно выделите рёбра (удерживая Shift) в Edit Mode и затем выберите в меню Edge -> Mark Seam. После этого надо повторить генерацию автоматической развертки используя в UV Editor меню UV -> Unwarp -> Smart UV Project. В большинстве случаев он делает хорошо, если нет - поэкспериментируйте с его параметрами или другими видами автоматических развёрток. Предусмотреть всё вряд ли получится, но всегда можно добавить ещё шов и снова повторить генерацию развёртки. Зачастую (например после объединения вершин или применения модификаторов) также потребуется её пересоздать. Для результата как на скриншоте развёртку увеличил, чтобы выглядело естественно. То что развёртка выходит за края рамки под текстуру не страшно, так как сама текстура подключена в настройках шейдера, а там во всех нодах (Image Texture) Extention по-умолчанию установлен на Repeat (в этом и заключается прелесть бесшовных текстур).
Для модели, которую планируется использовать в игре, это хороший результат, как по качеству передачи материала, так и по оптимизации модели: поверхность ветки состоит всего из 148 треугольников. Статистика написана в правом нижнем углу программы, если её нет - надо поставить соответствующую галочку в меню по правой кнопке мыши на status-bar. Но если присмотреться к краям объекта, то заметно, что смещение не настоящее. Поэтому для модели используемой для красивых рендеров можно воспользоваться парой модификаторов. Добавлять их надо во вкладке Modifiers (на скриншоте выделил где её найти).
Во-первых используем модификатор Generate -> Subdivision Surface (в моём примере уровень 4). Ветка из примера при этом стала плавно изгибаться. И применяем его кнопкой Apply (галочка в верхней строке модификатора). Число треугольников при этом выросло до 37888, что потребует более значительных вычислительных ресурсов.
Во-вторых отключим канал Displacement от Material Output в Shader Editor'e (мы его подключали в обход шейдера, когда настраивали материал). И добавим модификатор Deform -> Displace. После его добавления появится вкладка Texture (на скриншоте указал где), в ней следует выбрать нашу карту высот. Модель тут же поменяется. Возвращаемся во вкладку с настройкой модификатора, там указываем Coordinates -> UV и выбираем текущую развёртку. Останется только подобрать на свой вкус параметры Strength и Medival (подвигайте их и сразу станет понятно за что они отвечают), после чего применить модификатор (Apply).
Система частиц
Получился неплохой результат, но можно добавить ещё немного реализма добавив немного замшелости. Есть несколько способов это сделать, но сейчас мы учимся работать с материалами и текстурами, поэтому используем следующий подход: создадим текстуру, которая будет такой, что чем светлее - тем гуще мох, по которой уже добавим его с помощью системы частиц.
Для начала создадим новый материал и поменяем его цвет на оттенок зелёного.
Затем добавим модификатор Physics -> Particle System. После его добавления появится вкладка Particle System. В ней в разделе Emission переключим режим на Hair, увеличим число источников, уменьшим длину и число сегментов. В разделе Render выберем материал с цветом мха. В разделе Children переключим режим в Interpolated и увеличим густоту соответствующими значениями Amount. Для мха можно ещё подобрать на свой вкус параметры Clumping (собирает в пучки).
На этом моменте мох покрывает всю ветку. Сейчас проще всего создать новую текстуру с картой распределения мха. Можно использовать пустую картинку .png с прозрачностью или залитую чёрным цветом, но мне удобнее создать новую в рабочем пространстве UV Editing (размером как и другие текстурные карты). В разделе Textures создадим (и выберем) новую текстуру, при этом появится вкладка Texture. В этой вкладке выберем Type -> Image or Movie и там выберем нашу пока пустую текстурную карту.
Если у вас UV-развёртка накрывает полностью текстуру, то вам повезло и можно раскрашивать (в Viewport Shading), но если (как у меня) развёртка больше текстуры, то нужно создать ещё одну UV-развёртку и в ней уменьшить её размер (A -> S). Раскрашивать надо с выделенной этой развёрткой (переключать на, как используемую для рендеринга, не надо). После раскраски не лишним будет сохранить картинку с текстурой. И не забыть выделить правильную развёртку, чтобы не только при рендеринге всё выглядело как задумано. Может так случиться, что при изменении параметров системы частиц ничего не происходит или как-то всё не так после переключения карты - тогда удаляйте систему частиц или закрывайте проект не сохраняя и повторяйте последние действия - баг уже не один год, ловил ещё на 2ой версии Blender'a и при написании этой статьи опять случился. Поэтому в этом месте совет: время от времени сохраняйте проект. Затем во вкладке Texture настроим текстуру, привязанную к системе частиц: выберем в Image карту с распределением мха, которую только что сделали, включим параметр Density (привязка густоты мха) и выберем UV-развёртку использованную во время раскраски карты мха.
Повторюсь, что вопросы настроек камеры и рендеринга я оставлю за пределами этого цикла статей, а все скриншоты к статье сделаны с использование движка EEVEE.
Процедурно-генерируемые текстуры
Когда вы выбирали текстуры или добавляли ноды с текстурами, то наверняка заметили там стандартные процедурно-генерируемые текстуры: Шум Перлина, Диаграмма Вороного, волны итд. И глядя на то, как формируется шейдер для материала сама собой приходит мысль о процедурной генерации текстур: например, а зачем мне текстура дерева, если её можно получить смешав текстуры Noise и Wave?
На первом скриншоте (галереи выше) видно как с помощью Mix Shader получить текстуру мха на камне.
Прелесть такого подхода заключается в том, что можно сделать бесконечное число объектов (например камней) и назначить им один и тот же материал и нигде ничего не будет повторяться. А когда захочется что-то изменить, то достаточно будет подкрутить те или иные параметры глядя на всю сцену целиком.
На следующих четырёх скриншотах видно как получить растрескавшийся пенобетон используя Voronoi Texture (Диаграмма Вороного) в различных вариантах: акцентируя середины (для пузырей) либо границы ячеек (для трещин).
Так как цвета Noise Texture можно интерпретировать как смещение по соответствующим осям (посмотрите как раскрашено гизмо с осями координат и сразу станет понятно), то его можно использовать для создания реалистичных трещин и пузырей, проходящих сквозь объект.
Я выбрал для примера такой материал потому что в природе пузыри не могут накладываться, а решение этой трудности (как и совмещение пузырей с трещинами) подходит для того чтобы наглядно показать различные варианты смешивания текстур.
На последнем скриншоте использована текстура Wave для имитации годовых колец на торце досок. Не смотря на то что убедительного эффекта можно достичь и просто подкрутив настройки текстуры Wave, я добавил текстуру Noise для усиления искажений. Такой приём очень полезен в случаях когда надо создать текстуру с эффектом фрактальности.
Посмотрите на текстуры красивых природных камней (как на скриншоте поиска по картинкам выше). Половину можно получить последовательно использовав две текстуры Noise и подобрав градиент с помощью Color Ramp. Для других Noise -> Voronoi (F1) или Voronoi (Distance to Edge) -> Noise. При необходимости в нужное место можно добавлять ещё искажений с помощью Noise или полосок с помощью Wave. Уверен, что после повторения примеров из этой части статьи (хотя я рассказал не так уж и много), ваших знаний вполне хватит на создание текстуры подобной любой из приведённых на картинке.
Надо помнить, что при таком подходе, чтобы при масштабировании не растягивались процедурные текстуры - надо добавить на входе ноду Texture Coordinate (выход Generated). Также она потребуется если делать например структуру древесины растягиванием текстуры Noise (тогда следует использовать выход Object).
В случае всех материалов созданных с таким подходом, реализованным не только конкретными нодами, настроенными на скриншотах, ключевым преимуществом является гибкость в изменении настроек: оттенков, размеров, искажения и другими. Стоит отметить, что никто не мешает совместить процедурно созданный материал, с настроенным с помощью PBR-текстуры или раскрашенным вручную. Помните, что в этом вопросе следует не только познакомиться с инструментами, но и научиться представлять конечный результат и мысленно раскладывать его на составляющие.
Вместо вывода
В этой части статьи я постарался последовательно рассказать как работают материалы, но многое конечно же осталось за её границами. Мы затронули также такие краеугольные камни 3D-графики как шейдеры, освещение, развёртку, текстурные координаты итд. Поэтому теперь можно добавить ещё немного про экспорт.
В первой статье цикла я говорил, что если если менялась геометрия, то перед экспортом следует вывернуть нормали наружу (так как изнанка граней прозрачная). В этой статье дополню список того что следует сделать перед экспортом триангуляцией поверхностей (выделить всё кнопкой A в объектном режиме, а затем нажать Ctrl+T), если менялась геометрия. Приведу пример зачем это нужно. Если вы добавите плоскость (плоский квадрат, размещённый горизонтально), а затем сместите одну из вершин вверх или вниз, то плоскость плавно изогнётся. Когда вы её добавите в проект на Unity, то это место будет сильно бликовать и бросаться в глаза. Ещё перед экспортом я советую применить все трансформации (выделить всё, а затем нажать Ctrl+A -> Apply All transforms или ещё раз нажать A, отпустив Ctrl), при этом все значения будут приведены (масштаб и поворот к единице, смещение к нулю). Если этого не сделать - могут возникнуть неприятные эффекты при импорте: объекты которые были растянуты по одной из осей могут сжаться, изменится скорость анимации, текстура будет масштабироваться итд.
Говоря об экспорте в Unity, отмечу, что если объёкт должен плавно изгибаться (например как посудина из примера в начале статьи), то надо включать Shade Smooth (там же на скриншоте видно где включается) иначе в Unity будут чётко видны полигоны.
_________________________________
Шпаргалка по использованным в заметке горячим клавишам (без повторов с той, что была в первой части статьи):
Ctrl+T в Shader Editor c включенным Node Wrangler - добавить маппинг текстуры
Ctrl+Shift+LBM в Shader Editor c включенным Node Wrangler - вывести на материал результат ноды на которую кликнули (предварительный просмотр)
A -> Num . (точка на цифровой панели клавиатуры) - центрирует ноды. Может пригодиться если после чего-то сложного открыли простое и ноды ушли куда-то за границы экрана. На некоторых клавиатурах нет Num-пада, поэтому там через меню нужно будет выбрать.
Ctrl+T - триангуляция
Ctrl+A -> A - применяет все трансформации
В следующей части статьи рассмотрим ещё пару модификаторов и скелетную анимацию (и тут появится ссылка).