Карты высот и параллакс
Из этой статьи вы узнаете о картах высот (height maps), также называемых картами параллакса (parallax maps).
Что такое карта высот?
Как обычно, когда я говорю «карта», то имеют в виду текстуру, содержащую информацию о внешнем виде 3D-объекта. Карта высот/параллакса — это карта, которую можно использовать для того, чтобы создать иллюзию того, что одни части объекта выступают сильнее, чем другие, то есть имеют бОльшую высоту.
По описанию это может показаться очень похожим на карту нормалей (normal map), благодаря которой 3D-объект кажется более рельефным, но действует она немного иначе. Карта нормалей использует освещение, чтобы объект казался более рельефным, чем на самом деле. Карта высот использует параллакс, чтобы сделать объект выше, чем на самом деле.
Параллакс
Замечали ли вы в детстве, что когда идёшь вечером, луна идёт за тобой? Объекты, мимо которых мы проходим — или движемся параллельно им, приближаются и удаляются, но луна всегда занимает в небе одно и то же место. Если вы, как и я, выросли рядом с горами, то могли также замечать, что они тоже не очень быстро двигаются, однако если уехать достаточно далеко, они всё-таки останутся позади. Чем дальше от нас предметы, тем медленнее они «движутся» при изменении угла взгляда на них (например, когда проезжаешь их на машине) и чем ближе объекты, тем быстрее они смещаются при смене вашей позиции и угла взгляда.
В таких двухмерных играх-сайдскроллерах, как Mario или Rayman, создатели использовали этот эффект. Они создали несколько слоёв фона, прокручивающихся с разной скоростью в зависимости от того, насколько близкими они должны казаться. Это просто иллюзия — разумеется, все спрайты плоские, но она придаёт сцене ощущение глубины!
Однако в 3D-графике мы тоже можем использовать это явление. Но вместо прокрутки здесь можно комкать или растягивать координаты текстур в зависимости от направления обзора, чтобы обмануть глаз и увидеть глубину! Именно этим данный эффект отличается от карты нормалей. Карта нормалей оставляет неизменными координаты текстур, но изменяет сторону, в которую по нашим ощущениям направлен объект. Карта высот сохраняет направление, но меняет координаты текстур, которые мы используем для всех остальных карт.
Если посмотреть на них по отдельности, то различия очевидны. Вы можете воссоздать изображения из статьи в собственном проекте, или просто читать её.
Если вы хотите создать собственный проект, то перейдите по адресу www.textures.com/download/pbr0419/137925 и скачайте файлы в папку своего проекта, например, в Assets/Textures/Acoustic Foam. (Не волнуйтесь, текстуры бесплатны!) Затем создайте материал и установите этот шахматный паттерн в слот основной текстуры, а потом задайте материал плоскости. У материала оставьте шейдер Standard shader.
Материал плоскости имеет только этот шахматный паттерн в качестве основной текстуры albedo и больше никаких других карт.
Здесь использован шахматный паттерн как основная текстура albedo и карта нормалей в виде акустического поролона (acoustic foam). Заметьте, что шахматный паттерн по-прежнему идеально ровный.
Здесь шахматный паттерн используется как основная текстура albedo, а acoustic foam — как карта высот.
Если приглядеться, то можно увидеть, что эффект неравномерный! Так получилось, потому что направление обзора этих двух частей неодинаково.
Эффект довольно интересен, но лучше всего он работает, если вы смотрите на плоскость почти перпендикулярно, и разваливается при взгляде на плоскость сбоку.
Итак, всё это очень здорово, но иллюзия может добиться только этого. Похоже, что лучше всего её использовать в небольших дозах на тех объектах, на которые игрок не сможет смотреть под такими углами.
А вот плоскость с шахматным паттерном в качестве текстуры albedo, картой нормалей acoustic foam и картой высот acoustic foam. Они отлично сочетаются! Ну ладно, хватит болтовни, давайте уже напишем шейдер, выполняющий эту задачу!
Подготовка
Откройте сцену в Unity. Добавьте плоскость, нажав правой клавишей мыши внутри иерархии и выбрав 3D Object > Plane.
Установите transform плоскости в 0, 0, 0 и оставьте на ней материал по умолчанию, она нужна будет, чтобы дать нам представление о масштабе. Добавьте таким же образом ещё одну или две фигуры. Я буду использовать сферу и куб. Расположите их, где угодно, на плоскости или над ней. Скачайте эти бесплатные текстуры в свой проект: https://www.textures.com/download/pbr0579/138828 (или используйте любой другой набор текстур с картами высот!), например в Assets/Textures/CrystalOre. В той же папке или в подпапке папки Materials создайте новый материал под названием Crystal Ore. Примените новый материал к двум фигурам. Нажмите правой клавишей мыши в Assets/Shaders/Standard и выберите Create > Shaders > Standard Surface Shader
Назовите новый файл шейдера BasicParallax, затем дважды щёлкните по нему, чтобы открыть его в Visual Studio. Измените первую строку на Shader «Xibanya/Standard/BasicParallax», затем сохраните его и вернитесь в Unity.
Назначьте шейдер BasicParallax материалу Crystal Ore. Теперь можно перетащить в слот текстуры карту albedo.
Создаём шейдер
Мы уже говорили о том, как использовать карту нормалей, metallic map и так далее, поэтому я буду предполагать, что вы уже знаете, как это делается. (Если нет, то прочитайте информацию по ссылкам и возвращайтесь!).
Перейдите к созданному мной базовому шейдеру, нажмите на кнопку Raw, скопируйте и вставьте шейдер в BasicParallax (но перед сохранением обязательно измените название сверху на Xibanya/Standard/BasicParallax!). Теперь можно перетащить карту нормалей и карту AO.
Я создала этот минималистичный шейдер для записи всех свойств, используемых стандартной моделью освещения (Standard lighting model), и больше в нём ничего нет, поэтому требуется дополнительная настройка, чтобы шейдер мог использовать roughness map. Добавьте эту строку в свойства (например, над gloss map)
Добавьте это под surface pragma
Затем измените часть, после которой распаковывается glossmap, на это:
(Если вы незнакомы с roughness map или ключевыми словами, то о них можно прочитать здесь!) Завершив с этим, сохранитесь и возвращайтесь в Unity. Теперь перетащите roughness map и переключите флаг Roughness на true.
Отлично! Наконец мы подготовили основу, настало время приступать к параллаксу!
Создание шейдера параллакса
Наверху, в разделе свойств добавьте следующие пять строк:
Мы сделаем параллакс функцией, которая активируется/отключается ключевым словом _PARALLAXMAP. Для правильно применения карты параллакса нам нужно использовать касательное направление обзора. Если мы пишем поверхностный шейдер, то если ключевое слово задано (то есть мы его включили), это будет направление обзора, получаемое от структуры Input. Если ключевое слово _PARALLAXMAP не задано, мы всё равно будем получать касательное направление обзора, если выполняем запись в o.Normal. Однако возможно, что мы не всегда будем это делать, поэтому об этом легко забыть и запутаться, поэтому лучше привыкнуть использовать его каждый раз, когда нам нужно распаковать карту параллакса! В pragma ключевого слова Roughness добавим следующую строку:
и добавим в структуру Input float3 viewDir.
Наконец, объявим в подшейдере текстуру карты параллакса и свойства силы параллакса.
Сохраним код и вернёмся в Unity, чтобы убедиться, что не сделали никаких опечаток или ошибок. Если всё правильно, то теперь мы можем перетащить текстуру CrystalOre_1k_height в слот карты параллакса материала. Не забудьте там же включить параллакс.
Разумеется, это пока ни к чему не приведёт, ведь мы не внесли никаких изменений в функцию поверхности! Мы используем карту параллакса для определения того, как сжимать или растягивать координаты текстуры, поэтому нам нужно обрабатывать всё связанное с параллаксом перед всем остальным. Добавим следующее в самое начало функции поверхности:
Мы распакуем текстуру и возьмём зелёный канал (большинство карт высот чёрно-белые, из-за чего все каналы одинаковы, поэтому нам достаточно использовать один), а затем передадим его, силу параллакса и касательное направление обзора (удобно вычисленное за нас магией поверхностного шейдера Unity) во встроенную функцию под названием ParallaxOffset. ParallaxOffset — это величина, определяющая сжатие или растягивание UV-координат в зависимости от направления обзора. Её можно найти в библиотеке UnityCG.cginc, включаемой в каждый поверхностный шейдер. ParallaxOffset возвращает значение float2, которое мы затем можем прибавить к координатам текстуры IN.uv_MainTex (которые также являются float2!), чтобы каждая распаковываемая после этого текстура распаковывалась со смещением. Если вам любопытно, то это выглядит так, но вам необязательно знать, как это работает, чтобы добавить параллакс к своим поверхностным шейдерам!
(не добавляйте это в свой шейдер, этот код уже встроен!) И наша работа здесь на этом закончена! Сохранитесь и вернитесь в Unity. Поиграйтесь с ползунком Parallax Strength, чтобы увидеть эффект в действии.
В свойствах я при помощи ползунка с интервалом ограничил силу параллакса в пределах от 0 до 0.1, потому что при значениях выше 0.1 всё начинает выглядеть довольно безумно даже при самых идеальных углах обзора, но вы можете изменить свойство с интервала на float, чтобы поэкспериментировать с различной силой параллакса.
Точный учет микрорельефа при помощи parallax и relief mapping’а
Характерной чертой развития 3D-графики является все возрастающая степень детализации объектов. Первым шагом в такой детализации было применение bumpmapping-а (впервые предложенное Блинном).
Сейчас это стало повсеместно распространенным использовать bumpmapping, т.е. попиксельное задание вектора нормали, для моделирования неровностей поверхности (ее микрорельефа). За счет этого удается не усложняя геометрию объектов создать иллюзию микрорельфа, т.е. высокой степени детализации.
Рис 1. Пример использования bumpmapping-а.
Однако bumpmapping дает четко видимые результаты либо для освещения небольшим количеством точечных источников света (при этом желательно чтобы поверхности имели сильно выраженную бликовую компоненту как в DooM 3), либо при отражении (EMBM).
В данной статье мы рассмотрим моделирование подобных явлений начиная с самых простых и заканчивая наиболее продвинутыми методами.
Проще всего задавать микрорельеф поверхности при помощи так называемой карты высот (height map) h(s,t). При этом возможны два варианта трактовки этой карты. Значения из нее могут рассматриваться либо как высота точки над гранью (рис 2а), либо как углубление внутрь грани (рис 2b). Мы далее будем придерживаться первой интерпретации.
Рис 2. Возможные интерпретации карты высот.
Parallax Mapping
Когда неровная поверхность (задаваемая картой высот h(s,t)) рассматривается с направления v, то если мы не учитываем микрорельефа поверхности, в качестве точки на ней будет взята точка А (точнее, соответствующие этой точке текстурные координаты). Однако точному пересечению луча от наблюдателя соответствует точка В (и соответствующая ей точка T * в текстурных координатах).
Рис. 3. Приближенное вычисление точки на поверхности.
Можно использовать значение высоты в точке А для получения более точного значения текстурных координат (T1):
Коррекцию текстурных координат по приведенной формуле можно довольно легко реализовать при помощи простых вершинных и фрагментных шейдеров.
Steep Parallex Mapping
Рис 6. Нахождение пересечения путем перебора слоев.
В этом случае сначала проверяется точка A0, затем A1, затем A2 и так далее до тех пор, пока очередная точка не окажется ниже соответствующего значения высоты (для рис. 6 такой точкой является A3). Фактически осуществляется трассировка объема, разбитого на слои одинаковой толщины.
Однако поскольку не для всех графических ускорителей поддерживается цикл while во фрагментном шейдере, ниже приводится вариант шейдера для для конкретного числа слоев данный цикл развернут в цепочку условных операторов.
Рис 7. Изображение, получаемое при помои перебора набора слоев.
На следующем рисунке приводится изображение, построенное при помощи этого подхода. Однако использование небольшого числа проверяемых слоев может давать заметные погрешности, хорошо заметные на рисунке.
Рис 8. Артефакты, возникающие при переборе слоев.
Эта погрешность свзяана с тем, что проверка на пересечение луча проводится высего лишь в небольшом числе слоев, соответствующих дискретному набору высот. В ислу этого при резких изменениях высоты и/или при направлении взгляда, близкому к касательному, подобная «слоистость» поверхности становится явно видимой.
Также на форуме gamedev.ru предлагалось использовать вместо линейной интерполяции экспоненциальную.
Relief Mapping
Кроме того для устранения этих погрешностей можно использовать найденную путем перебора слоев точку как начальное приближения и произвести уточнение точки пересечения при помощи метода половинного деления.
Рис 9. Уточнение точки при помощи метода половинного деления.
Так для случая с рис. 8 точное значение пересечения лежит между точками A* и A1, поэтому в качестве начального приближения можно взять точку B1=(A1+A*)/2. Если эта точка лежит выше поверхности, задаваемой картой высоты, то корень находится на отрезке [B1, A*], в противном случае корень находится на [A1,B1].
Далее на получившемся отрезке вновь выбираем середину и сравниваем значение в ней со значением высоты. Это сравнение определяет какую половину отрезка следует оставить (т.к. она содержит корень).
Так проводится несколько итераций уточнения корня, при этом на каждой итерации точность удваивается (поскольку длина отрезка, содержащего корень сокращается в два раза на каждой итерации). После проведения фиксированного числа итераций середина последнего отрезка берется в качестве корня. Этот подход получил название relief mapping. Ниже приводится соответствующая фрагментная программа.
В качестве иллюстрации к этому подходу возьмем текстуру из NVSDK, задающую одновременно и карту нормалей (в RGB части) и карту высот (в альфа-канале). Далее построим изображение куба, на каждую сторону которого накладывается текстура камня и карта нормалей(высот). При построении изображения будет не только использовать relief mapping, но и проводить попиксельное вычисление диффузной и бликовой освещенности.
На следующих двух изображениях приведены изображения куба с использованием relief mapping и без него (только попиксельное вычисление освещенности).
Обратите внимание на то, что наложение текстуры на поверхность отличается от обычного bumpmapping‘а.
Рис. 10. Попиксельное освещение с использованием relief mapping-а
Рис. 11. Попиксельное освещение без использования relief mapping-а
Путем небольшой модификации шейдера можно использовать relief mapping не только для определения точной точки на поверхности, но также и для проверки ее затененности (закрывания микрорельефом от источника света).
Для этого поиск пересечения луча с поверхностью начинается от найденной точки пересечения и ведется в направлении вектора на источник света. Перебор слоев в этом случае осуществляется в обратном направлении (т.е. соответствующем увеличению высоты).
Parallax Occlusion Mapping
Существует еще один вариант развития steep parallax mapping‘а, получивший название parallax occlusion mapping.
Рис 12. Линейное приближение.
Тогда для приближенного нахождения точки пересечения мы можем просто найти точку пересечения из этого допущения вообще не прибегая к бинарному поиску (и вообще больше не обращаясь к текстуре). Данный способ оказывается не только более быстрым, но и дающим лучшие изображения.
Ниже приводится фрагментный шейдер, реализующий данный подход.
На следующих скриншотах приводятся результаты применения данного подхода. Обратите внимание на то, как чтеко виден рельеф поверхности.
Использование карты расстояний до поверхности
Существует еще один интересный способ для определения видимой точки с учетом карты высот. Он описан в главе 8 книги GPU Gems 2 (данная глава может быть скачана с сайта компании NVIDIA).
Данный способ также является итерационным способом нахождения пересечения луча от наблюдателя с поверхностью объекта. Однако для нахождения величины очередного шага он использует вспомогательную трехмерную текстуру.
Эта текстура строится по карте высот, где в качестве третьего измерения выступает высота. При этом значением каждого тексела является ближайшее расстояние до поверхности, задаваемой картой высот (см рис. 15).
Рис 14. Функция расстояния до поверхности.
Рис 15. Вспомогательная трехмерная текстура.
Этот подход также, как и предыдущий, осуществляет трассировку объема, однако в качестве величины очередного шага вдоль луча в направлении поверхности используется значение из этой вспомогательной текстуры.
Поскольку оно является ближайшим расстоянием до поверхности, то делая шаг этой длины, мы гарантированно не пересечем поверхность (что может произойти с ранее рассмотренным методом).
Рис 16. Последовательное приближение к точному решению.
Таким образом выполнение ряда шагов вдоль луча подобным образом дает нам приближенное значение точки пересечения луча с поверхностью. Чем больше шагов будет выполнено, тем выше будет точность.
Однако важным моментом является правильное согласование размеров вспомогательной текстуры со значениями внутри нее.
К сожалению данным метод требует специальным образом созданной 3D-текстуры и целого ряда зависимых (dependent) чтений из текстуры, что весьма отрицательно сказывается на быстродействии.
Cone Step Mapping, Relaxed Cone Step Mapping
Рис 17. Конусы на поверхности.
Тогда в силу построения такого конуся внутри него не может быть точек поверхности и можно не проверять нет ли пересечений луча с поверхностью внутри конуса, а сразу перейти к пересечению с границей конуса.
Поэтому для трассировки луча можно в начальной точке взять конус и найти пересечение луча с конусом, в точке пересечения луча с конусом берем новый конус и ищем пересечение луча с ним и та далее. В результате мы поулчаем последовательность точек, гарантированно сходящихся к точному пересечению луча с поверхностью.
Рис 18. Построение приближений к точке пересечения.
При этом как и ранее строится итерационная последовательность, но для каждой точки пересечения луча и конуса, проверяется не находится ли полученная точка под поверхностью. Если это так, то значит отрезок между полученной точкой последовательности и предыдущей содержит ровно одно пересечение, которое легко может быть поулчено либо при помощи половинного деления, либо через линейную интерполяцию.
Рис 20. Нахождение пересечения.
Таким образом полседний вариант (relaxed cone step mapping) отличается более высокой скоростью сходимости и, как и метод с функций расстояния, гарантирует, что даже мелкие детали не будут пропущены (что может иметь место при проверке отдельных слоев). Следующий рисунок иллюстрирует каким образом находится пересечение луча и конуса.
Рис 21. Нахождение пересечения луча и конуса.
Таким образом, для применения данного метода необходимо заранее по карте высот построить двухмерную тектсуру, содержащую тангенсы половинных углов разворота конусов. Следующий фрагмент псевдокода иллюстрирует алгоритм, который может быть использован для построения такой текстуры.
По этой ссылке можно скачать весь исходный код к этой статье. Также доступны для скачивания откомпилированные версии для M$ Windows, Linux и Mac OS X.
Русские Блоги
Параллакс карта
1. Параллакс Картография
1.1 Введение в теорию карт параллакса
Parallax Mapping использует технику, аналогичную нормальной картине, но основанную на других принципах. Как и карты нормалей, карты параллакса могут значительно улучшить детализацию поверхности и придать ей ощущение глубины. При использовании оптического обмана карта параллакса имеет лучшее выражение глубины и может давать невероятные эффекты при использовании с картами нормалей.
Карта параллакса принадлежитОтображение смещения Этакая технология.
Отображение смещения (Displacement Mapping) основано на геометрической информации, хранящейся в текстуре для смещения или смещения вершин. Одним из способов достижения этого является использование плоскости с примерно 1000 вершинами и смещение каждой вершины в соответствии со значением в текстуре (которое является значением высоты).Эта карта текстуры, где каждый тексель является значением высоты, называется картой высоты, Карта высот простой кирпичной поверхности выглядит следующим образом:
Каждая вершина на всей плоскости смещается в соответствии со значением высоты, выбранным из карты высот, и в соответствии с геометрическими свойствами материала плоская плоскость преобразуется в неровную поверхность. Например, плоская плоскость может быть преобразована с использованием приведенной выше карты высот для получения следующих результатов:
Одна проблема с вершинами смещения состоит в том, что плоскость должна состоять из множества вершин, чтобы получить реалистичный эффект, иначе эффект будет выглядеть не очень хорошо. Вычисление 1000 вершин на плоской поверхности слишком велико. Можем ли мы достичь аналогичных результатов без такого количества вершин? Фактически, верхняя поверхность представлена шестью вершинами (двумя треугольниками). Поверхность выше визуализируется с использованием технологии картирования параллакса, которая не требует дополнительных данных о вершинах для выражения глубины, а использует хитрый метод, такой как нормальное картирование, чтобы обмануть глаза пользователя.
Принцип и код реализации карты нормалей подробно описаны в примечании [Карта нормалей], где мы в основном обсуждаем проблемы карты нормалей. Карта нормалей предназначена не для увеличения числа граней модели, а для использования нормалей на карте нормалей для расчета освещения посредством ложного эффекта затенения, позволяющего наблюдателю ошибочно думать, что у модели есть неровности. Карта нормалей может сделать ложным только на светлом и темном эффекте (имитировать неровности), не может контролировать степень неровности на поверхности. Даже если мы используем программное обеспечение для обработки изображений, чтобы вызвать карту нормалей с очень очевидными выпуклостями, через тщательное наблюдение, нормальный эффект будет проблематичным.
Выше земля с картами нормалей, есть проблема в красном круге. Мы используем план для анализа.
Идея технологии Parallax Mapping (Parallax Mapping) состоит в том, чтобы изменить координаты текстуры так, чтобы поверхность фрагмента выглядела выше или ниже фактической, причем все они отображаются в соответствии с направлением и высотой просмотра. Чтобы понять, как это работает, посмотрите на изображение кирпичной поверхности ниже:
Грубая красная линия здесь представляет трехмерное представление значений в карте высоты, вектор V → » role=»presentation»> V → Представляет направление просмотра. Если плоскость фактически смещена, наблюдатель увидит поверхность в точке B. Однако наша плоскость фактически не смещена, и направление наблюдения будет соприкасаться с плоскостью в точке А. Цель карты параллакса состоит в том, что фрагмент в позиции A больше не использует текстурные координаты точки A, а текстурные координаты точки B. Затем мы используем текстурные координаты точки B для выборки, и наблюдатель выглядит как точка B.
Этот метод описывает, как получить координаты текстуры в точке B из точки A. Карта параллакса пытается передать вектор направления от фрагмента к наблюдателю V → » role=»presentation»> V → Задача решается путем масштабирования. Размером масштабирования является высота фрагмента в точке A. Так мы будем V → » role=»presentation»> V → Длина масштабируется до карты высот в точке A H ( A ) » role=»presentation»> H ( A ) Выборочное значение. На следующем рисунке показан масштабированный вектор P → » role=»presentation»> P → :
Затем мы выбираем P → » role=»presentation»> P → И координаты этого вектора, выровненные по плоскости, используются как смещение координат текстуры. Этот метод осуществим, потому что вектор P → » role=»presentation»> P → Он рассчитывается с использованием значения высоты, полученного из карты высот, поэтому чем выше высота фрагмента, тем больше величина смещения.
вектор V → » role=»presentation»> V → Преобразовать в касательное пространство, преобразованный вектор P → » role=»presentation»> P → Средние элементы x и y будут выровнены с касательными и двойными касательными векторами поверхности. Поскольку касательные и двойные касательные векторы находятся в том же направлении, что и координаты текстуры поверхности, мы можем использовать P → » role=»presentation»> P → Элементы x и y используются в качестве смещения координат текстуры, поэтому вам не нужно учитывать направление поверхности.
Была представлена теория отображения параллакса, которая является частью реализации кода в параллаксном отображении.
1.2 Реализация кода карты параллакса
Как и в учебнике по нормальному отображению, перед тем, как выбросить модель в графический процессор для рендеринга, мы сначала вычисляем касательные и касательные векторы вершин модели. В этом примере вам нужно использовать диффузные текстуры, карты нормалей и карты смещения, где вам нужно использовать карты нормалей и карты параллакса вместе. Поскольку карта параллакса создает иллюзию путем смещения поверхности, а когда освещение не соответствует ей, иллюзия больше не существует. А поскольку карты нормалей обычно создаются на основе карт высот, одновременное использование карт нормалей и карт параллакса может обеспечить совпадение энергии освещения и смещения. (Несовпадение здесь относится к тому, что, если при расчете освещения все еще используются исходные текстурные координаты фрагмента для выборки карты нормалей, результат расчета освещения не соответствует диффузному цвету. Это необходимо хорошо понять здесь. Используйте координаты текстуры после смещения, чтобы освещение могло соответствовать диффузному цвету.)
Карты параллакса реализованы в фрагментных шейдерах, потому что все эффекты смещения треугольной поверхности различны. В шейдерном фрагменте нам нужно рассчитать вектор направления от фрагмента к наблюдателю V → » role=»presentation»> V → Итак, нам нужны позиция фрагмента и позиция наблюдателя в касательном пространстве. Код для вершинного шейдера такой же, как и для вершинного шейдера, используемого в карте нормалей.
Код вершинного шейдера выглядит следующим образом:
Для карты параллакса нам нужно изменить положение вершины position И положение наблюдателя в касательном пространстве viewPos Отправьте фрагмент шейдера.
Мы реализуем логику отображения параллакса во фрагментном шейдере. Код фрагментного шейдера выглядит следующим образом:
Определены функция ParallaxMapping (), текстурные координаты фрагмента и вектор наблюдения в касательном пространстве V → » role=»presentation»> V → В качестве ввода. Эта функция возвращает координаты текстуры после смещения. Затем мы используем эти смещенные текстурные координаты для выборки диффузной карты и карты нормалей. Наконец, диффузный цвет и вектор нормали фрагмента правильно соответствуют положению после смещения поверхности (Это может гарантировать, что результат расчета освещения является правильным, потому что для расчета освещения также используется вектор нормали после смещения)。
Ниже приведена часть реализации функции ParallaxMapping ():
Мы знаем вектор viewDir Является ли единичный вектор, то viewDir.z Между диапазонами [0,1]. Когда вектор viewDir Когда он почти параллелен поверхности, то есть параллельно поверхности, чтобы наблюдать поверхность, viewDir.z Близко к 0 и делает viewDir.x / viewDir.z Значение viewDir Он намного больше, когда он перпендикулярен плоскости, что делает вектор viewDir Когда почти параллельно поверхности, рассчитанный вектор смещения p Он также очень большой, так что текущий фрагмент будет использовать более отдаленные координаты текстуры, когда вектор viewDir Расчетный вектор смещения при перпендикулярности поверхности p Он очень маленький, и текущий фрагмент использует близлежащие текстурные координаты. Конечно, вышеупомянутое обсуждается со значением высоты без изменений.
Есть также некоторые люди, которые не используют в приведенном выше уравнении viewDir.z Потому что обычные карты параллакса дают нежелательные результаты на углах, и этот метод также называетсяОтображение параллакса с ограничением смещения, Выбор техники зависит от личных предпочтений, здесь используется общая карта параллакса.
Понимание сформировано: карта параллакса основана на координатах текстуры, используемых текущим фрагментом ++, в соответствии с направлением вектора наблюдения и значением, выбранным картой глубины ++ для создания некоторого смещения, направление смещения является направлением вектора наблюдения, поэтому приведенное выше вектор p Делаются исходя из направления наблюдаемого вектора, вектора p Размер определяется значением образца карты глубины.
В сочетании с приведенным выше рисунком, когда направление наблюдения совпадает с направлением зеленой линии e, для обсуждения белая линия, где расположена синяя точка, представляет собой серую плоскость над нами (плоскость, в которой расположен элемент). При наблюдении синей точки точка Когда значение глубины мало, для этой точки будут использоваться координаты текстуры немного левее, а при наблюдении синей точки слева значение глубины среза будет все больше и больше, поэтому срезы будут использовать все дальше и дальше. Координаты текстуры, соответствующие координаты текстуры на красной линии не будут использованы полностью, что согласуется с фактическим явлением наблюдения, то есть текстуру на спине трудно наблюдать или даже наблюдать. Это должно быть причиной того, что карты параллакса имеют большее чувство глубины, чем карты нормалей!
Окончательные координаты текстуры будут использоваться для выборки диффузной карты и карты нормалей, установите значение height_scale равным 0,1, и полученное изображение эффекта будет показано ниже:
Здесь вы увидите разницу между отображением только нормалей и отображением нормалей в сочетании с отображением параллакса. Поскольку карты параллакса пытаются имитировать глубину, на самом деле они могут накладывать кирпичи поверх других кирпичей в зависимости от направления, в котором вы на них смотрите.
На карте параллакса вы увидите странные искажения по краям. Причина в том, что если выборка выполняется на краю плоскости, координаты текстуры после смещения могут превышать диапазон [0,1] в соответствии с методом наложения текстуры, что приводит к нереалистичным результатам. Решение состоит в том, чтобы отбросить фрагмент, когда он производит выборку за пределами диапазона координат текстуры по умолчанию:
Все фрагменты с текстурными координатами за пределами диапазона по умолчанию отбрасываются, и край поверхности карты параллакса дает правильный результат.Обратите внимание, что это решение не подходит для всех типов поверхностей, только когда ситуация обработки является плоской, это решение может показать хорошие результаты, другие поверхности могут быть немного менее эффективнымиНа следующем рисунке показан окончательный результат отображения:
1.3 Пример кода
1.4 Проблемы
Применение технологии картирования параллакса выглядит хорошо и работает быстро, потому что только использование дополнительной карты текстуры (карты глубины) может заставить карту параллакса работать должным образом. Но будут некоторые проблемы: при взгляде под косым углом крутые места будут давать неверные результаты, как показано на следующем рисунке:
Причина вышеупомянутой проблемы состоит в том, что это только грубое приближение карты смещений, то есть на приведенной выше схематической диаграмме точка P используется для аппроксимации точки B. Использование некоторых дополнительных приемов позволяет получить идеальные и правильные результаты даже при резких изменениях высоты. Например, вместо использования одной выборки, но с использованием нескольких выборок, чтобы найти ближайшую точку B, каков будет результат?
2. Рельефное картирование
2.1 Принцип рельефной карты
Рельефное картирование (Relief Mapping), также известное как Steep Parallax Mapping, Крутое параллаксное картирование (Steep Parallax Mapping) является расширением параллаксного картирования, все они используют один и тот же принцип, но вместо использования одиночной выборки, Steep Parallax Mapping выбирает несколько семплов, так что точка P достигает точки B. Даже при резком изменении высоты эта технология отображения может дать хороший эффект отображения, поскольку увеличение количества выборок может повысить точность отображения (Точность здесь должна означать, что точка P ближе к точке B)。
Объяснение принципа: проследите каждый слой сверху вниз, и для каждого слоя сравните значение глубины слоя со значением глубины, взятым из карты глубины. Если значение глубины текущего слоя меньше значения глубины, выбранного из карты глубины, текущий слой и вектор P → » role=»presentation»> P → Пересечение (Фиолетовая точка на картинке выше) Не под поверхностью модели продолжайте переход к следующему слою и повторяйте вышеуказанную операцию, пока значение глубины текущего слоя не станет больше значения глубины, выбранного из карты глубины (в этом случае точка пересечения находится ниже поверхности модели) Прекрати обходить
В приведенном выше примере мы видим, что значение глубины карты глубины второго слоя (D (2) = 0,73) все еще ниже, чем значение глубины второго слоя 0,4, поэтому мы продолжим. На следующей итерации значение глубины этого слоя на 0,6 больше значения глубины, взятого из карты глубины (D (3) = 0,37). Можно предположить вектор третьего слоя P → » role=»presentation»> P → Это возможно. Можно использовать смещение координат текстуры T 3 » role=»presentation»> T 3 Для смещения или смещения исходных текстурных координат фрагмента. Видно, что с увеличением количества слоев увеличивается и точность.
2.2 Реализация кода карты рельефа
Чтобы реализовать карту рельефа (также называемую крутой картой параллакса), вам нужно всего лишь внести некоторые изменения на основе карты параллакса, поскольку все переменные, которые вам нужно использовать, уже предоставлены. В реализации карты рельефа необходимо изменить только функцию ParallaxMapping (). Чтобы отличить ее от кода карты параллакса, здесь переопределена новая функция escapeMapping (), которая не влияет на понимание:
Код реализации функциирепортажа () выглядит следующим образом:
В вышеприведенной реализации определяется количество слоев, высота (или глубина) каждого слоя и смещение координат текстуры по мере продвижения каждого слоя.
Затем пройдитесь по всем слоям сверху вниз, пока значение глубины, полученное путем выборки карты глубины, не станет меньше значения глубины слоя, и обход не закончится. Ниже приведен оставшийся код реализации функции escapeMapping ():
Этот многоуровневый метод реализации более точен, чем предыдущая карта параллакса. (Это означает, что приближенная точка P ближе к фактической наблюдаемой точке B.) Отображаемое изображение эффекта выглядит следующим образом:
2.3 Пример кода
2.4 Проблемы
Крутые карты параллакса также имеют свои проблемы. Поскольку крутая карта параллакса основана на ограниченном количестве выборок, вы столкнетесь с зубчатыми эффектами и очевидными ошибками между слоями:
Вышеупомянутые проблемы могут быть уменьшены путем увеличения количества выборок, но это приведет к значительному снижению производительности. В настоящее время существует несколько способов решения этих проблем, один из которых: не использовать первое пересечение под поверхностью (Относится к случаю, когда значение глубины этого слоя больше, чем значение глубины, полученное из выборки карты глубины на пересечении), Но используйте интерполяцию пересечения двух соседних слоев в качестве конечного P » role=»presentation»> P Точка, как это P » role=»presentation»> P Укажите ближе к B » role=»presentation»> B Точка.
Два самых популярных решения называютсяРельеф Параллакс Картография иПараллакс окклюзия картирование, Карта рельефного параллакса является более точной, чем карта маскирования параллакса, но имеет более высокую производительность, чем карта маскирования параллакса. Поскольку эффект маскирования параллакса аналогичен предыдущему, но он более эффективен, этот метод (маскирование параллакса) используется чаще. Карта окклюзии параллакса описана ниже.
3. Параллакс окклюзионное картирование
3.1 Принцип картирования окклюзии параллакса
Parallax Occlusion Mapping и крутое параллаксное картирование (также называемое рельефным картированием) используют тот же принцип, но вместо использования текстурных координат первого пересечения под поверхностью, текстурные координаты на пересечении текущего слоя и предыдущего Линейная интерполяция между текстурными координатами пересечений слоев, Вес линейной интерполяции основан на расстоянии между высотой поверхности и соответствующим слоем, принципиальная схема выглядит следующим образом:
3.2 Карта маскирования параллакса Код реализации
Код карты маскирования параллакса увеличивается из кода крутой карты параллакса:
Карты окклюзии параллакса дают очень хорошие результаты. Хотя вы все еще можете видеть некоторые незначительные нереальные и алиасовые проблемы, это лучший компромисс между производительностью и эффектомПо сравнению с рельефным картированием параллакса (Relief Parallax Mapping) потребление производительности велико), И эти проблемы со зрением возникают только тогда, когда они расположены очень широко или угол обзора очень крутой, иначе они не будут видны.
Он должен находиться далеко от поверхности, чтобы эффект отображения был наилучшим. Когда вы подходите ближе и ближе к поверхности, вы обнаружите, что некоторые детали поверхности движутся (неправильно), поэтому, когда вы находитесь очень близко к поверхности, появится вышеуказанное. Природное явление.
3.3 Пример кода
4. Резюме
Все вышеперечисленные методы отображения реализованы в фрагментном шейдере, поскольку координаты текстуры необходимы только в фрагментном шейдере.Различные карты параллакса, наконец, возвращают текстурные координаты текущего смещения фрагмента, а затем используют текстурные координаты для выборки диффузной карты и карты нормалей。
Обсудите стоимость расчета:Затраты на вычисление карт нормалей и карт параллакса относительно невелики, и отбираются только две текстуры, в то время как вычислительные затраты на карты рельефа и карты маскирования параллакса относительно велики.。






























