Кто создал Normal Map
В современных играх графика разнообразна: от ультра-реализма до сумасшедше стилизованных проектов. Есть много вариантов достижения того или иного результата, но какой бы путь ты ни выбрал, скорее всего, тебе придётся столкнуться с Normal Map.
Откуда возникла эта нормал мапа? Вряд ли какой-то дядька програмист сел за компьютер, по клавишам потыкал, нолики-единички написал, if/else добавил, вжух и нормал мапа. Когда я только начинал свой путь в 3D, примерно так этот процесс и представлял. Но история показывает обратное: это многолетний труд людей, увлеченных графикой. Благодаря им мы сейчас имеем магию в чистом виде. А как она появилась — давай разберёмся!
Меня зовут Ильфат, я Lead HardSurface Artist в CODA Studio. После 5 лет профессиональной работы над ассетами для игр я вдруг задался вопросом о первоначальном появлении Normal Map, и хочу рассказать, что я нашёл.
Часть 1: Идея, с которой все началось.
Начнём нашу историческую сводку с имени. James F. Blinn — американский учёный в области компьютерной графики, легенда и популяризатор, чья работа заложила основы многих современных технологий визуализации. Его главный талант — умение превращать сложные математические концепции в практические и эффективные алгоритмы. Многие научные статьи, которые я видел, опирались на его работы.
Джим Блинн создал свои первые изображения, сгенерированные компьютером, в 1968 году, будучи студентом Мичиганского университета. С 1974 по 1977 год он был аспирантом Университета Юты, где занимался исследованиями в области фотореалистичного рендеринга. Результаты этих исследований стали стандартными техниками в современных системах компьютерной анимации. К ним относятся реалистичные модели зеркального освещения specular lighting, рельефное текстурирование bump mapping и наложение карт окружения/отражения environment/reflection mapping. В 1977 году он получил докторскую степень и перешёл в Лабораторию реактивного движения (JPL), где создавал компьютерные графические анимации для различных космических миссий к Юпитеру, Сатурну и Урану. Эти анимации демонстрировались во многих новостных программах в рамках освещения миссий в прессе и стали для многих людей в индустрии первым знакомством с компьютерной анимацией. С 1987 по 2007 год он вёл постоянную колонку под названием «Уголок Джима Блинна» в журнале IEEE Computer Graphics and Applications, где описывал математические методы, используемые в компьютерной графике. Эти материалы были собраны в три книги. С 1995 по 2009 год он работал в Microsoft Research в качестве специалиста по графике (Graphics Fellow), разрабатывая новую схему математической нотации, которая значительно упрощает алгебраическое описание и манипуляцию кривыми и поверхностями. В настоящее время он на пенсии.
Как можно понять, человек умный, посвятивший свою жизнь графике. Тебе тоже его фамилия показалась знакомой? Не показалось. В любом 3D-редакторе ты мог видеть шейдер под названием Blinn, он назван в честь этого учёного.
В далёком 1978 году Блинн в своей работе «Simulation of Wrinkled Surfaces» предложил метод, который позже стал известен как «bump mapping» — карты рельефа. Блинн описал, как с помощью текстуры, хранящей значения высот, можно модифицировать векторы нормалей поверхности, не меняя её реальной геометрии. Это создавало иллюзию сложного рельефа на простой геометрии: складки, неровности и прочее.
Статья решает одну из ключевых проблем ранней компьютерной графики: чрезмерная, «пластиковая» гладкость создаваемых 3D-моделей. Даже сложные параметрические поверхности, созданные из сплайнов и кривых, выглядели искусственно, потому что в реальном мире не существует идеально гладких объектов, все имеют микронеровности: царапины, вмятины, морщины.
До Блинна существовал метод текстурирования texture mapping, предложенный Эдом Кэтмуллом. Он натягивал на 3D-модель растровое изображение текстуры, меняя её цвет. Но этот метод был плох для имитации рельефа: например, если на текстуре был нарисован шершавый бетон, поверхность всё равно оставалась геометрически гладкой, и обман раскрывался при изменении освещения.
Блинн пришёл выводу, что цвет и рельеф — разные вещи. Чтобы поверхность выглядела шероховатой, нужно изменить не её цвет, а характер отражения света. Блинн предложил гениально простой математический трюк, который стал основой всей современной техники рельефного текстурирования: не изменяй геометрию поверхности, измени вектор нормали, по которому рассчитывается освещение. В итоге свет ведёт себя так, будто поверхность шероховатая, форма не меняется, а глаз верит освещению и видит рельеф. Это и есть bump mapping по Блинну.
Математически метод Блинна изложить не смогу, но простая аналогия такая: представь гладкий пластиковый шар, на который наклеена фотография апельсиновой корки. Это текстурирование по Кэтмуллу — цвет есть, рельефа нет. Теперь представь, что ты взял тот же гладкий шар, но покрыл его тонким слоем прозрачной эпоксидной смолы с вкраплениями песчинок. Поверхность осталась гладкой на ощупь, но из-за песчинок свет отражается тысячами маленьких граней, создавая иллюзию шероховатости. Это метод Блинна.
Бамп-маппинг Блинна — это прямой предшественник и математическая основа технологии чёрно-белой текстуры бампа, а впоследствии и нормал мапы. Блинн в своей статье честно указал и на недостаток метода: нормали не влияют на силуэт объекта. Если вы посмотрите на сферу с картинки сбоку, её контур останется идеально круглым, хотя должен быть рельеф. Этот недостаток унаследовали и все последующие вариации метода, вплоть до современной Normal Map.
Метод Джеймса Блинна — это живая классика. Изложенный им принцип «обмануть освещение, изменив нормаль» — краеугольный камень рендеринга в реальном времени и по сей день. Современная Normal Map — это не что иное, как более оптимизированная, удобная и дружелюбная для художников реализация оригинальной идеи Блинна.
Часть 2: Декомпозировать чтобы улучшить.
После Джеймса Блинна многие учённые начали экспериментировать с этой технологией, но вот что зацепило меня. В то время компьютеры и приставки были слабыми, их графическое железо было ограниченным. Программируемых шейдеров в современном понимании не существовало, был фиксированный конвейер — картинки, которые отрисовывали устройства с помощью заранее заданных настроек. В то же время в оффлайн-рендеринге, например, в RenderMan от Pixar, уже вовсю использовались сложные процедурные и многослойные материалы. Благодаря этому в кино и мультиках уже использовались сложные и визуально красивые материалы для 3D-моделей. И тут на сцену выходит статья «Interactive Multi-Pass Programmable Shading» 1997 года.
Авторы задумались, как заставить слабые игровые компьютеры рисовать графику так же круто и сложно, как в кино? Так родилась идея статьи: эмулировать сложный программируемый шейдер путем разбиения его на последовательность простых проходов, каждый из которых выполняется на фиксированном конвейере.
Авторы предложили систему, которая анализирует высокоуровневый шейдер, что-то вроде RenderMan от Pixar. Система разбивает шейдер на элементарные операции и создаёт план рендеринга: последовательность, где каждый проход представляет собой один или несколько элементарных шагов. Использует кадровый буфер и текстуры как общую память для передачи данных между проходами. Результат одного прохода записывается в текстуру, которая становится входом для следующего.
Технические приёмы, которые использовали в статье:
- Текстуры — это не только цвет. В них можно хранить любые данные: направления нормалей, векторы света и другую полезную информацию.
- Сложный свет рисуется за несколько проходов. Сначала рисуется одно, например, основной свет, потом другое — блики, а затем эти проходы складываются в одну картинку.
- Смешивание через альфа-канал. С помощью готовых функций смешивания цветов можно складывать или умножать результаты разных проходов, получая нужный итог.
Можно сказать, что это совсем не про нормал мапу, но в жизни для решения одной задачи часто приходится решить несколько других.
В другой своей работе они предложили хранить компоненты вектора XYZ в цветовых каналах текстуры RGB. То есть вектор нормали для каждого пикселя хранился не в виде геометрических данных модели, а в виде текстуры normal map. Это похоже на то, как хранятся нормали в tangent space в современных normal maps. В то время это называлось perturbed normal или bump map.
Так как старые видеокарты не умели за один раз брать нормаль из текстуры и сразу считать по ней свет, процесс разбили на шаги:
- Берут готовую карту нормалей — текстуру, где вместо цвета записаны направления
- Считают, откуда идет свет на каждый пиксель, и тоже записывают это в текстуру
- Перемножают эти две текстуры с помощью функций смешивания цветов. Результат умножения и даёт правильное освещение
Когда в начале 2000-х появились программируемые шейдеры, всю цепочку из нескольких проходов удалось сжать в один быстрый шейдер.
Саму идею бамп-маппинга придумали ещё в 1978 году, но именно эта статья показала, как заставить всё это работать в реальном времени, что и привело к массовой адаптации этой идеи. Благодаря этому технология стала развиваться дальше.
Авторы доказали, что сложная графика возможна и в играх. Главный урок их работы: чтобы победить ограничения слабого железа, нужно разбивать сложную задачу на простые шаги. Этот принцип до сих пор лежит в основе всей современной игровой графики.
Часть 3: Сохранение внешнего вида при упрощении
Приближались 2000-ые, и развитие не стояло на месте. Теперь уже высокодетализированные highpoly модели состояли из миллионов полигонов, а их рендеринг был слишком медленным. Алгоритмы, которые уменьшали количество полигонов, хорошо работали с геометрией, но не учитывали потерю силуэта, что делало упрощённые объекты плоскими и невыразительными.
Тогда вышла статья «Appearance Preserving Simplification» (1998), авторы которой предложили алгоритм, который не просто уменьшал количество полигонов, но и сохранял внешний вид оригинальной модели. Они предложили разделить информацию о модели на три независимых канала:
- Положение поверхности (Surface Position) — грубая геометрия (low-poly)
- Цвет (Color) — текстурная карта (color map)
- Кривизна и детали (Normals/Curvature) — карта нормалей (normal map)
Их алгоритм включает в себя несколько важных этапов:
Метрика отклонения текстуры (Texture Deviation Metric):
Это основная часть работы. Раньше методы замеряли только отклонение новой вершины от старой. А Коэн с коллегами предложили метрику, которая следит, чтобы пиксели текстуры на экране сдвигались не больше заданного предела. Это позволяет контролировать искажение normal map на упрощённой модели и избегать визуальных ошибок.
Декуплирование атрибутов (Decoupling of Attributes):
Модель разделяют на простые составляющие:
- Геометрия (сам каркас, форма) — её можно упрощать, уменьшать количество полигонов.
- Цвет и нормали (детали: морщинки, царапины, рельеф поверхности) — их сохраняют в отдельных картинках (текстурах).
Упрощается только каркас, а все мелкие детали остаются в текстурах и никуда не пропадают. Когда модель показывают на экране, эти текстуры накладываются сверху — и простая модель выглядит так же детально, как сложная.
Фильтрация во время выполнения (Run-time Filtering):
Когда компьютер рисует модель на экране, он берёт:
- Цвет из color map
- Нормали (направления поверхности) из normal map
И смешивает их для каждого пикселя отдельно (per-pixel), а не для целого полигона сразу.
Эта идея изменила подход к упрощению 3D-моделей: главным стало визуальное качество, а не просто скорость.
Теперь можно запекать мелкие детали (царапины, выпуклости) в текстуры — особенно в normal map, — а саму геометрию делать низкополигональной. В итоге модель выглядит почти как оригинал, но требует гораздо меньше вычислений.
В своей работе авторы переносят нормали в текстурную карту.
Вектор нормали — это направление в 3D-пространстве, которое описывается координатами X, Y и Z. Чтобы сохранить его в текстуре, эти координаты нужно записать в пиксель. Текстура — это RGB-изображение, поэтому у каждого пикселя есть три канала: красный, зелёный и синий.
Авторы предложили логичное решение: сопоставить каждый канал одной из координат вектора:
- Красный (R) хранит X
- Зелёный (G) хранит Y
- Синий (B) хранит Z
Таким образом, каждый пиксель карты нормалей кодирует не цвет, а направление, в которое смотрит поверхность в этой точке. В статье 1998 года были важные отличия от того, как мы используем normal map сегодня. В современных игровых движках почти всегда используются карты нормалей tangent space. Это карты с характерным преобладающим сине-фиолетовым цветом. Они позволяют анимировать модели и накладывать текстуры на разные объекты, так как координаты нормали привязаны к поверхности модели. В статье Коэна, скорее всего, использовалось object space или какой-то похожий на него алгоритм, где нормали привязаны к глобальным координатам XYZ. Такие карты выглядят более разноцветно и радужно и негибки для повторного использования. В оригинальной статье lowpoly модель должна была создаваться специальным «ограниченным алгоритмом упрощения», который был частью их системы. Современные инструменты используют более гибкий подход, предложенный Чиньони в том же 1998 году.
Часть 4: Lowpoly и Highpoly больше на зависят друг от друга
В конце 90-х годов существовало много методов для упрощения 3D-моделей, но возникла новая потребность. При уменьшении полигонажа перенос детализации работал только внутри одного алгоритма или системы, то есть лоуполи жестко зависела от хайполи модели. Тогда авторы статьи «A general method for preserving attribute values on simplified meshes» (1998) предложили иной метод, в котором нет зависимости от конкретного алгоритма упрощения геометрии: неважно, как была получена низкополигональная модель, предложенный подход позволяет перенести на неё детали с оригинала. Highpoly и Lowpoly модели могут быть созданы независимо, а нормали запекаются путём проекции лучей с высокодетализированной модели на низкополигональную. Процесс, описанный в статье, можно разбить на несколько ключевых этапов, которые фактически описывают классический пайплайн создания нормал мап.
1. Разделение геометрии и деталей: Авторы предлагают «развязать» форму объекта и его детали. Форма хранится в виде простой низкополигональной модели, а все детали (цвет или неровности) — в текстурах
2. Создание треугольных текстурных лоскутов. Для каждой треугольной грани упрощённой lowpoly модели строится перпендикулярная ей плоскость — проекционная основа. На эту плоскость проецируется участок исходной высокополигональной модели. В результате для каждой грани получается свой небольшой треугольный участок текстуры, лоскут или иначе говоря UV Shell, содержащий всю информацию об утерянных деталях
3. Упаковка в единую карту текстуры. Самая сложная техническая часть — упаковать множество треугольных лоскутов разного размера в одну стандартную прямоугольную текстуру, максимально эффективно, чтобы не оставалось пустого места. В статье предлагают и обсуждают методы решения этой задачи
4. Семплинг — пересчёт информации. Каждый пиксель текстуры в этих лоскутах заполняется путём усреднения соответствующих значений с высокополигональной модели. Этот процесс гарантирует, что финальная карта будет точно соответствовать оригиналу
Так ещё одна проблема и ещё один метод её решения привели нас на шаг ближе к методу получения нормалки.
Именно этот подход, предложенный в 1998 году, вместе с работой Коэна «Appearance Preserving Simplification», лёг в основу всех современных инструментов для запекания нормал карт от Autodesk Maya и 3ds Max до специализированных программ вроде xNormal и Marmoset Toolbag. Метод Чиньони был особенно важен тем, что он не привязан к конкретному способу упрощения геометрии, что сделало его универсальным.
Часть 5: Normal map пришёл в игры.
Потихоньку технология развивалась, решались разные задачи и усовершенствовались методики. В Quake III Arena 1999 технология нормалки начала прокладывать себе путь. Она не была основой графики, а использовалась точечно, для создания специфических оптических эффектов.
В Q3A применялся метод, который сейчас называют Dot3 bump mapping или embm — environment mapped bump mapping. Это был более ранний и менее совершенный подход по сравнению с normal mapping. Он не мог создавать сложный рельеф произвольной формы, но был идеален для имитации неровных, шершавых, шумных и рябящих поверхностей.
В Q3A эффект был специфичным. Его основное применение — создание иллюзии детализации на поверхностях. Но в 2004 году в Doom 3 карты нормалей создавали уже более объёмные кирпичи, шрамы на коже монстров или выбоины в металле.
К моменту работы над Doom 3 Кармак — американский разработчик компьютерных игр, соучредитель и совладелец компаний id Software — принял решение, которое сейчас кажется очевидным, но тогда было революционным: практически вся геометрическая детализация поверхности должна быть представлена в картах нормалей, а не нарисована в диффузных текстурах. Это позволило одной и той же текстуре по-разному взаимодействовать со светом, создавая невиданный ранее реализм.
Кармак документально зафиксировал принцип кодирования нормалей в цвете. Вектор нормали XYZ преобразовывался в цвета RGB. Так как нормали в основном направлены от поверхности, в касательном пространстве это ось Z, большинство карт нормалей имеют характерный синеватый оттенок RGB: 127 127 255. Если вектор смотрит строго вверх, он кодируется как тот самый классический синий цвет.
id Software не использовала сторонние плагины для 3ds Max или Maya. Кармак интегрировал инструмент генерации карт нормалей прямо в движок Doom 3, назвав его Renderbump. Это было гениальное инженерное решение. Художник создавал две модели: Highpoly — сотни тысяч полигонов — со всеми мельчайшими деталями, в ZBrush или Maya; Lowpoly — например, 2000 треугольников — модель для игры.
Затем запускался Renderbump, который проецировал геометрию высокодетализированной модели на низкополигональную и запекал всю информацию о рельефе в сине-фиолетовую карту нормалей.
В Doom 3 сформировалась чёткая система, где каждая текстура отвечала за свой аспект внешнего вида объекта. Это была элегантная замена громоздким шейдерам: Normal map хранит информацию о рельефе; Diffuse map отвечает за цвет поверхности; Specular map определяет, какие участки блестят (металл), а какие нет (кожа, резина).
Работа Кармака стала весомым моментом в развитии normal map. Он не просто внедрил технологию, а написал подробную документацию для моделлеров и разработчиков, объясняя, что такое карты нормалей, чем они лучше карт высот и как их использовать в материалах игры. Это был акт передачи знаний. До Doom 3 normal map был экспериментальной технологией. Кармак доказал, что на массовом железе можно в реальном времени обсчитывать динамический свет для каждого пикселя, используя карты нормалей, и получать картинку, недостижимую для чистых полигонов. После выхода Doom 3 и Half-Life 2, который использовал схожие принципы, наличие карт нормалей стало стандартом для любой AAA-игры. Разработчики из Valve прямо указывали на Doom 3 и Far Cry как на причины, по которым их игры выглядят настолько лучше предшественников.
Так normal map прошла путь от просто шумных поверхностей в Q3A до полноценного использования на всех уровнях детализации в Doom 3. Эти 5 лет стали для данной технологии решающими, а подход Кармака «найти технологию, довести её до совершенства с инженерной точки зрения, сделать её практичной и подарить индустрии новое дыхание» — великолепие!
Однозначно понятно одно: к той технологии нормал мап, которую мы с тобой используем в разработке, приложили руки огромное количество разных специалистов и энтузиастов, сообща, передавая знания из десятилетия в десятилетие. Я уверен, что тут не рассказано ещё о многих специалистах, но те статьи, что я предоставил, стали основой и базой, заложившей начало великой технологии, идею которой когда-то сформулировал J.F.Blinn.
Если хочешь больше контента по 3D, приходи к нам в тг.
Литература:
The Bumpy Road to Blinn Shading (James Blinn)
www.jimblinn.com
Simulation of wrinkled surfaces
Interactive Multi-Pass Programmable Shading
Jonathan Cohen, Marc Olano, Dinesh Manocha — «Appearance Preserving Simplification» (1998)
Paolo Cignoni, Claudio Montani, Claudio Rocchini, Roberto Scopigno — «A general method for preserving attribute values on simplified meshes» (1998)
Making DOOM 3 Mods : Bump Maps