![image](https://habrastorage.org/getpro/habr/post_images/c04/14c/07c/c0414c07c198aeaa0b580a88e67f66b3.jpg)
Часть 1: что такое карты нормалей и как они работают
Часть 2: как запекаются карты нормалей
Часть 3: типы карт нормалей
Это четвёртая часть туториала о картах нормалей, но она независима от остальных частей и её можно читать отдельно.
Здесь я перечисляю проблемы карт нормалей, с которыми я сталкивался за годы работы, и некоторые решения, позволяющие их устранить.
Проблема: на рёбрах модели присутствуют «чёрные линии» или «вставки»
![image](https://habrastorage.org/getpro/habr/post_images/300/3c2/fc0/3003c2fc07215c52e319e3354e391526.jpg)
Такое происходит, когда у модели есть резкие рёбра (hard edges), поскольку вершины модели имеют нормали, полностью перпендикулярные поверхности полигона, из-за чего программа запекания может пропустить некоторые детали (оставляя на модели чёрные линии).
![image](https://habrastorage.org/getpro/habr/post_images/94f/4dd/da9/94f4ddda9c6073b147f8f35a7db1fc30.jpg)
Решение: программы запекания карт нормалей учитывают эту проблему при создании карт нормалей и пытаются снизить её влияние, вычисляя немного больше информации за нормалями вершин, но чтобы сохранить её, им нужен зазор между UV-развёртками полигонов.
Здесь есть более подробное объяснение, но на практике правило довольно простое: когда на модели есть резкое ребро, нужно отделять в UV соединённые им грани.
Проблема: карта нормалей выглядит СОВЕРШЕННО неправильно, особенно под некоторыми углами
Эта проблема может возникать по множеству причин. Давайте обсудим некоторые из них:
- Вы используете неправильное касательное пространство: нормали вашей lowpoly-модели, которые мы пытаемся модифицировать при помощи карты нормалей, могут вычисляться в программе запекания иначе, нежели в программе, использованной для рендеринга модели. Если эти вычисления отличаются, карта нормалей может выглядеть очень странно, особенно под некоторыми углами.
Также возможно, что вы используете в качестве карты нормалей касательного пространства карту нормалей мирового пространства. В таком случае убедитесь, что вы выполняете запекание карты нормалей касательного пространства, и используете её в этом качестве.
Решение: старайтесь всегда использовать для вычисления карт нормалей базис касательного пространства Mikk. Это стандартизованный способ вычисления нормалей, позволяющий избегать подобных проблем. Если программа запекания карт нормалей не может использовать Mikk, попробуйте воспользоваться программой наподобие handplane для переключения между различными касательными пространствами. - Вы используете в карте нормалей гамма-коррекцию: карты нормалей — это не обычные изображения с информацией о цвете. Они содержат информацию о нормалях поверхностей, и не ведут себя как цветные изображения. Гамма-коррекция — это регулирование цветов изображения, способное нежелательным образом изменять цвет карты нормалей. Чтобы убрать гамма-коррекцию из карты нормалей, смените цветовое пространство карты нормалей на linear/linear color/raw или снимите флажок sRGB в движке Unreal.
- Вы не используете карту нормалей касательного пространства как карту нормалей касательного пространства: убедитесь, что движок не использует карту нормалей касательного пространства как карту нормалей пространства объекта, рельефную карту (bump map), карту смещений (displacement map) и т.д...
- Нормали lowpoly-модели в программе запекания отличаются от нормалей lowpoly в программе рендеринга: это может происходить, если в процессе экспорта/импорта теряется информация о группах сглаживания (smoothing groups)/резких рёбрах (hard edge), если вы используйте изменённые/весовые нормали, а программа рендеринга не поддерживает их или отбрасывает эту информацию.
В таком случае сравните lowpoly в обоих приложениях и если они отличаются, то попробуйте изменить параметры импорта/экспорта, используемые форматы файлов (файлы obj теряют информацию о нормалях) и проверьте совместимость своей программы с настраиваемыми нормалями.
Проблема: как мне создать карту нормалей острого конуса?
Решение: вам это… не нужно. Не обязательно создавать карты нормалей для всего. Острый конус — классический пример этого, но существует множество других случаев, когда карты нормалей не являются решением.
![image](https://habrastorage.org/getpro/habr/post_images/eff/c59/2bc/effc592bc5b65c113db37e86eb26ee1a.jpg)
Мы используем карты нормалей для изменения направления нормалей lowpoly-моделей. Иногда направление нормалей правильно и не требует никаких изменений, а иногда нормали lowpoly чрезвычайно повёрнуты (как в случае острого шипа) и детали из highpoly-модели неправильно сопоставляются с поверхностью lowpoly-модели. В таких случаях я просто удаляют детали карты нормалей при помощи такого цвета:
![image](https://habrastorage.org/getpro/habr/post_images/aa3/a2b/2f7/aa3a2b2f7c2948cbf626da237c3a2307.jpg)
Этот цвет на 50% красный, на 50% зелёный и на 100% синий, и он не меняет направления нормалей карты нормалей касательного пространства, поэтому можно использовать его для удаления деталей в местах с неудачной проекцией.
Острый конус — это просто пример одного из случаев, когда карты нормалей могут не решить ваших проблем. Важно здесь помнить, что в некоторых случаях карта нормалей не является наилучшим решением, её возможности ограничены и мы не можем ожидать, что они будут вести себя так, как нам нужно, в любой ситуации. Иногда мы тратим много времени, пытаясь заставить работать карту нормалей, когда можно было бы просто добавить деталей в diffuse-текстуру или в lowpoly, а не пытаться передать деталь при помощи карты нормалей.
Проблема: детали на моей модели выглядят вывернутыми.
Это очень распространённая проблема, и её можно наблюдать во многих видеоиграх, даже AAA-уровня.
Как мы видели в этом туториале [перевод на Хабре], карты нормалей — это текстуры, использующие зелёный, красный и синий каналы для изменения способа отражения света от поверхности модели, когда он падает соответственно сбоку, сверху и спереди модели (помните, что это упрощённое объяснение и оно верно не на 100%).
![image](https://habrastorage.org/getpro/habr/post_images/693/1df/95d/6931df95deb620abb8e75ca0932cfdad.jpg)
Проблема в том, что некоторые приложения считают, что зелёный канал должен показывать модель как освещённую снизу, а другие считают, что он должен показывать модель как освещённую сверху. Иногда это называют «правостороннесть карты нормалей» (normal map right-handiness):
- OpenGL-приложения (правосторонние, положительный зелёный канал): Blender, Maya, Modo, Toolbag, Unity.
- DirectX-приложения (левосторонние, отрицательный зелёный канал): 3DStudio Max, CryEngine, Source Engine, Unreal Engine.
- Substance Painter может работать с обоими типами и экспортировать оба типа карт нормалей.
Решение: инвертировать зелёный канал карты нормалей. У большинства игровых движков есть опция текстур инвертирования карты нормалей, или же вы можете вручную инвертировать зелёный канал текстуры в Photoshop (перейдите во вкладку каналов, выберите зелёный канал и нажмите Ctrl+i).
Проблема: некоторые части кажутся плоскими/в них отсутствуют какие-то детали
Представьте, что при запекании карт нормалей программа запекания испускает лучи из поверхности lowpoly-модели, следуя по нормалям lowpoly, пока лучи не пересекутся с highpoly-моделью и не повернутся. После этого программа запекания берёт эту информацию и сохраняет её в карту нормалей.
Эти испущенные лучи не должны двигаться бесконечно, потому что могут столкнуться с далёкой частью highpoly и повернуться неправильно, поэтому программа запекания ограничивает дальность испускания лучей и иногда лучи могут останавливаться прежде, чем успеют пересечься с highpoly. В таком случае мы теряем детали и карта нормалей имеет области плоского цвета.
![image](https://habrastorage.org/getpro/habr/post_images/eeb/be0/bb7/eebbe0bb7369dd4f9e184b96df91ccd3.jpg)
Решение: зависит от того, как программа запекания позволяет управлять расстоянием запекания:
- Некоторые программы ищут детали только снаружи lowpoly и игнорируют то, что находится «внутри» lowpoly-модели (однако большинство современных программ запекания выполняет поиск в обоих направлениях). В таком случае нужно модифицировать модели так, чтобы lowpoly полностью находилась внутри highpoly.
- Другие программы, например Max, используют клетку (cage) — «экструдированную» версию lowpoly, которую можно изменять для точного управления границами процесса запекания.
- Другие программы позволяют задавать расстояние запекания числом (в Substance Painter это max frontal/rear distance).
Также можно попробовать сделать lowpoly и/или highpoly более похожими друг на друга, чтобы лучи смогли получить детали по всей поверхности модели. Ещё один вариант заключается в запекании двух карт нормалей с разными расстояниями cage и их смешивании в разных частях текстур. Некоторые пуристы создания карт нормалей могут на вас за это ругаться, так что берегите уши.
Проблема: карта нормалей имеет искажённые детали
Это очень типичная проблема. Такое происходит, когда нормали lowpoly неправильно соответствуют деталям highpoly, поэтому кажутся наклонёнными (на самом деле, если смотреть на них с направления нормалей вершин, они соответствуют идеально). Такое обычно происходит, когда некоторые грани образуют очень острый угол.
![image](https://habrastorage.org/getpro/habr/post_images/1f4/508/41f/1f450841ff63fc683594fc7cbd7418c1.jpg)
Решение: я более подробно писал об этой теме в другом туториале [перевод на Хабре], но в целом решения бывают такими:
- Сгладьте острый угол, добавив фаску (bevel).
- Преобразуйте ребро острого угла в резкое ребро (hard edge)/разделите грани на разные группы сглаживания (smoothing group).
- Используйте настраиваемые нормали (custom normals)/весовые нормали (weighted normals).
Проблема: карта нормалей выглядит пикселизированной или содержит полосы
Earthquake (AKA бог карт нормалей) написал очень хорошее объяснение этой проблемы.
Если lowpoly и highpoly очень похожи, то бОльшая часть карты нормалей будет иметь один базовый цвет карты нормалей, а другими цвета будут в местах отличия lowpoly от highpoly.
Если ситуация обратная: lowpoly и highpoly очень отличаются, то карта нормалей будет иметь гораздо большее разнообразие цветов и начнут возникать градиенты:
![image](https://habrastorage.org/getpro/habr/post_images/71f/069/01e/71f06901e389eabf5495de19c8bbf466.jpg)
Такие плавные градиенты вызывают проблемы, потому что для их представления нужно множество цветов, а самые распространённые способы сжатия текстур основаны на снижении общего количества цветов.
Решения:
- Сделайте lowpoly более похожей на highpoly: благодаря этому карте нормалей придётся делать меньше работы и она будет более похожей на первое изображение, что позволит избежать больших и плавных градиентов. Также может помочь изменение нормалей lowpoly, чтобы они лучше соответствовали highpoly.
- Используйте 16-битные карты нормалей: по умолчанию в большинстве изображений используется 8-битная глубина цвета. Это значит, что каждый канал цвета текстуры может использовать 8 разных значений (0 или 1). Для всех трёх каналов цвета это даёт нам 256 возможных цветов.
При наличии плавных градиентов мы можем замечать на модели полосы, потому что изображение не имеет достаточного количества цветов для представления такого небольшого изменения цвета.
16-битные значения могут использовать 16 различных битовых значений на каждый канал, что составляет 65536 возможных цветов. Это означает, что диапазон плавных градиентом может быть больше. Учтите, что 16-битные изображения больше по размерам, чем 8-битные (потому что содержат больше информации). Кроме того, иногда 16-битные изображения содержат альфа-канал; тогда они называются 24-битными изображениями. [Прим. пер.: тут у автора очевидная ошибка.]
Также существуют изображения с большей глубиной цвета, но для карт нормалей они не используются, потому что 16 бит более чем достаточно. - Используйте дизеринг: нехватка цветов в текстурах — это проблема, которой уже несколько десятков лет, и десятки лет назад было придумано её решение — использование дизеринга. Идея заключается в том, чтобы перемежать пиксели в текстуре, обозначая градиент и при удалении это выглядит вполне хорошо. Обычно дизеринг можно включить при экспорте текстуры.
- Убедитесь, что карта нормалей правильно сжата: при сжатии текстур компьютер берёт области близких цветов и объединяет их, создавая блоки одного цвета, снижая количество цветов в изображении. Для обычных изображений это обычно нормально, но ужасно для карт нормалей: это не только уничтожает градиенты, но и может объединить информацию каналов цвета. Для карт нормалей придуманы специальные алгоритмы сжатия. Убедитесь, что игровой движок интерпретирует изображение как карту нормалей (обычно это можно сделать, выбрав опцию ассета текстуры, пометив его как карту нормалей), и параметры сжатия будут настроены автоматически.
Проблема: на отдельных частях модели заметны пиксели
Очевидным решением будет увеличение UV-«острова» (island) этой части модели или использование более крупных текстур, но давайте рассмотрим и менее очевидные решения:
- Запекайте с удвоенным разрешением карты нормалей, а затем уменьшайте размер изображения: если вы используете текстуру 512x512, то запекайте карту нормалей с разрешением 1024x1024, а затем преобразуйте изображение в 512x512. Благодаря этому каждый пиксель окончательной текстуры будет получать информацию от четырёх пикселей, создавая своего рода «сглаживание» (antialiasing) и снижая пикселизацию. Это также справедливо и для других запечённых изображений; кроме того, стоит сохранять версии текстур высокого разрешения на случай, если позже вам захочется увеличить детали в некоторых областях.
Заметьте, на этом изображении карты нормалей имеют одинаковое разрешение, но та, которую мы запекли с разрешением 1024, выглядит более сглаженной и похожей на highpoly, потому что в процессе уменьшения она сохранила в себе дополнительную информацию. - Можно накладывать UV islands друг на друга, чтобы они использовали одинаковую информацию карты нормалей на разных частях модели. Просто переместите одну сторону модели на 1 единицу за наружу UV-пространства, чтобы программа запекания не пыталась получить детали с обеих сторон одновременно.
Можно пойти ещё дальше и использовать в некоторых деталях trim-текстуры или декали для оптимизации использования текстур. - Текстуры используют сетку пикселей, а пиксели квадратны. Если какие-то детали образуют линию, попробуйте выровнять эту линию горизонтально или вертикально. Благодаря этому выровняются сетка пикселей и детали текстуры:
Проблема: моя модель симметрична, но с разных сторон карта нормалей отличается.
При применении к модели симметрии направления нормалей могут измениться из-за того, что изменился способ соединения граней. Иногда это означает, что можно получить шов прямо по центру модели. Чтобы избежать этого, сделайте так, чтобы нормали lowpoly в самом центре были выровнены, и при необходимости настройте сглаживание.
Ещё одна возможная причина — триангуляция: при импорте моделей в игровой движок они всегда триангулируются и иногда этот процесс может изменить нормали lowpoly, а по диагоналям граней lowpoly могут появиться артефакты. Чтобы избежать этого, триангулируйте модель перед запеканием, запеките карту нормалей, а затем примените модификатор симметрии.
Кроме того, вы можете изучить небольшой туториал Earthquake, который помог мне немного больше понять нормали вершин и карты нормалей.
Дополнительную информацию о картах нормалей можно узнать из wiki сайта Polycount.