Рельефное текстурирование основывается на технике выполнения затенения по Фонгу, поэтому, если вы не прочитали предыдущие разделы, предлагаю сделать это прямо сейчас.
Рельефное текстурирование очень напоминает обычный процесс наложения ("натягивания") текстуры на полигон. Только при обычном наложении текстуры мы работаем со цветом и изменяем его цветовое восприятие, а вот при рельефном текстурировании мы добавляем ощущение рельефа, объемности плоскому полигону. Эта техника может добавить детализацию сцене без создания дополнительных полигонов. Заметьте, что полигон по-прежнему остается плоским, но создается ощущение его выпуклости (рельефности).
Рассмотрите куб на рисунке, создается впечатление, что он состоит из множества мелких полигонов, обрисовывающих чеканку и клепки. Но в действительности этот куб состоит из 6 плоских четырехугольных полигонов. Вы можете задать вопрос, а чем же это отличается от обычного текстурирования. Ответ - рельефное текстурирование отражает реальное положение источника света в сцене и даже изменение его местоположения. (Интересующимся можно посоветовать прочитать статью, посвященную реализации рельефного текстурирования в DirectX6)
А как оно действует?
Посмотрите на рисунок. С расстояния единственный способ определить, что изображение отображает рельефную поверхность, — это проанализировать изменения яркости отдельных участков изображения. Наш мозг делает это автоматически, незаметно для нас. В результате мы четко определяем, что будет выпуклостью, что впадиной.
Очень похоже на выдавливание (чеканку). Но, по сути, единственное, что было сделано для придания объемности плоскому изображению, — это правильное наложение ярких и темных участков. Остальное делает наш мозг.
Но как определить, какие биты изображения делать яркими, и наоборот. Очень просто. Большинство людей в течение своей жизни продолжительно находятся в условиях, когда свет исходит сверху. Таким образом, человек привык, что большинство поверхностей сверху ярко освещены, а снизу, наоборот, находятся в тени и будут темнее. Таким образом, если глаз воспринимает светлые и темные области на объекте, то человек воспринимает их как рельеф.
Нужны еще доказательства? Посмотрите на тот же рисунок, только развернутый на 180 градусов. Он стал похож на полную противоположность предыдущему. То, что раньше казалось выпуклым, стало вогнутым, и наоборот. А ведь это то же самое изображение.
Тем не менее, наш мозг все же не настолько глуп :). Если вы сможете заставить себя подумать, что свет исходит снизу, мозг воспроизведет информацию так же, как на первом изображении. Попробуйте!
Что такое рельефная карта (текстура)?
Рельефная карта (текстура) — это обычная текстура, только в отличие от первой, несущей информацию о цвете определенных участков, рельефная карта несет информацию о неровностях. Самый распространенный способ представить неровности — это применить карту высот. Карта высот — это текстура в оттенках серого, где яркость каждого пикселя представляет, насколько он выдается из базовой поверхности. (См. рисунок справа). Очень простой и удобный метод. Его легко реализовать.
Даже в псевдотрехмерных играх и приложениях, ввиду своей простоты, этот метод используется очень широко. Например, игра SimSity3000. Рельеф местности там задается bitmap текстурой с градацией яркости от 0 до 255. Где 50 соответствует нулевому уровню земли.0 — самым глубоким частям рек и озер, а 255 — будут означать вершины самых высоких гор. Bump maps очень широко используются разработчиками во многих пакетах работы с графикой и трех-мерными объектами.
Но это просто отступление, показывающее диапазон применения bump maps.
Используя карту высот, вы сможете имитировать неровности практически любой поверхности: дерево, камень, шелушащуюся краску и т.д. Конечно, у всего есть свои пределы. Используя bump mapping, вы не сможете имитировать крупные впадины и возвышенности, но вот для имитации неровностей и шероховатостей на поверхности этот метод подходит идеально.
Как реализовать?
По сути, это логическое продолжение техники просчета Phong shading. При использовании Phong shading мы интерполировали нормаль к поверхности по всему полигону, и этот вектор использовался для дальнейшего определения яркости соответствующего пикселя (См. главу, посвященную затенению по Фонгу). Реализуя bump mapping, мы немного меняем направление вектора нормали, основываясь на информации, содержащейся в карте высот. Изменяя положение вектора нормали в конкретной точке полигона, мы, соответственно, меняем яркость текущего пикселя (помните, закон косинуса из теории света :)) Все очень просто!
Для того, чтобы этого достичь, существует несколько путей. Давайте рассмотрим один из возможных способов.
Для начала нам нужен способ для преобразования информации о высоте неровностей на карте высот в информацию о величине подстройки вектора нормали. Это, собственно говоря, несложно, но немного тяжело для объяснения. Все же постарайтесь понять.
Сначала нам нужно преобразовать высоты с карты (bump map) в маленькие векторы, по одному на каждый пиксель. Посмотрите на увеличенный рисунок слева. Более светлые квадраты соответствуют более выпуклым участкам. Понятно. Теперь, для каждого пикселя (на нашем рисунке квадрат соответствует пикселю) мы должны рассчитать вектор, указывающий нам направление уклона поверхности. Рисунок справа демонстрирует нам это. Маленькие красные векторы указывают на уменьшение высоты. Для определения этих векторов, мы определим величину градиента для каждого пикселя:
- x_gradient = pixel(x-1, y) — pixel(x+1, y) y_gradient = pixel(x, y-1) — pixel(x, y+1),
где х и y — координаты соответствующего пикселя
Теперь, имея в руках значения градиентов, мы сможем подкорректировать вектор нормали в соответствующем пикселе.
Слева — полигон с изначальным вектором нормали, обозначенным n. Также показаны два вектора, которые будут использованы для изменения положения (направления) нормали к пикселю под ним. Оба вектора должны располагаться параллельно осям
координат применяемой карты высот.
Справа показаны карта высот и полигон. На обоих рисунках показаны направления U и V осей координат карты (текстуры) высот.
Пересчитать новый вектор нормали легко:
New_Normal = Normal + (U * x_gradient) + (V * y_gradient)
Получив новый вектор нормали, мы может просчитать яркость данного пикселя, используя ранее изученную технологию затенения по Фонгу.
Выполнение быстрого рельефного текстурирования
(Fast Bump mapping)
Выше вы узнали, что при рельефном текстурировании производится изменение вектора нормали к поверхности на площади всего полигона в соответствии с картой высот. Вы так же помните, что для ускорения просчета затенения по Фонгу мы применили способ с заранее просчитанной Phong map, которая представляет собой набор яркостей для всех возможных нормалей на полигоне. Таким образом, не надо быть гением, чтобы предположить, что быстро выполняемым вариантом рельефного текстурирования будет просчет смещений к карте затенения по Фонгу. Результирующей яркостью пикселя будет сумма значений, полученных с карты затенения и рельефной карты. Используя этот подход, мы одновременно будем производить затенение по Фонгу с учетом рельефности рисунка.