ПрограммированиеСтатьиГрафика

Detail textures: теория и практика.

Автор:

Рассмотрим полигон, с наложенной на него текстурой, причем сначала расстояние от зрителя до полигона будет достаточно велико (используем mipmap, поэтому качество замечательное), а вот второй раз расстояние будет уже мало настолько, что вовсю начинает работать фильтрация текстуры (или, проще говоря, «размазывание»).

ИзображениеИзображение
далекий полигонблизкий полигон

Прекрасно видно ухудшение качества изображения: еще бы, у нас же текстура ограниченных размеров и на определенном расстоянии появляется "размазывание", что не есть хорошо.

Как с этим бороться ? Можно, конечно, увеличить качество (разрешение) текстуры, это может спасти, так как уменьшается "критическое" расстояние, но при этом увеличивается размер текстуры, а память ускорителя, как известно, не резиновая, поэтому мы так делать не будем.

Рассмотрим один из способов решения этой проблемы:

Микрофактурные текстуры (detail textures) или, как их еще (неверно) называют, детальные текстуры появились довольно таки давно, если мне не изменяет память - с Unreal-а.

Это довольно таки простой эффект, но значительно повышающий качество графики в игре.

Для реализации этого эффекта берется основная текстура (base) и микрофактурная (detail). Причем, detail текстура создается таким образом, что она должна быть (ну очень желательно) никак не цветной, а черно-серо-белой, то есть grayscale. Плюс еще к этому, средний уровень значений цветов должен держаться около середины, то есть около 128 (от 0 до 255). Зачем ? Это вы увидите дальше.

микрофактурная текстура:

Изображение

Порядок отрисовки полигонов следующий:

1. Накладываем base текстуру (как обычно)

2. Накладываем detail текстуру таким образом, что текстурные координаты для detail в несколько раз больше, чем для base текстуры (например, при равных размерах текстур, можно выбрать коэффициент увеличения 16 или более), при этом используя блендинг с операцией двойного умножения (modulate2x).

Таким образом получаем (возвращаясь к уже написанному - grayscale detail текстура со значениями цветов в половину от максимальных),

Result_texture = base * detail * 2 
               = base * (max_intensity/2) * 2 
               = base * max_intensity

То есть, получаем, что основная текстура умножается на значение максимальной интенсивности цвета, что равносильно умножению на единицу. Из этого можно сделать вывод, что яркость результирующей текстуры не будет отличаться от base, но при этом в некоторых пикселях результата мы будем получать небольшие отклонения, ввиду того, что detail текстура у нас все-таки не идеально серая (есть колебания в сторону увеличения и уменьшения яркости). Это все - последствия (хорошие) выдерживания средней интенсивности цвета detail текстуры на среднем (128) уровне.

Тот же факт, что мы сделали detail текстуру в оттенках серого не дает составляющим цвета основной текстуры пропадать или очень сильно увеличивать свою яркость по сравнению с другими (можете попробовать сделать detail текстуру немного "цветную" и вы увидите результат).

Пример реализации.

Пример сделан с использованием OpenGL, что, впрочем, не составит труда перенести его в DirectX.

Для двойного умножения использовалась функция текстурного бленда:

glBlendFunc( GL_DST_COLOR, GL_SRC_COLOR );

Что означает

Res.color = src.color * GL_DST_COLOR + dst.color * GL_SRC_COLOR 
          = 2 * src.color * dst.color

А это то, что нам и надо для операции.
Так же эту операцию можно провести, используя расширение OpenGL TEXTURE_ENV_COMBINE, которое позволяет производить умножение результата бленда на 2, а так же, с использованием расширения nVidia - REGISTER_COMBINERS_NV, что так же представлено в исходных текстах примера. Небольшое обучение работы с этим расширением можно найти здесь.

Все бы вроде хорошо, но, оказывается, не все ! Что произойдет, если отдалиться от полигона на большое расстояние ? Detail текстура станет просто невидимой, но она по-прежнему отрисовывается на полигоне. Чтобы подавить это ненужное действие (и, соответственно, падение производительности), мы просто рассчитываем расстояние до полигона и решаем, использовать нам detail текстуру или нет. Все просто.

В результате получаем:

Изображение

Ну, и в заключении, небольшой трик: предположим, человек находится в темноте и приближается к стене. При достаточно большом приближении стена уже не кажется ему такой темной, как сначала (на это есть физическое объяснение явления, при условии, что темнота не идеальная). Если мы в своей detail текстуре сделаем среднюю интенсивность немного больше 128-ми, то будем наблюдать такой же эффект - увеличение результирующей яркости при приближении к полигону.

При написании примера использовалась библиотека GLUT.

Управление в примере: 1 - выключение detail текстур, 2 - включение, M - многопроходный метод, R - использование Register Combiners.

Скачать: Пример (226 Кб). (Исходный код прилагается)

#текстурирование

28 ноября 2001 (Обновление: 17 июня 2009)