Древнейшая проблема бэйкинга и её изящное решение
Так о чем же речь?
В настоящее время существует огромное количество материалов, подробно объясняющих как устроен процесс запечки. Казалось бы, уже не осталось неосвещенных проблем и «сакральных» способов их решения в области бэйкинга. Но все же, на мое удивление, существует одна тема, которая затронута очень слабо, но оказывает ощутимое влияние на качество выпечки ваших моделей.
Данная статья будет посвящена усреднению нормалей клетки и артефактам, которые это усреднение вызывает. А также мне хотелось бы рассказать об одном способе решения этих проблем, которому, на мой взгляд, уделено слишком мало внимания. Этот материал предполагает наличие базовых знаний о бэйкинге. Если вы не знакомами с основами, предлагаю к прочтению данные статьи:
Два фактора, определяющих качество вашей запечки
Наверняка многие из читающих этот материал знакомы с таким артефактом как «бахрома» при выпечке цилиндров с фаской. Еще с давних времён, на первых форумах, посвященных 3д, появлялись статьи об этом нежелательном эффекте и способах его устранения.
Рис. 1. Пример «бахромы» (волнистый край фаски). Наиболее заметен при виде сбоку.
Рис. 2. Пример «бахромы» на развёртке цилиндра.
Мы будем рассматривать проблему неправильного переобразования форм High Poly модели в карту нормали Low Poly модели на примере появления бахромы на цилиндрах. И начать стоит с двух факторов, без которых мы бы не говорили на эту тему:
1. Различие форм Low Poly и High Poly моделей
Рис. 3. Low Poly (красный) — 6 граней. High Poly (синий) — 48 граней.
Как бы мы ни старались совместить геометрию Low Poly объекта с High Poly объектом, у нас всегда будут получаться несовпадения. В принципе на то Low Poly и Low Poly, что отличается в меньшую сторону количеством геометрии, нежели High Poly. А на примере с цилиндрами у нашей низкополигональной модели будет всегда меньше боковых граней, чем у высокополигональной.
Рис. 4. Варианты сопоставления Low Poly и High Poly цилиндров. Красными стрелочками указаны области наибольшего несовпадения геометрии.
Опираясь на изображение выше, видно, что как бы мы ни совмещали две модели, у нас всегда будут места, где геометрия этих моделей будет наиболее близка друг к другу, и напротив, области, в которых она будет максимально разнесена. И это неизбежное явление станет «катализатором» в появлении бахромы для фактора номер два.
2. Averaging Normals и интерполяция векторов
Давайте взглянем на клетку, из которой проецируются лучи на Low Poly модель при запечке.
Рис. 5. Cage (Клетка) — бежево-прозрачный. Low Poly — красный.
Нам известно, что при запекании лучи проецируются из вершин клетки в вершины Low Poly.
Рис. 6. Cage (клетка) — прозрачный / серый. Rays (лучи) — синий. Low Poly — красный.
По всей же остальной поверхности модели лучи интерполириуются между лучами, направленными из вершин клетки в вершины Low Poly.
Рис. 7. Пример интерполяции векторов между векторами 'a' и 'b'.
В наших же подопытных цилиндрах интерполяция векторов на определённом участке будет выглядеть вот так:
Рис. 8. Пример интерполяции лучей при запечке на небольшом выбранном участке ввиде линии.
Не мешайте водку с пивом!
По отдельности ни интерполяция лучей, исходящих из клетки, ни разница в геометрии между Low Poly и High Poly объектами не являются чем-то плохим, но вместе они начинают давать крайне негативный эффект.
Рис. 9. High Poly — серый. Rays (лучи) — красный. Low Poly — normal map color.
В результате интерполяции в месте, где на High Poly проходит граница фаски, лучи, исходящие из клетки, проецируются не перпендикулярно, а под углом. И чем большее расстояние они успевают пройти, прежде чем достигнут Low Poly, тем большее искажение информации мы получим на запечённой карте нормалей. Поэтому на краях цилиндра, которые ближе всего находятся к геометрии High Poly, искажение минимально и, напротив, чем ближе к середине грани, тем большее расстояние между геометрией, и тем сильнее граница фаски съезжает вниз, образуя искривление, называемое бахромой.
Так что же с этим делать?
Если известны причины — будет и решение! Можно снизить влияние первого фактора, различия в геометрии между Low Poly и High Poly объектами, добавив в низкополигональную модель дополнительных граней. Но раз уж мы изготовили Low Poly модель такой, какая она есть, значит так было нужно, и добавлять новую геометрию не то, что хотелось бы.
В таком случае у нас остается второй вариант — работать с направлением лучей. И тут на ум приходит следующее: добавить дополнительный edge loop на клетке, чтобы лучи начинали менять свое направление только в том месте, где начинается фаска на высокополигональной модели.
Рис. 10. Cage (клетка) — прозрачный / чёрный. Дополнительные ребра на клетке — жёлтый. Rays (лучи) — синий. Срез High Poly — серый. Low Poly — красный.
Как видно на изображении выше, благодаря дополнительному ребру на клетке лучи начинают свой наклон именно в том месте, где начинается фаска. Таким образом мы бы избавились от бахромы, ведь теперь лучи на границе фаски перпендикулярны поверхности, а значит, теперь пройденное лучом расстояние от геометрии Low Poly до High Poly не имеет значения, ведь луч не имеет наклона, а значит, не будет и искажения за пройденное расстояние.
Рис. 11. Разница в проекции лучей между обычным цилиндром и клеткой (сверху) и цилиндром и клеткой с добавлением рёбер (снизу).
Всё бы хорошо, если бы не одно «но». Ни один из существующих ныне бэйкеров либо не умеет работать с клетками, геометрия которых по количеству и индексам вершин отличается от геометрии низкополигональной модели, либо делает это очень плохо, где-то принимая во внимание дополнительные ребра для изменения интерполяции лучей, а где-то полностью игнорируя их. А это значит, что такое же ребро придется добавить и на Low Poly модель для проекции лучей строго из вершин клетки в вершины Low Poly. А так как мы не хотим создавать дополнительную геометрию на низкополигональном объекте, то после запечки нам нужно будет еще и удалить его.
А ещё есть один важный момент, который я пока не упоминал. Это развёртка клетки. Дело в том, что она тоже играет очень важную роль. Проекция лучей происходит не только из вершины клетки в вершину низкополигональной модели в 3д пространстве, но еще и из вершины uv развёртки клетки в вершину uv развёртки Low Poly.
Подробнее о том, как устроен процесс запечки карт нормалей изнутри, можно узнать в этом материале:
В нашем же цилиндре после выдавливания клетки из Low Poly или добавления ребра на уже существующую клетку на UV развёртке оно окажется в другом месте, нежели ребро на UV развёртке низкополигональной модели. И нам нужно будет его совместить.
Рис. 12. По направлению зелёных стрелочек нужно совместить вершины развёртки клетки с вершинами развёртки Low Poly.
Передвижение вершин на UV развёртке клетки, конечно же, приведёт к деформации текстурного пространства, но деформация пространства клетки не ведёт для нас ни к чему плохому, в отличие от того, как если бы деформировалось UV пространство низкополигональной модели.
Рис. 13. Пример деформации uv на клетке.
С фаской на боковых гранях цилиндра вроде бы решено, ну, а что же делать с фаской на верхней и нижней стороне цилиндра? Она ведь тоже получает искажение. Происходит это, как видно на иллюстрации ниже, из-за всё тех же факторов: расстояния, которое проходят лучи, и их наклона. В результате радиус границы фаски уменьшился, а сама фаска немного растянулась.
Рис. 14. Cage (клетка) — прозрачный / чёрный. Rays (лучи) — красный. High Poly — прозрачный / серый. Low Poly — цвет карты нормали.
В принципе, этот артефакт заметен вовсе не так сильно, чтобы тратить время на добавление еще одной секции рёбер, но тем не менее, если вам это по какой-то причине нужно, придётся добавить дополнительный edge loop, желательно равный по количеству вершин границе фаски High Poly модели, а затем так же подогнать вершины uv клетки к вершинам uv Low Poly модели.
Рис. 15. Cage (клетка) — прозрачный / чёрный. Rays (лучи) — красный. High Poly — серый. Low Poly — цвет карты нормали.
В таком случае финальный вид клетки и Low Poly модели будет выглядеть как-то так:
Рис. 16. Low Poly с добавленными для запечки рёбрами — слева. Cage (клетка) — справа.
Добавление и удаление дополнительных рёбер
Добавить ребро на Low Poly модель перед запечкой, а после удалить звучит достаточно тривиально, но не стоит забывать, что добавление рёбер ведёт к изменению триангуляции модели.
Рис. 17. Триангулированный Low Poly с добавленными для запечки рёбрами — слева. Триангулированный исходный Low Poly — справа.
Для запекания нужного нам Tangent Space Normal Map это критично, ведь этот тип карт нормалей основан на вычислениях направления отражения лучей относительно нормалей вершин объекта (касательного пространства). Добавление же новых вершин и изменение триангуляции, а следовательно и этих нормалей, приведёт к тому, что запеченная карта нормалей больше не будет валидна для этой модели.
Подробнее о картах нормалей касательного пространства (tangent space) можно узнать вот тут:
На самом деле, в этом примере с цилиндрами разницы в шэйдинге из-за другой триангуляции фактически не будет, но мы лишь рассматриваем их как пример, поэтому будем считать этот вариант не всегда рабочим.
И неужели снова тупик?
World Space Normal Map вступает в игру
Мы знаем, что карта мирового пространства, которая доступна для запечки практически во всех известных мне бэйкерах, полностью игнорирует шэйдинг модели. То есть, в отличие от карты нормалей касательного пространства, каждый тексель имеет закодированный через три канала RGB трёхмерный вектор, который указывает на направление отражения лучей от поверхности в мировом пространстве. В каждом текселе Tangent Space Normal Map также через RGB закодирован вектор (хотя бывают и двухканальные карты, но сейчас не об этом), только этот вектор показывает отклонение отражения лучей относительно нормали объекта, в точке падения луча.
Вот отличный материал, в котором достаточно просто объясняются основные отличия разных типов карт нормалей:
Исходя из вышесказанного, выходит, что если взять две модели с одинаковой формой геометрии и развёрткой, но разным шэйдингом и запечь их с одной и той же High Poly моделью, то их Tangent Space Normal Map окажутся разными, а World Space Normal Map — одинаковыми?
Рис. 18. Первый ряд — естественный шэйдинг. Второй ряд — Tangent Space Normal. Третий ряд — World Space Normal.
Всё верно. На примере выше — два цилиндра, которые имеют идентичную UV развёртку и геометрическую форму, а вот количество вершин, триангуляция и шэйдинг (я намеренно испортил шэйдинг правой модели, дабы продемонстрировать разницу) у них разные. Хорошо заметны визуальные отличия между их Tangent Space Normal Map, но вот World Space Normal Map между собой абсолютно идентичны.
А самое замечательное в этом всём то, что World Space Normal Map можно конвертировать в Tangent Space Normal Map, используя при конвертации нужную вам низкополигональную модель.
Таким образом, мы сначала можем запечь карту мирового пространства на Low Poly модель с добавлением рёбер для нужной нам интерполяции лучей, а затем конвертировать её в карту касательного пространства для низкополигональной модели с исходной геометрией.
Рис. 19. Схема получения валидной карты касательного пространства (Tangent Space) из карты мирового пространства (World Space) при запечке из отличающегося по шэйдингу объекта.
Для конвертации World Space в Tangent Space я буду использовать Substance Designer (также я слышал, что это умеет делать утилита под названием HandPlane). Для этого возьмём полученную карту мирового пространства из Substance Painter (или любого другого бэйкера), а так же исходную низкополигональную модель и импортируем их в граф Substance Designer. После чего нажмём правой кнопкой мыши по Low Poly модели в нашем графе и в появившемся окошке кликнем «Bake model information».
Рис. 20. Конвертация World Space в Tangent Space. Шаг первый.
Далее в появившемся окне выполним следующие шаги:
Нажмём «Add baker».
В открывшемся окне выберем World Space Direction.
Во вкладке «Baker Parameters», в параметре «Input Direction» выберем «From Texture».
В той же вкладке, в параметре «Direction File» выберем нашу карту World Space из импортированных ресурсов.
Остальные параметры выбираем по вашим нуждам, как и в любых других бэйкерах, которыми вы пользуетесь. Затем нажимаем «Start Render».
В правой части окна отобразится результат выпечки, который сохранился по указанному вами пути.
Рис. 21. Конвертация World Space в Tangent Space. Шаг второй.
Для тех, кто будет повторять эти шаги, рекомендую обязательно триангулировать и создать Tangent Space при экспорте Low Poly модели из вашего 3д-редактора. Так как разные программы делают это по-разному, это может привести к неожиданным артефактам. Например, в моем случае я не сделал этого, полагая, что и Substance Painter и Substance Designer сделают эти вещи одинаково, ведь они выпускаются одним и тем же издателем. Но нет, я получал артефакты до тех пор, пока не сделал это при экспорте из Blender.
Посмотрим на результат
Рис. 22. Результат запечки на Low Poly с дополнительными гранями и конвертации карты касательного пространтсва на исходную модель из карты мирового пространства.
Повторим еще раз, но очень кратко:
Запекаем на Low Poly модель с дополнительными гранями карту World Space Normal.
Для наглядности я сделал пару изменений: намеренно включил полное сглаживание этой низкополигональной модели, чтобы различия в картах Tangent Space было хорошо видно, а также увеличил размер фаски на High Poly и Low Poly/Cage соответственно.
Рис. 23. Исходные объекты для запечки.
Сохраняем карту World Space Normal и переносим в Substance Designer.
Рис. 24. Результат запечки. Tangent Space запечён только для наглядности.
Конвертируем World Space Normal в Tangent Space, используя изначальную Low Poly модель.
Рис. 25. Конечный результат.
В заключение хотелось бы отметить, что этот материал написан не для того, чтобы показать, как правильно запекать цилиндры. Мне хотелось поднять тему несовершенства существующего в данный момент алгоритма запечки и способе устранения тех артефактов, которые появляются в результате нежелательной интерполяции лучей в некоторых местах на Low Poly модели. Такой способ я считаю универсальным и применимым к любым моделям, которые вы изготавливаете.