Текстурирование, или что нужно знать, чтобы стать Художником по поверхностям. Часть 4. Модели, нормали и развертка
По моему скромному мнению, художник по текстурам должен отвечать за развертку. Не за саму развертку (ее стоит делать 3D-художникам или вообще отдельным UV-специалистам), а ее укладку. Он должен определять, как острова должны располагаться, как должны быть повернуты и насколько сильно их можно потянуть в той или иной ситуации в зависимости от требований.
Именно художник по текстурам (а в дальнейшем, по поверхностям) должен определять скейл (масштаб) островов (об этом чуть позже).
В этой части мы рассмотрим модели, развертку и нормали. Создадим текстуры для первой полноценной модели (хоть и простой) и настроим ее в Unreal Engine 4.
Внимание. Предполагается, что к этому моменту вы разобрались с картой нормалей, и зачем она нужна. Потому что в этом туторе мы будем очень часто о ней говорить.
Часть 1. Пиксель здесь.
Часть 2. Маски и текстуры здесь.
Часть 3. PBR и Материалы здесь.
Часть 4. Модели, нормали и развертка — вы ее читаете.
Часть 5. Система материалов здесь.
Модели и PBR. Практика
Я не буду рассказывать, как создавать модели или как зачищать / выстраивать сетку. Эту информацию можно получить со множества курсов, которые есть как в свободном доступе, так и в платном. Наша задача сейчас разобрать конкретные ограничения в строениях моделей для игр и какие варианты решений существуют на данный момент.
Но для начала мы затекстурим модель, а за одно посмотрим на ней первое ограничение. Работать мы будем над этой лавкой:

Для этого нам необходимо будет скачать сам меш и заранее подготовленную карту нормалей к нему (ниже я объясню наглядно, зачем мы ее подготовили). Ссылка здесь.
Так же я бы хотел сделать ее основу деревянной, а ножки — металлическими. Ну и немого накидать грязи. Соответственно, нам понадобятся 2 материала:
- дерево
- обработанный металл.
Начнем практику и создадим стандартный проект, укажем лавочку, текстуры и запустим его:

Обратите внимание, что в этот раз нам необходимо будет указать Normal Map Format — OpenGL. Я уже писал в прошлой части, что карты нормалей считываются по разному разными программами. И данная карта была сгенерирована под программы, которые используют OpenGL.
У нас были загружены 9 текстур + основной меш.
Сейчас не будем делать никаких слоев и папок, а давайте рассмотрим максимально близко лавочку. Особенно нас интересуют грани объекта:

Я выделил для примера одну грань лавочки. Сейчас она максимально идеальная. То есть, две стороны сошлись в одном ребре и создали идеальный угол. Сколько бы мы не приближали этот стык, он всегда будет идеально ровным. В реальности же идеальных углов не существует, и даже лезвие бритвы при должном увеличении будет скруглено. Именно поэтому ребра выглядят сейчас не кинематографично. Такие модели смотрятся очень слабо, и когда мы видим их в игре, то сразу ощущаем всю слабость визуальной картинки, даже если не замечаем эти углы у моделей напрямую.
Это первое ограничение модели
Раньше, когда ресурсы видеокарт не позволяли обрабатывать миллионы вертексов в одном кадре, решение было в текстурах карт нормалей. В них указывали, как свет должен начать отражаться так, чтобы появилось ощущение, будто у этих границ есть скругление. Конкретно к этой лавочке такая карта нормалей выглядит вот так:

Даже просто глядя на набор параметров в виде этой карты можно ощутить, как карта нормалей будет сглаживать углы.
Теперь давайте укажем эту карту нормалей, как основную (то есть, она всегда будет подкладываться к результату, как самый нижний слой без маски). Для этого нам необходимо открыть настройки основных текстур объекта и указать в параметрах карт нормалей нашу текстуру:

И смотрим на результат:

Это первый самый известный и часто используемый метод борьбы с резкими гранями — запекать в карты нормалей фаски. То есть, модель все так же жесткая, но карта нормалей у ее граней начинает искажать свет, что создает иллюзию красивой мягкой фаски. В интернете можно найти кучу информации о том, как это делать. Для простых объектов, как эта скамейка, можно не делать хай-поли модели (и не запекать с нее соответственно), а сгенерировать карту нормалей с фасками в программах. Например, это умеет делать программа Modo. Наша скамейка имеет карту нормали, сгенерированную в Modo.
Но опустим тему запекания фасок и продолжим текстурирование скамейки.
Теперь создадим 2 папки для слоев, создадим и перенесем в каждую по 1-му слою и в каждый слой вставим все текстурные карты. Не забывайте о нейминге, чтобы потом не путаться:

Сейчас иерархия слоев нам не важна, так как данные материалы (металл и дерево) между собой пересекаться не будут — у нас не будет ситуации, когда сквозь дерево начнет проступать металл и наоборот. Но маски нам все еще нужны будут, так теперь нам необходимо ограничить видимость слоев на разных островах, поэтому сейчас добавьте черные маски на обе папки:

И теперь укажем, какие острова разверток у нас должны быть белыми на масках, а какие — черными. Для этого выделим маску и переключимся в режим выделения островов:

Кликнем на модели по основной скамье (если вы выделили маску дерева) и получим следующий результат:

Как видно на скриншоте — маска обновилась, и теперь на ней огромная белая полоса, которая расположена на месте острова. Покрасим таким образом всю скамью вокруг:

Сам материал дерева оказался не самым удачным, но наша цель сейчас не максимально красиво все сделать, а разобраться в принципах работы.
Сделаем то же самое с маской для металла, отметив видимой зоны с островами ножек. Выделите маску металла и укажите нужные части объекта:

Так же нужно залезть в трудно доступные места на стыках и отметить там нужные нам острова как для дерева, так и для металла:

Если вы внимательно осмотрите ножки, то заметите второе ограничение модели.
Развертка выполнена не корректно, и рисунок стали между сторонами ножек не согласуется — его фактура направлена в разные стороны, что визуально сильно бросается в глаза (направление отмечено стрелочками):

Это именно ограничение, преодолевать которое можно путем выравнивания островов и их растягивания. Сейчас остров, на котором нарисована стрелочка вниз, выглядит так (выделен оранжевым):

Для того, чтобы исправить проблему, необходимо, чтобы остров был выпрямлен в одну линию:

Тогда мы решим это ограничение, но у нас возникнет другое — потяжки:

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

Поэтому давайте создадим маску, которая позволит нам в дальнейшем под ней отображать такие же потертости, царапины и сколы.
Для этого необходимо открыть настройки основной текстуры (где мы указывали карту нормалей), там выбрать Bake Mesh Maps.
В появившемся окне убрать все лишние галочки, оставив только Curvature и запечь ее, нажав на Bake [доп.название] Mesh Maps:

Когда создание текстуры закончится — она станет доступна в shelf под тегом Project:

А так же эта текстура автоматически подключится в качестве основного параметра Curvature в настройках текстуры. Уберем ее оттуда:

Если создать новый слой вверху иерархии и установить в качестве параметра Base Color полученную текстуру, то мы увидим следующий результат:

Теперь удалим этот слой, так как он нам нужен был исключительно для понимания.
Далее создадим папку, назовем ее Folder Dirt и поместим ее в папку с деревом НАД слоем с деревом. В этой папке создадим слой под названием LowLayer_Dirt, а на самой папке создадим черную маску, чтобы слой не накладывался на результат:

Укажем, что маска для грязи должна состоять из эффектов Fill, чтобы добавить текстуру, которую мы создали (curvature), и дополнительным эффектом «Levels».
Для чего нам нужен эффект «Levels» сейчас? Вы, наверное, обратили внимание, что маска для граней слишком светлая? Сейчас нам нужно будет обрезать цвета таким образом, чтобы оставить светло-белым места на гранях, а все остальное сделать абсолютно черным.
Конечный результат у вас должен получиться таким:

Таким образом мы создали «границу дозволенного» для грязи. Теперь надо ограничить саму грязь. Для этого нужно наложить черную маску на сам слой LowLayer_Dirt. После этого добавить эффект Fill, и в нем указать маску Dirt4, которая спрятана под тегом Procedurals:

Выше на скриншоте обведены дополнительные параметры маски Dirt 4. Дело в том, что это не текстура в том формате, в котором мы привыкли представлять ее. Это генератор случайных чисел по определенным правилам. Иначе говоря, процедурная текстура, пиксели в которой имеют сгенерированную интенсивность. Вы можете поиграться параметрами, например, покрутить Balance и Contrast, чтобы добиться желаемого результата.Теперь измените параметр Height в слое LowLayer_Dirt на -0.35 и посмотрите на результат:

Повторюсь. Сейчас наша цель не в качественной идеальной покраске лавочки, а работа с основами и тренировка работы с масками.
А сейчас домашнее задание
В целом, сейчас мы рассмотрели, как накладывать быстро маски для конкретных материалов, которые между собой не пересекаются. Как можно догадаться, чтобы нанести лак на дерево — нам нужно создать слой в папке с деревом. Но сейчас мы этого делать не будем, а сама задача остается для домашней работы:
- залакируйте дерево
- создайте царапины на лаке (те царапины, которые видны только под углом, потому что они продавливают лак, но не повреждают дерево)
- создайте царапины под лаком
Мы разобрали, как текстурировать модели с помощью масок. Как наносить грязь, сколы и царапины.
Чтобы в дальнейшем у вас было простое представление, как это все работает, запомните правило — один материал — одна папка для работы с ним. Так вы сможете лучше контролировать ваши маски и слои. Например, поместив слой грязи в папку с материалом вы все еще контролируете на уровне маски папки общую зону видимости этого материала, а теперь еще и грязи на нем (или слоя под ним). Например, в реальности под фактурой (материалом) может лежать другая фактура — под металлическим напылением может прятаться пластик. В данном случае, металл — это основной слой, а пластик — дополнительный слой под металлом (хотя в туторе выше мы слой со сколами и поместили выше дерева, по факту — это более низкий слой в иерархии. Иначе говоря, это ошибка).
Слои материалов, их иерархию нужно просчитывать до того, как вы начнете создавать текстуры. Это важно, поэтому что некорректные расположения слоев в конечном итоге могут привести к тому, что вам придется все начинать сначала и потратить долгие часы на разбирательство того, почему ваша текстура отображает только металлический слой.
В целом, на этом мы закрываем большую тему того, как можно текстурировать объекты для игр в рамках PBR. Всё остальное — техники. Моя задача рассказать суть, основу всего этого, чтобы у вас не было в дальнейшем вопросов по типу «А чем отличается карта Roughness от Metallic и Normal map?» (сразу отвечу — ничем), а появились вопросы — «А как это можно усовершенствовать? Как сделать лучше и эффективнее?»
Мы разобрали несколько ограничений, у которых существуют решения.
- Ограничение с фасками.
- Ограничение с расположением островов.
Во втором случае так же нужно помнить о направлениях островов — их нужно разворачивать согласовано, как и направление узора в материалах. Иначе возникнут сложности, описанные выше.
Развертка
Отложим на время в сторону Substance Painter. Не закрывайте проект, он нам пригодится позже, когда мы будем экспортировать текстуры в Unreal Engine 4.
В этом куске туторов мы рассмотрим развертку объектов, плотность островов и наконец-то изучим такое явление, как плотность текселя.
И начнем с текселя.
Тексель — это текстурный пиксель (ба-дум-с).
Плотность текселя и островов
Чтобы не путать пиксель монитора (физический элемент реального мира, который всегда фиксированного размера) с пикселем текстуры (визуализированный квадратик, который может менять свои размеры на экране монитора и вообще искажаться в целом), текстурный пиксель стали называть текселем (Текстура и пиксель).
На эту тему есть достаточно полная статья здесь. И перевод здесь.
Однако, мы еще раз рассмотрим это явление, потому что в дальнейшем, если мы не осознаем всю идею текселей, то нам будет сложно работать дальше. И уж тем более будет сложно стать художником по поверхностям.
С этого момента, мы начинаем говорить правильно — пиксель и тексель. Пиксель — мониторный элемент. Тексель — текстурный элемент.
Так вот, повторим пройденное, тексель — это мнимая единица отображения информации. Она существует только в цифрах (массив цифр из различных каналов), но, чтобы нам было проще работать с параметрами рендера, были введены текстуры, как визуальный заменитель массивов цифр. Думаю, никому не было бы приятно разрисовывать космический корабль одними только цифрами, держа в голове представление, что тексель в 8 ряду и в 453 столбце должен быть на 1 значение меньше, чем тексель в 284 ряду и в 112 столбце. Проще тыкать кисточкой в Photoshop’е.
Рендеры (системы визуализации) считывают эти цифры и отображают их в качестве квадратиков (текселей). Отображение текселя в виде квадратика — дело условное. И зависит оно в частности от плотности и натяжения островов развертки модели.
О плотности островов развертки мы поговорим чуть позже, а сейчас разеберемся с натяжением островов.
Представим себе кусок ткани (если представить сложно — возьмите любой кусок ткани, которую можно растянуть). В спокойном состоянии рисунок (или паттерн материала) на ней остается неизменным, как и задумывал производитель. Но если мы начнем растягивать ткань, то и рисунок начнет так же растягиваться. Тот же самый эффект происходит тогда, когда мы растягиваем (или сжимаем) остров развертки модели:

Развертка левой и правой стороны расположилась вот так:

На примере видно, что сжав репрезентацию (остров) левой стороны, мы растянули тексели таким образом, что теперь они отображаются на левой стороне куба в виде прямоугольных вытянутых палочек. То есть, тексель на объекте зависит от того, как выполнена развертка этого объекта. Часто в 3D-редакторах объектов есть возможность проследить, насколько сильно сжат или растянут остров развертки. Например, в Autodesk Maya это выглядит вот так:

Где красным отображается сильное сжатие, а синим — растяжка.
Плотность островов
Остров развертки должен корректно расправляться, не создавая стяжек. Еще острова должны быть отмасштабированы между собой. То есть, площадь, которую занимает остров, должна соответствовать площади другого острова. В противном случае, получится так, что один остров реальной площадью 20 кв.см будет занимать 20% площади текстурного пространства, а остров с реальной площадью в 100 кв.см будет занимать 5% площади текстурного пространства. И отсюда получится разногласие в отображении количества текселей на острове:

Остров правой стороны куба очень маленький и способен отобразить лишь 25 текселей, на которых он и располагается. В связи с этим, рендер увеличивает тексели согласно площади острова, и мы видим большие квадраты.
Слева остров очень большой — он покрывает большой кусок текстурного пространства и способен вместить в себя больше текселей, что и получилось на экране. Верхняя сторона имеет усредненный размер.
То есть, чтобы модель правильно текстурировать — нужно выравнивать площадь всех островов, чтобы они были равны по отношению друг к другу:

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

Это говорит нам о том, что текущий размер текстуры не достаточно высокого качества, поэтому мы видим тексели. Но так ли это?
Представим, что текущая текстура (ее обычно называют «чекер» (Checker) — текстура для проверки корректной настройки островов) имеет размерность 63 на 63 текселей. И сейчас мы видим этим тексели, потому что объект расположен к нашей камере настолько близко, что размер одного текселя занимает площадь 30х30 пикселей монитора (условно).
А если мы отдалим куб от камеры подальше?

Попробуйте теперь разглядеть тексели на этом кубе?
Теперь 1 тексель равен по размерам 1 пикселю (но это не точно). И размер такой текстуры является идеальным, так как позволяет отобразить все свои тексели, а так же не отображает ничего лишнего и не прячет ничего лишнего. Это идеальный размер для такого расстояния.
То есть, размер текстур зависит очень сильно от площади, которую занимает развертка модели и от расстояния объекта до камеры. Если объект будет находиться на достаточно большом расстоянии от нас — нет смысла ему выдавать текстуры 8к на ноготок. Даже если вы делаете текстуры для фильма — никто просто не увидит белую полоску на ноготке девушки, рука которой занимает 3% от площади экрана.
Важно понимать масштабы моделей и то, где они будут располагаться относительно камеры, чтобы корректно выстраивать размеры текстур. Очень часто я видел игры от инди-разработчиков, которые пренебрегали этими простыми правилами, и в итоге их текстуры были не самого лучшего качества.
Не забывайте выравнивать острова относительно друг друга — это важно и очень сильно влияет на восприятие. Если вы откроете, например, игру Fallout 4 и начнете диалог с каким-нибудь NPS, то заметите, что качество текстур на одежде персонажа оставляет желать лучшего, а лицо имеет максимального размера текстуры:

Стоит помнить, что в играх часто специально занижают размер текстур в угоду производительности. Да и кто смотрит на одежду, когда у персонажа такое интересное лицо со шрамами?
Большие размеры текстур занимают большое пространство (в памяти, я имею в виду). Поэтому многие разработчики принимают тяжелое решение — что урезать, а что оставить, лишь бы игра не тормозила на вашем ПК / консоли / телефоне. Однако, к этому вопросу мы еще вернемся и рассмотрим новейшие методики, которые позволяют избегать таких неприятностей.
Запекание текстур
Что такое — запекание текстур?
Запекание текстур — это когда пакет для создания текстур начинает высчитывать конечный результат и сохранять его в отдельные файлы, с помощью которых потом окрашивается модель в игровом движке.
Грубо говоря, в Substance Painter мы накладываем слои за слоями через маски и прочие хитрости, чтобы добиться конечного результата. Мы работаем над тем, как должна выглядеть конечная модель, смешивая различные варианты материалов. Но, если вы заметите — чем сложнее будет ваша комбинация слоев, масок и материалов, тем сложнее будет обрабатывать ваши изменения программе. Дело в том, что Substance Painter (Любая другая программа для текстурирования) сверяет каждое ваше изменение и просчитывает в реальном времени ВСЕ созданные вами слои и каналы (а я напоминаю, что вы можете еще и свои каналы добавлять в слои для всего-чего-угодно), которые приходятся на тексель.
И когда мы довольны результатом и готовы выгрузить его в игровой движок, то мы просим Substance Painter сделать последние расчеты и создать нам текстуру с параметрами для цвета каждого пикселя, и 3 дополнительные текстуры с параметрами Metallic, Roughness и Normal Map. Это позволит нам не выгружать в игру тонны масок и дополнительных материалов, не заставлять движок рассчитывать все заново, а просто предоставить ему готовый результат, который он преобразует в текстуры для модели.
В целом, с запеканием текстур мы разобрались. Однако нам нужно посмотреть, как происходит выгрузка параметров в текстуры, чтобы мы узнали, как мы можем контролировать то, в какие каналы текстур какие данные пойдут. Это важно, потому что в стандартах изображения все еще всего 4 канала. И нам нужно уметь выбирать, в какой канал какие параметры пойдут, чтобы мы могли потом быстро их подключать.
Теперь возвращаемся в Substance Painter, в наш проект, и начнем выгружать текстуры. Для этого откроем окно выгрузки текстур (File — Export textures):

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

Как видим, здесь 4 текстурных файла, которые должны экспортироваться, против 9 файлов, которые мы загрузили.
Но нас они не интересуют, так как стандартные настройки, а нам нужны свои личные (или по стандарту студии, в которой вы работаете). Поэтому перейдем в окно Configuration:

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

Теперь обратим внимание на панели справа:

Input Maps — это список каналов, которые мы использовали. Большая часть из них имеют названия, так как используются для PBR для конкретных целей. Есть 8 каналов (от 0 до 7), которые доступны для редактирования, но Substance Painter не знает, зачем вам они могут пригодиться, поэтому у каналов стандартные названия User0 — User7.
Converted Maps — это список текстур, которые зависят от типа рендера. Например, Normal Map зависит от движка. И нам нужно знать, какой API использует движок — DirectX или OpenGL, чтобы выбрать корректную карту нормалей для него. Поэтому Substance Painter выделяет эти карты в отдельную категорию, так как конечный результат их будет зависеть от того, что вы выберете.
Mesh Maps — те текстуры, которые вы загрузили вместе с объектом или сгенерировали во время работы над ним. Мы загружали 9 текстур. 8 из них относились к слоям (материалам), а 9-ая карта нормалей для фасок уже относилась напрямую к объекту. Кроме карты нормалей мы создали еще карту Curvature для наложение по ней сколов. Эти карты относятся именно к объекту и не могут использоваться в качестве основы для материалов, поэтому они вынесены в отдельный список.
Теперь рассмотрим панель создания текстур:

Это кнопки, нажав на которые вы создаете 1 файл текстур (точнее, подготавливаете все для его создания).
Gray — создает текстуру с одним каналом. В этот канал мы можем расположить любые наши настройки — Roughness, metallic, specular, emissive. Все те настройки, которые работают в одном канале.
RGB — создает текстуру с 3 связанными каналами. То есть, это предназначается для таких параметров, как цвет (BaseColor), карта нормалей. То есть, для всех параметров, которые используют 3 канала для полноценной реализации себя.
R+G+B — создает текстуру с 3 не связанными каналами. То есть, у нас текстура с тремя Gray — каналами. Можем указать параметр с 1 каналом в каждый канал текстуры отдельно. Часто это используетс для ORM — (Occlusion-Roughness-Metallic). То есть, в первом канале хранится Ambient Occlusion, во втором хранится Roughness, в третьем — Metallic.
RGB+A — как вы уже догадались — 3 связанных канала и 1 не связанный.
R+G+B+A — четыре не связанных канала.
Теперь, зная это, подумайте, сколько файлов нам необходимо, чтобы выгрузить всю информацию о том, как должна выглядеть конечная текстура для объекта.
Правильно, минимум 3 текстуры:
- RGB — BaseColor
- R+G+B — ORM
- RGB — Normal Map

Не забываем правильно именовать текстуры, иначе потом не разберемся, что где и как.
Сейчас нам необходимо указать, какие параметры в каких каналах будут храниться. Для этого просто перенесите из Input Maps параметры в нужные каналы. Карту нормалей нужно перенести DirectX, так как в UE4 используется такой формат чтения нормалей.
В итоге, у нас получится следующий набор:

Теперь переключаемся обратно в Export. Там мы:
- Указываем путь, куда сохраняться.
- Выбираем созданные нами преднастройки в параметрах Config.
- Выбираем тип текстур — Targa.
- Нажимаем Export.
И вуаля — экспорт текстур прошел успешно. Откроем текстуру BC (BaseColor) в Photoshop и посмотрим на нее:

Вы помните, как мы создавали 2 разных материала в разных слоях? Substance Painter сложил все слои, высчитал результат конечного варианта текстуры, которая будет покрывать объект, и «запек» все тексели ровно так, как вы замаскировали их. Все то же самое он сделал с Normal Map, Roughness и Metallic.
Если мы откроем карту ORM в Photoshop, перейдем режим отображения каналов и выберем последний (синий), то мы увидим запеченную карту Metallic:

По этой карте можно представлять, где острова должны быть металлическими, а где — не металлическими.
Мы научились создавать готовые текстуры для игрового движка.
Важно. Сейчас мы научились запекать текстуры, делая весь расчет создания этих текстур в Substance Painter. То есть, мы сделали все для того, чтобы получились готовые текстуры, которые теперь мы можем использовать в разных движках (с оговоркой на обработку некоторых параметров PBR). Минус такого подхода — если нам нужно что-то кардинально изменить — нам приходится возвращаться в программу и переделывать текстуры.
Чтобы рассчитать, как правильно отображать цвет и свет от текселя — видеокарте нужно произвести расчеты на каждый тексель. И это не будет никак зависеть от того, сколько пикселей у вас на мониторе. Это будет зависеть от того, сколько текселей используется при формировании текстуры (в паинтере мы используем стандартные настройки, значит, используем 1024*1024 текселей). То есть, чтобы отобразить корректно текстуру, паинтеру нужно посчитать каждый пиксель, и учесть в нем все слои, которые вы создали. Это трудоемкая задача, поэтому раньше (да и сейчас) PBR-текстуры создавали в основном в программах для текстурирования.
Unreal Engine 4
И на последок выгрузим наш объект в UE4 и посмотрим наш результат. Я не буду расписывать, как открыть UE4, как создать проект, как вообще его устанавливать и какие там кнопки жать. Для этого есть очень хорошие курсы от Flakky. Курсы все располагаются на его сайте uengine.ru.
Сейчас мы рассмотрим только импорт нашей лавки и получившихся текстур, создание примитивного шейдера и подведем итоги.
Для начала откроем проект и создадим в нем папку «Bench», в которую мы скинем все наши текстуры и объект. Чтобы импортировать все текстуры — достаточно просто перенести их из браузера в проект. Они без проблем импортируются и никаких настроек дополнительно не попросят. Что касается объекта, то при его импорте Unreal Engine попросит вас указать некоторые настройки. В целом, ничего менять не нужно, кроме 2 параметров. Их надо отключить:

Эти параметры отвечают за импорт текстур, а они у нас отдельно хранятся.
В итоге, в нашей папке 3 текстуры и 1 объект:

Теперь в любом свободном пространстве в браузере проекта нажмем ПКМ и выберем Material:

Назовите его M_Bench.
Откройте его и перетащите в него все наши текстуры. Получим такую картину:

Это ноды (Node) контейнеры, которые позволяют визуализировать настройки так, чтобы с ними было удобно работать даже новичку (огромное спасибо за успешную реализацию нод Epic Games. Без систем Blueprints и нод в частности у многих горели бы головы от цифр и кода). Белые пины (выходы и входы) на текстурах (нодах слева) обозначают, что подаются сразу три канала. А вот красные, зеленые и синие — каждый канал отдельно. Последний сероватый — это альфа-канал, но в наших текстурах его нет, поэтому использовать этот пин мы не будем. Справа большая нода, которая принимает в себя параметры, суммирует их и создает полноценный материал.
Весь принцип работы текстур в Substance Painter используется и здесь (и в любом другом игровом движке) — вы указываете, какие параметры для чего нужны, и программа выдает результат. В данном случае, большую часть расчетов взял на себя Substance Painter, Unreal Engine же просто складывает готовые результаты Painter’а и создает готовый шейдер (материал), который можно наложить на лавочку.
Нам осталось только правильно подключить пины и попросить движок рассчитать нам результат:

А почему я не воткнул из текстуры ORM красный канал в Ambient Occlusion? Я уже как-то упоминал, что AO считается устаревшей, так как АО часто рассчитывается в реальном времени. И в ноде материала есть пин Ambient Occlusion, но он не работает. Он даже не принимается в расчеты. Оставлен здесь по какой-то причине. Предполагаю, что достаточно большой объем работ требуется для его удаления.
Итак. У нас готов самый простой шейдер (материал), и мы можем наконец-то покрасить нашу лавку. Для этого откройте лавку в UE4, кликнув по ней 2 раза ЛКМ. И перетащите материал из браузера проекта в слот для материала:

Ну вот. Теперь вы получили свой первый готовый объект.
Результат вы можете увидеть сами, а я лишь подведу итоги.
В очень простой форме мы научились создавать первые шейдеры в движке UE4. Вы спросите — а почему это называется Material, а не шейдер в самом движке? Так проще объяснять, что это за формат построения текстур такой — это материал, который накладывается на объект, и объект становится красивым. Но возможности шейдеров куда больше (намного, в сотни раз больше), чем просто показать текстуры.
Оффтоп. Решение проблем с фасками
Выше я обозначил проблему с фасками и как ее решить. Но есть второй способ, который мы в рамках этой части рассматривать не будем полноценно — это создание фасок на модели и выравнивание нормалей таким образом, чтобы поверхность меша создавала иллюзию красивой фаски. Такая фаска создается за счет выравнивания нормалей вертексов (тангенсов). И этот метод даже в чем-то более экономичный для производительности, чем метод с картами нормалей, а уровень красоты его запредельно высок по отношению к обычному текстурированию фасок. Вот пример двери, которая стоит в одном из наших игровых проектов (пока что не анонсированных):


Я натыкался на информацию об этой теме только на англоязычных ресурсах. Здесь.
Плюс этого метода в том, что мы создаете красивую фаску, при этом, кол-во вертексов увеличивается не на много, так как жесткие грани — это всегда 2 вертекса в одной точке, а мягкие грани — это 1 вертекс, и увеличивается кол-во треугольников для отрисовки:

Стоит помнить, что нам карта нормалей для объекта нужна в 99% случаев для создания фасок. А карты нормалей для материалов и каких-то отдельных элементов — это уже немного другая тема.
Оооооох. Ну и большой же получилась эта часть. Но она была необходима, чтобы полностью покрыть тему стандартного текстурирования. И на этом мы можем остановиться.
Ну правда, мы прошли путь от еле заметного элемента пикселя на вашем мониторе до сложных схем из масок, которые определяют видимость не менее сложно устроенных слоев материалов. Наконец-то разбили слово пиксель на два — тексель и пиксель. И научились все это запекать и подключать в игровом движке. На этом шаге можно подвести длинную жирную черту и сказать, что мы стали самыми настоящими художниками по текстурам. Все остальное — красота сколов на объектах, кинематографичность визуального представления — это все наработка временем и постоянным стремлением познать новые техники и способы.
Можно смотреть больше уроков и совершенствовать свой навык. Например, в Substance Designer есть огромная наковальня генераторов, создав которые, вы можете использовать в качестве их генераторов слоев. И все те маски, которые были для грязей, уже не создавать вручную, а реализовывать на уровне функций, которые все сделают красиво за вас.
Нужно всегда помнить, что мы рассматриваем диапазон значений от 0 до 1. Это важно, потому что стандартные текстуры имеют 8 бит на канал, а HDR-текстуры имеют более широкие каналы (от 16 бит и более), а значит, диапазон чисел там намного больше, чем 0 до 255. Но это все еще диапазон от 0 до 1.
И казалось бы все, предел. Мы достигли высокой планки понимания того, как создаются текстуры. Можно просто все бросить и пойти уже на работу художником по текстурам в любую компанию, которая разделяет моделирование и текстурирование (как это делаем мы, например).
Но так ли это? Мы действительно достигли предела в текстурировании и лучше уже не получится?
Или есть куда ещё расти?
Да! И у нас остался еще один тутор, который выведет текстурирование на новый технологический скачок и, по моему скромному мнению, будет представлять собой следующее поколение текстурирования.
Tile Textures
![]()
Эй, всем привет! Меня зовут Эндрю Харрингтон, и я ведущий художник по окружению. За время проведенное в индустрии я успел проработал во многих студиях. Учился и находился под влиянием у сотен людей. В этой статье я надеюсь поделиться некоторыми своими знаниями и процессом создания стилизованных текстур для окружения. В частности, я шаг за шагом разберу процесс создания следующей бесшовной текстуры.
Блокинг
Мой первый шаг при создании любой текстуры окружения — это либо нарисовать ее в Photoshop, либо сделать плоский блокинг геометрии в 3ds Max или Maya. Если я рисую текстуру в Photoshop, то обязательно позабочусь о том, чтобы она была бесшовной.А затем использую ее в качестве ориентира, чтобы сделать плоский блокинг. Обычно я работаю на плоскости 8m х 8m, потому что в большинстве случаев она обеспечивает соответствующую плотность текселей для использования в игре. Это разрешение позволяет лучше судить о детализации в текстуре в сравнении с размером персонажа.
После блокинга я решаю, какие части будут перекрываться, для обеспечения бесшовности. Обычно я работаю справа налево, а затем сверху вниз. Правый верхний кусок становится «краеугольным».
Теперь, когда я разобрался с тайлом, пришло время экструдить края каждого блока, чтобы у меня были фаски для скульпта. Важно отметить, что я не делаю экструд края ровно под углом в 90 градусов, а «раздуваю» их, чтобы они перекрывали края блоков. Это гарантирует, что я не получу никакого негативного пространства при добавлении деталей на фаски, и лучше буду контролировать края.
В конце я создаю плоскость размером 8m х 8m и центрирую ее позади моего блокинга. Это будет низкополигональная плоскость, на которую я проецирую свою высокополигональную сетку при запекании текстуры. Это также поможет мне в ZBrush, когда будет нужно сделать тайл сабтулов.
Наконец, все, включая плоскость 8×8, экспортируется в ZBrush одним .obj.
Добавление деталей
Базовая модель, экспортируемая в Zbrush — один целый кусок. Я хочу, чтобы каждый элемент был разбит на отдельный сабтул, чтобы я мог работать индивидуально над каждым из них и добавлять сабдивы без ущерба для производительности.
Сначала я использую функцию «Auto Group» на вкладке «Polygroup». Каждый элемент получает свою собственную Group ID, что позволит разделить их на сабтулы.
Во вкладке «Subtool» нажимаю «Groups Split» для разделения на отдельные сабтулы. Затем я применяю DynaMesh для ретопологии сабтулов,делаю 4–5 дивайдов. Это должно обеспечить достаточное разрешение для добавления хорошей детализации.
Существует много способов добавления детализации на поверхности, которые придадут им стилизованный вид. Основная цель, которую я преследую при добавлении деталей — дать достаточно информации, для понимания из какого материала сделан объект, но не слишком много, чтобы избежать лишнего «шума». Как говорил мне один из моих арт-директоров: «Иногда меньше значит больше». В данном случае я использовал метод добавления множества деталей, с дальнейшим удалением лишнего. Я начал с кисти ClayBuildup, чтобы добавить детали, а затем использовал Planer Brush, чтобы убрать их.
Примечание: использование квадратной альфы с Planer Brush даст вам хорошие острые края. Затем используется кисть TrimSmoothBorder для большей конкретизации.
Этот метод хорошо работает, поскольку дает чистую поверхность с намеками на детали. Я повторяю этот метод для остальных сабтулов. Как только вы сделаете это несколько раз, процесс пойдет довольно быстро. Я обязательно уделяю особое внимание краям блоков, чтобы у них было много углов, и они давали больше глубины. Без них текстура будет выглядеть довольно плоско. Также постоянно стоит проверять общий вид текстуры под прямым углом к камере, так как она будет выглядеть при запекании.
После того, как сделан скульпт всех сабтулов, я хочу добавить немного вариаций их вращения и глубины, чтобы придать текстуре дополнительный слой. Я делаю это лишь для некоторых сабтулов. Если бы я сделал это для всех элементов, это выглядело бы довольно неорганизованно. Изменения помогают уменьшить эффект повторяющихся элементов, когда текстура тайловая.
На этом этапе я готов выложить свою текстуру в ZBrush в плоскости 2.5D.
Тайлинг в ZBrush
Первое, что я делаю, когда готовлюсь сделать бесшовной геометрию в ZBrush — проверяю, чтобы размер моего документа соответствовал размеру будущей текстуры. Я делаю это для карты высот с корректным размером в 2.5D. В разделе «Document» я установил размер 2048 × 2048.
Затем я рисую Ztool на холсте и выбираю сабтул с плоскостью 8×8, который я экспортировал из Max с базовой геометрией. Выбрав его, я проверяю, чтобы Dynamic Perspective была выключена и размещаю сабтул в кадре. ZBrush будет кадрироваться в соответствии с любым выбранным вами сабтулом, поэтому я использовал плоскость. Таким образом, мой Ztool идеально вписывается в размер документа.
С кадрированным Ztool я теперь могу дублировать сабтулы по краям, а затем сделать офсет по сторонам. Если смещения не идеальны по пикселям, это нормально, я исправлю швы на следующем шаге.
Затем я перехожу в режим 2.5D. Вы можете прокрутить текстуру, удерживая тильду (`). Либо можете более точно сместить холст, перейдя на вкладку «Layer» и отрегулировав ползунки «Displace Н» и «Displace V».
Так как я знаю, что мой холст имеет размер 2048 × 2048, то если я смещу H и V на 1024 × 1024, все швы будут в центре холста.
Когда шов размещен посередине я «захватываю» карту высот холста с помощью инструмента «RGBZGrabber» в разделе «SimpleBrush», а затем очищаю холст, нажав «Ctrl + N».
Базовая плоскость 8х8 будет использована как высокополигональный мэш для дисплейса геометрии на основе только что полученной карты высот. Разрешение базовой плоскости увеличено до примерно до 4 миллионов точек при помощи дивайдов, но без сглаживания.
Карта высот назначается как «Current Alpha», в параметрах маскирования применяется «Mask by Alpha». Альфа-маска проецируется на мою плоскость 8х8m.
Во вкладке Deformation Options настраивается офсет геометрии. Обычно я корректирую смещение только до 5 или 6, поскольку не хочу сверхсильного смещения.
Теперь я могу очистить маску и отполировать швы. Я буду повторять шаги в режиме 2.5D, пока швы не будут полностью удалены. Как только это будет сделано, я экспортирую геометрию в качестве моей высокополигональной модели и буду использовать исходную плоскость 8mx8m в качестве моей низкополигональной для запекания.
Текстурирование
Для меня процесс текстурирования — это этап, на котором я, вероятно, трачу наименьшее количество времени. Мне нравится сохранять вещи довольно простыми при работе со стилизованными формами, так как я считаю, что это делает их более читабельными в игре.
В ходе текстурирования я предпочитаю сохранять все упорядоченным и для этого использую устаревший плагин DDO для Photoshop для организации слоев. Я загружаю только базовую карту нормалей в плагин и заменяю карты AO и Curvature.
Когда все базовые слои настроены с помощью запеченных текстур, я заполняю различные элементы моей текстуры сплошным цветом, близким к цвету, который я ищу.
Крайне важно то, что я устанавливаю все свои значения цвета для работы с Linear Rendering (Unreal Engine 4, CryEngine, Marmoset и т. Д.). В Liner Rendering среднее значение серого цвета (в RGB — пер.) не 127/127/127, а больше похоже на 187/187/187. Слишком часто я вижу слишком темные текстуры, которые нужно компенсировать, подавляя освещение в сцене. Темная текстура плохо воспринимает свет, поэтому окажите себе услугу и сохраняйте цветовые диапазоны в верхних значениях.
Пришло время наложить несколько мазков и тонких цветовых вариаций. Для этого я беру простую кисть с узором. В свойствах кисти я включаю настройки Color Dynamics, отключаю «Apply Per Tip» и задаю небольшие значения для оттенка, насыщенности и яркости. Теперь каждый раз, когда я делаю мазок кисти, он выбирает цвет в пределах диапазона.
Еще одна вещь, которую стоит отметить — я проверяю, чтобы flow и opacity кисти были установлены на 50%. Таким образом, я могу получать разные цвета.
Затем я накладываю некоторые более мелкие детали и играю с различными цветовыми вариациями, используя настройки слоя.
Последний шаг — использовать полученный результат в качестве текстуры основного цвета в Substance Painter, наложить некоторые эффекты и сгенерировать карты «Metall/ Roughness». В Painter я стараюсь все делать просто, так как я не хочу добавлять «шумы». Мне нужно лишь добавить немного гранжа и слегка детализировать карту Roughness. Мне нравится использовать «Bone Stylized» для этой цели, а затем добавлять немного цвета на карту грязи AO, чтобы поиграть с ней. Вот, наверно, и все. Как я уже говорил, иногда меньше значит больше.
Рендер
Я использую довольно простые настройки рендера в Marmoset. Используется трехточечный источник света, настроенный с помощью Child Lights на одной из Enviornment-карт. Поскольку при текстурировании я использовал высокие диапазоны в значениях цвета, я могу получить гораздо больше от освещения, не увеличивая его. Как уже было сказано, очень важно использовать правильные значения цвета.
Заключение
Надеюсь, что вам понравилось заглянуть внутрь моего процесса создания стилизованных текстур. Мои знания и навыки — это сочетание обучения, наблюдения за другими и МНОГО проб и ошибок. Самое замечательное в стилизованном искусстве заключается в том, что на самом деле нет универсальных ответов. Просто получайте от этого удовольствие. Спасибо!
Текстурирование, или что нужно знать, чтобы стать художником по поверхностям
Серия статей о том, как стать художником по поверхностям.
В данной серии очень больших статей я постараюсь максимально раскрыть теорию создания текстур для игровой индустрии, начиная от самого понятия «пиксель» и заканчивая построением сложных материалов (шейдеров) в игровом движке на примере Unreal Engine 4.
Серия уроков была написана год назад в пяти частях и выложена на «Хабр». Тогда я не дописал последнюю часть, оставив пятую часть без практики и подробных данных о том, как можно минимизировать потребление текстур и вывести текстуры на более высокий уровень.
Начиная выкладывать статьи на DTF, я постараюсь этот пробел закрыть, а так же ещё раз пробегусь по тексту и предоставлю вам более актуальную версию с отредактированным текстом (2-е издание, так сказать).
- Часть 1. Пиксель — вы её читаете.
- Часть 2. Маски и текстуры. Здесь.
- Часть 3. PBR и материалы.Здесь.
- Часть 4. Модели, нормали и развертка. Здесь.
- Часть 5. Система материалов. Здесь.
- Часть 6. Погружение в систему материалов. Здесь.
Я попытаюсь охватить такие программы, как Windows Paint, Photoshop, Substance Painter и Substance Designer.
Mixer от Quixel вышел сравнительно недавно и не будет добавлен в статьи в виду экономии времени. В целом, его работа практически ничем не отличается от работы любого другого ПО для текстурирования — принципы и ядро у всех одинаковые, а мы именно в глубь ядра и будем заглядывать.
Всё это будет рассмотрено с самых низких и базовых уровней для первоклашек и тех, кто с этим вообще никогда и ни-ни, чтобы по завершении прочтения этих статей, у читающего не оставалось никаких вопросов, было максимальное понимание, как это всё работает, и он мог начать уверено работать с текстурами и шейдерами в любом ПО, так как основа (база, суть) у всех одна.
Я не совершенен. Я не считаю, что я знаю эту тему «от и до». Я начал писать эту статью, чтобы помочь своим знакомым втягиваться в прекрасный мир текстурирования без моей помощи — чтобы они могли в любой момент открыть статьи, прочитать их и понять, как им с этим работать и что им делать. И я буду благодарен всем вам, если вы поможете мне с заполнением пробелов, чтобы мы все могли дать ссылку на эти статьи нужным людям, и они могли быстро втянуться. Я очень прошу всех, кому не безразлична эта тема и тема обучения этому направлению, помочь мне в комментариях — пишите свои правки или пожелания, если вдруг что-то я упущу или ошибусь в чем-то.
Очень прошу всех, кто может придумать другие примеры для лучшего понимания какого-то блока, отписаться в комментариях, чтобы я мог добавить эти примеры в статью. Вдруг, мои примеры окажутся недостаточными для полного понимания основы?
Итак, котятки, погнали =)
А что такое «Пиксель»?
Понятие «пиксель» используется в определении:
- физический элемент матрицы дисплея;
- цветовая точка в цифровом изображении.
И в том, и в другом случаях — пиксель является наименьшим элементом, обладающим цветом, из которого составляется изображение. Понятие «пиксель» равноправно используется и там, и там по той простой причине, что в целом принцип работы у этого элемента одинаков и в мониторах, и в изображениях с небольшими отличиями.
Поэтому, для начала разберём принцип работы пикселя на мониторе.
Важно: описание работы пикселей ниже является абстрактным и не описывает реальные физические явления работы ЖК-мониторов.
В мониторах пиксель является физическим элементом, состоящим из трёх светящихся элементов трёх цветов — красного, зелёного и синего. Интенсивность каждого элемента (сила свечения) определяет цвет пикселя. То есть, если зелёный и синий элементы перестают полностью светиться, а красный элемент остается включённым, то на экране это будет уже красная точка (красный пиксель). Если максимально приблизиться к монитору — можно разглядеть, как эта красная точка справа от себя имеет чёрный пробел — два погасших элемента.
Ещё раз повторим. Цвет пикселя определяется тремя световыми элементами — красным, зелёным и синим. В зависимости от их силы свечения получается сам цвет. Это важно.
Теперь представим это в виде шкалы интенсивности каждого элемента, где зелёный цвет представляет текущую интенсивность, а в квадрате справа цвет, который примерно получается из комбинации интенсивности элементов:
Соответственно, если мы уменьшим интенсивность зелёного и синего элементов до 0, то получим исключительно яркий красный цвет:
Теперь мы видим, что интенсивность яркости пиксельных элементов имеет границы. Эти границы я называю «диапазоном интенсивности».
Диапазон интенсивности — это диапазон состояния элемента от его минимального состояния (отсутствия свечения полностью) до его максимального состояния (максимальная яркость свечения).
Диапазон интенсивности можно выразить в различных значениях:
- от 0% до 100%. То есть, элемент может светиться в пол силы, иначе говоря, на 50%;
- от 0 до 6000 свечей. То есть, максимальная яркость элемента (100%) — 6000 свечей, а мощность на 75% будет равна соответственно 4500 свечам;
- от 0 до 255. То есть, 30% в этом диапазоне будут равны 76,5;
- от 0 до 1. То же самое, что 100%, только вместо 100 использовать 1 или 0.58 (58%). Это удобно для вычислений, что мы обязательно рассмотрим позже.
В статьях я буду использовать последний вариант представления диапазона от 0 до 1, так как он удобен для расчётов, в чём мы в дальнейшем убедимся. Этот диапазон можно назвать нормализованным диапазоном.
В реальности (за пределами наших условностей) яркость света в мониторах измеряется в единицах измерения candela, что в переводе с итальянского означает «свеча». В мире принято обозначать яркость и писать cd (русском варианте «кд»). В нашем туторе для того, чтобы обозначить именно условность этих значений, я буду продолжать использовать слово «свеча».
Теперь добавим к нашей шкале диапазоны интенсивности и получим следующую картинку.
Сейчас мы видим, что интенсивность R = 1, интенсивность G = 0.55-0.60, а B = 0. В итоге мы получаем примерно оранжевый цвет, который выдают нам на мониторах пиксели.
Важно понимать, что у каждого монитора, в зависимости от производителя матрицы, сборки и каких-то дополнительных параметров, сам уровень яркости может разниться. Например, диапазон яркости пикселя у матриц мониторов (условно):
- Samsung может быть 6000 свечей;
- LG = 5800 свечей;
- HP = 12000 свечей.
Это абстрактные цифры, не имеющие никакого отношения к реальности, нужны для того, чтобы было понимание, что у каждого монитора максимальная сила интенсивности может быть разной, а вот диапазон интенсивности всегда один — от 0 до 1. То есть, когда вы выкручиваете до 1 интенсивность красного элемента, то у вас он начинает светиться максимально ярко, потому что 1 = максимум.
Сейчас у нас появилось максимальное представление о том, как выстраивается цвет на мониторе — миллион пикселей настраивают интенсивность своих элементов так, чтобы в сумме получался нужный цвет. Если вы читаете на белом фоне чёрными буквами этот текст, то уже должны понимать, что сами буквы отображаются пикселями, которые полностью выключили свое свечение, а белый фон состоит из пикселей, которые включили интенсивность всех своих элементов на максимум.
Если заходить совсем глубоко в этот океан, то на полпути ко дну можно обнаружить, что у пикселя есть два диапазона интенсивности свечения — это диапазон интенсивности каждого элемента в отдельности, и общий диапазон интенсивности, который определяет в целом яркость всего монитора (для примера, яркость монитора убавляют в темноте и прибавляют, когда очень светло).
Итак, поняв, как выстраивается цвет в пикселях, мы понимаем, как формируется изображение на мониторе. А какой размер у пикселя? И почему размер важен?
Чем меньше пиксель физически в размерах, тем больше можно их засунуть в монитор. Однако само количество пикселей всегда ограничено разрешением экрана. Например, экран с разрешением 1920х1080 содержит в себе 2 073 600 пикселей.
Таким образом, в зависимости от диагонали монитора и разрешения экрана, пиксель на экране имеет свои размеры. Так, при диагонали монитора в 19 дюймов и разрешении 1920х1080 размер пикселя будет меньше, чем у монитора 24-х дюймов и таким же разрешением.
Чем меньше пиксель в своих размерах, тем больше их можно упаковать, и на одной и той же площади можно показать больше деталей и сделать картинку более качественно.
- У нас есть представление, как формируется цвет пикселей на мониторе.
- У нас есть представление о размерах пикселей, и что они могут изменяться в зависимости от самого монитора.
- У нас есть представление, что при разрешении 1920х1080 на экранах телефона картинки будут смотреться детальнее и чётче, так как пиксели меньше размером.
- И в целом, у нас есть понимание того, как формируется изображение на мониторе.
Ещё раз. Понятие «пиксель» используется в определении физического элемента матрицы дисплея, а так же является наименьшей цветовой точкой в изображении , из кучки которых формируется само изображение.
Давайте рассмотрим изображение, какую-нибудь картинку. Например, моего котика, который специально для статьи нарядился.
Данная картинка имеет разрешение 178х266 пикселей. То есть, картинка состоит из 47 348 пикселей и занимает на экране всего 2,2 процента пространства, если разрешение вашего монитора классическое — 1920х1080.
А так ли это? Действительно ли эта картинка занимает на вашем мониторе 47 348 физических пикселей? А если масштаб картинки уменьшить? При уменьшении и увеличении картинки число пикселей, из которых она состоит, не изменяется, а значит, пиксели в картинке явно подразумевают что-то другое, отличное от пикселей в мониторе. И да, и нет.
Пиксель в изображении — это наименьшая цветовая точка, из кучки которых составляется изображение. Количество пикселей в картинке никак не привязано к мониторным пикселям и их физическому размеру.
Когда компьютер хочет отобразить моего кота на вашем мониторе, он считывает каждый пиксель изображения поочередно и выводит их на монитор. При масштабе изображения 1 к 1 (1 пиксель изображения равен 1 пикселю монитора или, иначе говоря, масштаб равен 100%), размер изображения занимает точно такое же количество пикселей монитора, какое имеет сам.
Однако если мы увеличим картинку, то получится так, что один пиксель изображения будет занимать 4/9/16/25/36 (и так далее) мониторных пикселя:
Чтобы было ещё проще понять, что такое «пиксель» в изображении, обратимся к программной реализации этого объекта.
Пиксель в изображении для компьютера — это набор цифр. Он так же состоит из элементов, как и пиксель монитора, но уже с четырьмя элементами. Условно говоря, этот блок (кирпич, квадрат, точка, ничто) содержит в себе 32 бита. Эти 32 бита делятся на четыре элемента по восемь бит в каждом.
Элементы, из которых состоит пиксель, принято называть каналами .
Три канала отводятся на распределение интенсивности цветов красного (Red), зелёного (Green) и синего (Blue) (вспоминая, как работает пиксель в мониторе, сразу становится понятно, как эти значения влияют на цвет). Четвёртый канал отводится для прозрачности (сам канал называют Alfa). Ну вот мы и собрали все буковки вместе RGBA .
И так. Биты, RGBA, 32, 4 канала, 8 бит — немного каша, да?
Мы работаем с компьютером, поэтому должны понимать, что компьютер не понимает слова «красиво», «красный» или «интенсивный». Он понимает и думает только цифрами.
И думает не просто цифрами, а только двумя значениями 0 и 1. Причем, только либо 0 либо 1.
Так появляется БИТ — самое маленькое значение для компьютера, которое может быть либо 0, либо 1.
Как я писал выше, пиксель картинки состоит из 3 цветов + альфа данные.
Каждый их этих 4 составляющих называется каналом — красный канал, синий канал, и так далее.
Когда мы говорим, что один канал (например, Green) состоит из 8 бит, то это значит, что он буквально записывается в компьютере в виде 00110101 (цифры будут разные, это просто для примера).
А когда мы говорим, что один пиксель состоит из 32 бит, то он буквально записывается, как 00111100010101010111001101011010.
Программы, которые работают с изображениями, понимают, как правильно считывать данные. Например, первые 8 цифр — это зеленый канал, вторые — синий, и так далее.
Иначе говоря, пиксель в изображении — это набор цифр, значения которых определяют то, как этот пиксель отобразить.
В этих уроках мы будем рассматривать только 32-битные изображения и 8 битные каналы. Всё остальное — это уже частности и прочие стандарты, которые работают по аналогии.
Любой элемент размером в 8 бит может содержать в себе только 256 значений. Поэтому все наши каналы ограничены диапазоном интенсивности от 0 до 255.
И снова компьютерная тема.
8 бит — это 01010111.
Не очень удобно читать такие значения и править их, правда? Удобнее, когда это что-то привычное. Например, обычные значения 45, или 26, или 255.
Так вот, чтобы не было сложностей с чтением цифр, было решено переводить биты в нормальные значения. Но количество комбинаций 0 и 1 в 8 битах ограничено, и оно равно 256 уникальных комбинаций.
Отсюда и ограничение к 256 значений, где 0 — это первое значение, а значит, самое максимальное — 255.
Иначе говоря. Если каналы, отвечающие за зелёный и синий буду равны 0, а красный будет равен 255 — то пиксель изображения будет максимально красным. Если значение зеленого поднять до 128 (что равно середине или 0,5), то пиксель будет оранжевым, как на примере с пикселями от монитора выше.
Или вот такой вот ещё пример.
Подведя мини-итог — у пикселя изображения есть три канала цвета (три значения), которые имеют свой диапазон интенсивности от 0 до 255. Регулируя интенсивность канала, можно получать различные оттенки цветов. Alfa-канал не всегда используется в изображениях. Например, в Windows Paint нельзя редактировать Alfa-каналы и сохранять их. Но Photoshop умеет и любит работать со всеми каналами и даже больше — умеет добавлять еще сверху (но это тонкости, которые сейчас нас не интересуют).
Так завелось, что для визуального отображения диапазона интенсивности начали использовать оттенки серого цвета.
- Самый черный цвет = 0.
- Самый белый цвет = 1 (или 255, если рассматривать шкалу от 0 до 255).
С этого момента мы начнем пользоваться программой Adobe Photoshop, потому что у неё есть отличный способ визуализации составления цвета пикселя из трёх каналов.
Создание текстуры для готовой модели
Руководство по текстурингу\ ретекстурированию. Уровень сложности: Адепт.
Как известно, шмоток модов много не бывает, но каждому хочется выделить своего персонажа из толпы довакинов\нереваринов\эльфиек\вампиров. 🙂
Прекрасно знаю, как по-разному может выглядеть одна и та же вещь с разными текстурами. Поэтому, решила написать небольшой тутор по созданию текстур и ретекстуров для готовых моделек. А если точнее, то распишу последовательность действий, в которой я обычно работаю.
Недавно сделала несколько новых моделей, на примере одной из них буду показывать и рассказывать. Итак:
Название: Текстуры — тонкая материя.
Уровень сложности: Адепт.
Нужности: Photoshop+NVIDIA Tools Normalmap Filter+DDS Plugin, Autodesk 3D Max+Nif Plugin (Importer-Exporter).
Рейтинг: NC-17.
Размер: Миди.
Статус: Закончено.


Текстуры во многих играх «запаковываются» в формат DDS, по своей сути это еще один алгоритм сжатия изображения, как PNG или JPEG, который имеет гибкую систему настроек. Чтоб создавать игровые текстуры, нужно установить DDS Plugin для фотошопа.
Если открыть чужую текстуру и с ходу начать поверх нее работать, то можно перепутать верх и низ, один элемент с другим, лево и право (да-да,так тоже можно). Некоторые текстуры интуитивно понятны, а в некоторых черт ногу сломит. Дабы не гадать на бобах и не запускать по сто раз игру для проверки, надо выяснить, с чем мы имеем дело 🙂
Цель описанных далее манипуляций — определить, как лучше работать над текстурой в 2D. Если вы ровненько наложили красивые текстурки и не можете понять, почему же в игре великолепные узоры поплыли, то 3D вам в помощь.
Нам понадобится рассмотреть выбранную модель в 3D максе. Макс у меня открыт почти все время, пока я делаю текстуру, в нем можно быстро посмотреть результат манипуляций в 2D редакторе, подключить сетку для лучшей ориентировки и т.д.
Модели в Скайриме (и еще в некоторых играх) в формате Nif. И для экспорта в макс нужно поставить Nif Plugin.
Нажимаем на эмблему макса в левом верхнем углу, Import.

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


Легче всего взять файл прямо из Data, но если вы выложили модель в любое другое место, проверьте, чтобы в пути к файлу не было русских букв (макс может выдавать ошибку). У меня импортер не ругается только на русскоязычные название жестких дисков и рабочий стол, но у всех по-разному, у вас может с рабочего стола не открыть.
Опять жмякаем Import.

Готово, модель с нами.

Выделим ее ЛКМ. Справа, на панели инструментов заходим во вкладку Modify, в списке у вас будет три модификатора.

Щелкаем на верхней строчке ПКМ, выбираем Collapse to -> Yes. (Просто мера предосторожности, чтоб избежать вылетов.)

Добрались до главного. Чуть выше, в Modifier List находим модификатор Unwrap UVW. Весь список не листаем, достаточно щелкнуть по нему и нажать U на клавиатуре, все просто. У меня этот модификатор до кучи вынесен на отдельную кнопку, прямо под списком, вместе с другими «горячими» модификаторами 😀
[Для справки: этот модификатор позволяет присвоить пространственным точкам модели (вертексам) такое значение на плоскости, при котором рисунок, наложенный в дальнейшем на плоскость в 2D редакторе, не будет искажен на данной объемной модели.]
Open UV Editor.

Открывшееся окно разворачиваем, в нем нам нужен пункт рендера развертки. Tools -> Render UVW Template.

Теперь выберем размер в пикселях. Корректными значениями будут: 8х8, 16х16. 512х512, 1024х1024, 2048х2048, 4096х4096. Выбирайте размер под свои нужды. Обычно я беру 4к или 2к (для больших и мелких объектов соответственно), изначальный большой размер дает лучшее качество при дальнейшем сжатии. 4к можно потом уменьшить на 2к, 2к на 1к и т.д. без значительных потерь. Уменьшать — не растягивать 😀
Render UVW Template.


Полученное изображение сохраняем в формате PNG. Формат PNG очень классный, он сохраняет прозрачность. На кой черт оно нам надо? Изображение помещается в фотошопе на самый верхний слой, оно прозрачное и не содержит ничего лишнего, кроме граней модели. Если исходные текстуры на выбранной вами модели очень мусорные и невозможно из них понять, что к чему относится, то отрендеренная развертка поможет четко разграничить объекты.

Как я уже писала в самом начале, 3D макс оставляю открытым почти все время текстурирования. Есть еще несколько вещей, которые хотелось бы упомянуть.
Если после рендера все еще остается непонятным, какой элемент развертки за что отвечает, то можно использовать окно Unwrap, чтобы все прояснить. В левом нижнем углу нужно отметить «выделение по полигонам» и «выделение по элементу». Это позволит выделить элемент полностью, нажав на любой полигон, относящийся к нему.


Во вьюпорте элемент тоже выделяется.

Очень удобно для выявления вот таких маленьких объектов.

Развертки бывают разные..
Правильно сделанная развертка — залог вкусной текстурки. :3 Плохая развертка несет с собой отчаяние, разрушение и багет :С Она непредсказуема, с ней сложно работать в 2D редакторе. Прежде чем браться за ретекстур не лишним будет проверить, а стоит ли?
Material editor -> Diffuse -> Checker.

Перетаскиваем сферу (материал) на объект. Это стандартный материал макса для проверки на вшивость. Представляет из себя «шахматную доску». Там, где растягиваются квадраты, растянется и итоговая текстура. Все дело в степени потянутости. Есть приемлемые растяжения, а есть не совместимые с жизн работой в 2D редакторе. Некоторые модели лучше оставить в покое, серьезно..для безопасности своих же нервов.
При желании можно увеличить тайлинг (квадраты уменьшатся), чтобы оценить адекватность развертки на мелких деталях.




Сразу несколько примеров.


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


Чужая модель — потемки. Если свой собственный меш я знаю от и до, какие где швы находятся, имеются ли искажения, как части развертки соотносятся друг с другом по размеру..и прочие мелочи, то чужой меш приходится изучать.
Ладно,перейдем уже к фотошопу.
Начнем с создания Diffuse map, а, проще говоря, нарисуем карту цвета. Одно важное действие, которое полезно предварительно сделать. Создать «маску» для каждого элемента. В кавычках потому, что это не маска слоя. Это всего один слой, на котором у меня лежать все силуэты элементов, залитые каким-нибудь одним цветом.
Вот так это выглядит.

Зеленые линии — границы элементов (верхний слой).

Маску всегда создаю с небольшим припуском, с помощью инструмента «перо». Никакие сглаживания не делаю, только грубое выделение. Главное — не оставлять открытые участки.Все, что происходит в Вегасе, остается в Вегасе.
Все, что происходит дальше — находится между первым слоем и слоем с маской. Слоев получается много, очень много..слишком :\ (Я делаю резервные копии всего, что только можно, поэтому к концу работы собирается огромная группа «Резерв».)

Для каждого объекта (или материала) создаю свою папку, чтобы они не зависели друг от друга. Я не сливаю слои до последнего, чтоб была возможность скорректировать один элемент, не затрагивая остальные.
В процессе работы на слоях скапливается много шлака. В любой момент можно встать на слой-маску, сделать выделение нужного объекта, инверсию выделения и быстро удалить весь мусор. Или нарезать и примерить пачку фото, в поисках подходящей текстуры.
Кстати, не всегда можно найти подходящую под замысел картинку в и-нете, иногда приходится действовать по вдохновению, my brothers. Например, за основу для подошвы я взяла фото собственного сапога. И вообще, стараюсь фотографировать все, что может пригодиться для текстурирования. Также для создания подошвы мне понадобились старый забор, гвоздодер и наждачка.



Еще слой-маска полезен, если у вас нет возможности или желания запекать карту теней. Выделяем нужный объект и, ориентируясь по слою с разверткой, чисто и быстро накидываем тени.

Cнова открыв Material editor, можно примерить текстуру на модель: Diffuse -> Bitmap -> Твоя_текстура.jpg\png\tiff.


Теперь уже можно в целом посмотреть на то, что мы натворили. Включив сетку, увидим, как исправить тот или иной косяк, на какое конкретно место что нужно передвинуть.

Теперь пора оживить модель. Normal map — та самая карта, которая дает плоскому Diffuse map рельеф. Грубо говоря, эта карта создает реакцию на свет и тень. Наложив нормали на лоу-поли модель можно добиться эффекта объема.
Мидл-поли штаны и хай-поли обувь.

Normal map штанов.

Реакция на освещение.


Карту для штанов я снимала с хай-поли модели.

Нормали могут выглядеть по-разному. Для рендера в 3D максе, например, подходит ч\б версия диффуза, но он также воспринимает и другие виды нормалей. Далее я распишу один из способов создания подобной карты в фотошопе.
Нам понадобится установить NVIDIA Tools Normalmap Filter.
Сперва нужно обесцветить созданный ранее диффуз. Но перед этим важно учесть одну особенность: темные оттенки воспринимаются как углубления, а светлые — как выпуклости. Что из этого следует? Нужно обратить внимание на материалы: царапины всегда будут светлее основы, а т.к. царапины — это углубления, то придется их сделать темными, чтоб фильтр их понял правильно.
Например, на этой текстуре присутствует два материала: кожа и металл. Оба они имеют царапины.

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


В данном случае я инвертировала сразу оба материала.
Что касается наших ботинок, то на них есть некоторые материалы, которые не нуждаются в инверсии. Колдовать придется с металлом, темными швами и царапинами на подошве. Подошва представляет собой наиболее сложный объект, т.к у нее есть ребристая поверхность, которую НЕ нужно инвертировать, и царапины, которые нужно инвертировать. Упорядочивание слоев и групп может показаться слишком педантичным, но сейчас без этого было бы очень сложно.
Первым шагом я создаю две новые группы Normal и Diff (да-да, снова группы, еще больше групп). В Diff скидываю весь диффуз и отключаю тени, сейчас они не понадобятся. Далее, стоя на группе Diff, нажимаю Ctrl+Alt+Shift+E. Создается слой со всем содержимым, который отправляется в папку Normal (можно перед этим еще фон отключить, но это не столь важно). Применяем к нему обесцвечивание.


Группу Normal пока можно скрыть и заняться сложными пациентами. После обработки, накладываю инвертированные объекты поверх обесцвеченных. Можно еще подтянуть контраст или наоборот, приглушить некоторые моменты. Теперь все готово к применению фильтра Normalmap.

Заходим в Фильтр -> NVIDIA Tools -> NormalMapFilter. В окне настроек можно поменять Scale, попереключать каналы (задействует красный, зеленый, синий или все сразу) и посмотреть на результат. Сейчас меня устроили такие настройки.

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

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

Добиться лучшего эффекта можно несколькими простыми действиями. Копируем полученный слой, ставим ему режим перекрытия и применяем на нем фильтр Размытие по Гауссу. А дальше только нажимаем Ctrl+J (скопировать слой) и Ctrl+F (применить последний фильтр, в нашем случае «размытие»).
Теперь больше похоже на правду.

Кратко о Specular map (карта блеска). Тут уже более-менее без выкрутасов. Нам понадобится простой ч\б вариант диффуза. Регулировка производится таким образом: черный цвет — нет блеска, белый цвет — есть блеск. Металл может быть ржавый, тусклый. Или наоборот — отшлифованный. Кожа может быть матовой, потертой или лакированной. Свойства материала настраиваются в соответствии с задумкой.
Спекуляр может быть сохранен как отдельная карта или вставлен в альфа-канал нормала.

Последним пунктом является сохранение созданных текстур в DDS формате. Файл -> Сохранить как, выбираем расширение DDS. В открывшемся диалоговом окне нам предлагают выбрать тип текстуры и степень сжатия. Подробно про разные алгоритмы сжатия можно почитать тут и еще тут. Сейчас я сохраняю в DXT5.

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




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