На что влияет анизотропная фильтрация в играх
Что такое анизотропная фильтрация и зачем ее включать
Почти во всех современных играх есть пункт в настройках графики “анизотропная фильтрация”, коротко АФ, но зачем ее включать и на что она влияет? Давай те разберемся вместе.
Как понятно из названия опции, АФ предназначена для “фильтрации текстур”. Данный параметр крайне рекомендуется выставлять в максимальное значение. Для ясности взгляните на изображение ниже.
Первый кадр не демонстрируется с полностью отключенным АФ, в то время как значение на втором кадре равно X16. Обратите внимание, что чем дальше дорого уходит от камеры игрока, тем больше уменьшается прорисовка текстур.
Если выбирать, какое значение выбрать, то знайте, разница в производительности между 8х и 16х ничтожна, поэтому мы рекомендуем выбрать все-таки x16.
Но эффект от фильтрации текстур лучше всего заметем в движении. Без АФ заметны “лесенки” в стыках текстур поверхностей. Как правило, анизотропная фильтрация может заметно повлиять на частоту кадров и съесть память вашей видеокарты, хотя это не всегда так и данный эффект разница от одного компьютера к другому.
Подводя итог, анизотропная фильтрация придает четкости текстурам на отдалении от игрока. Испытать вы можете эффективности АФ в своей любимой игре, лучше всего каком-нибудь шутере от первого лица.
На что влияет анизотропная фильтрация в играх
Думаю, с понятием разрешения знакомы уже более-менее все игроки, но на всякий случай вспомним основы. Все же, пожалуй, главный параметр графики в играх.
Изображение, которое вы видите на экране, состоит из пикселей. Разрешение — это количество пикселей в строке, где первое число — их количество по горизонтали, второе — по вертикали. В Full HD эти числа — 1920 и 1080 соответственно. Чем выше разрешение, тем из большего количества пикселей состоит изображение, а значит, тем оно четче и детализированнее.
Влияние на производительность
Очень большое.Увеличение разрешения существенно снижает производительность. Именно поэтому, например, даже топовая RTX 2080 TI неспособна выдать 60 кадров в 4K в некоторых играх, хотя в том же Full HD счетчик с запасом переваливает за 100. Снижение разрешения — один из главных способов поднять FPS. Правда, и картинка станет ощутимо хуже.
В некоторых играх (например, в Titanfall) есть параметр так называемого динамического разрешения. Если включить его, то игра будет в реальном времени автоматически менять разрешение, чтобы добиться заданной вами частоты кадров.
Вертикальная синхронизация
Если частота кадров в игре существенно превосходит частоту развертки монитора, на экране могут появляться так называемые разрывы изображения. Возникают они потому, что видеокарта отправляет на монитор больше кадров, чем тот может показать за единицу времени, а потому картинка рендерится словно «кусками».
Вертикальная синхронизация исправляет эту проблему. Это синхронизация частоты кадров игры с частотой развертки монитора. То если максимум вашего монитора — 60 герц, игра не будет работать с частотой выше 60 кадров в секунду и так далее.
Есть и еще одно полезное свойство этой опции — она помогает снизить нагрузку на «железо» — вместо 200 потенциальных кадров ваша видеокарта будет отрисовывать всего 60, а значит, загружаться не на полную и греться гораздо меньше.
Впрочем, есть у Vsync и недостатки. Главная — очень заметный «инпут-лаг», задержка между вашими командами (например, движениями мыши) и их отображением в игре.
Поэтому играть со включенной вертикальной синхронизацией в мультипеере противопоказано. Кроме того, если ваш компьютер «тянет» игру при частоте ниже, чем заветные 60 FPS, Vsync может автоматически «лочиться» уже на 30 FPS, что приведет к неслабым таким лагам.
Лучший способ бороться с разрывами изображения на сегодняшний день — купить монитор с поддержкой G-Sync или FreeSync и соответствующую видеокарту Nvidia или AMD. Ни разрывов, ни инпут-лага.
Влияние на производительность
В общем и целом — никакого.
Сглаживание(Anti-aliasing)
Если нарисовать из квадратных по своей природе пикселей ровную линию, она получится не гладкой, а с так называемыми «лесенками». Особенно эти лесенки заметны при низких разрешениях. Чтобы устранить этот неприятный дефект и сделать изображения более четким и гладким, и нужно сглаживание.
Здесь и далее — слева изображение с отключенной графической опцией (или установленной на низком значении), справа — с включенной (или установленной на максимальном значении).
Технологий сглаживания несколько, вот основные:
Влияние на производительность
От ничтожного (FXAA) до колоссального (SSAA). В среднем — умеренное.
Качество текстур
Один из самых важных параметров в настройках игры. Поверхности всех предметов во всех современных трехмерных играх покрыты текстурами, а потому чем выше их качество и разрешение — тем четче, реалистичнее картинка. Даже самая красивая игра с ультра-низкими текстурами превратится в фестиваль мыловарения.
Влияние на производительность
Если в видеокарте достаточно видеопамяти, то практически никакого. Если же ее не хватает, вы получите ощутимые фризы и тормоза. 4 гигабайт VRAM хватает для подавляющего числа современных игр, но лучше бы в вашей следующей видеокарте памяти было 8 или хотя бы 6 гигабайт.
Анизотропная фильтрация
Анизотропная фильтрация, или фильтрация текстур, добавляет поверхностям, на которые вы смотрите под углом, четкости. Особенно ее эффективность заметна на удаленных от игрока текстурах земли или стен.
Чем выше степень фильтрации, чем четче будут поверхности в отдалении.
Этот параметр влияет на общее качество картинки довольно сильно, но систему при этом практически не нагружает, так что в графе «фильтрация текстур» советуем всегда выставлять 8x или 16x. Билинейная и трилинейная фильтрации уступают анизотропной, а потому особенного смысла в них уже нет.
Влияние на производительность
Тесселяция
Технология, буквально преображающая поверхности в игре, делающая их выпуклыми, рельефными, натуралистичными. В общем, тесселяция позволяет отрисовывать гораздо более геометрически сложные объекты. Просто посмотрите на скриншоты.
Влияние на производительность
Зависит от игры, от того, как именно движок применяет ее к объектам. Чаще всего — среднее.
Качество теней
Все просто: чем выше этот параметр, тем четче и подробнее тени, отбрасываемые объектами. Добавить тут нечего. Иногда в играх также встречается параметр «Дальность прорисовки теней» (а иногда он «вшит» в общие настройки). Тут все тоже понятно: выше дальность — больше теней вдалеке.
Влияние на производительность
Зависит от игры. Чаще всего разница между низкими и средними настройками не столь велика, а вот ультра-тени способны по полной загрузить ваш ПК, поскольку в этом случае количество объектов, отбрасывающих реалистичные тени, серьезно вырастает.
Глобальное затенение (Ambient Occlusion)
Один из самых важных параметров, влияющий на картинку разительным образом. Если вкратце, то AO помогает имитировать поведения света в трехмерном мире — а именно, затенять места, куда не должны попадать лучи: углы комнат, щели между предметами и стенами, корни деревьев и так далее.
Существует два основных вида глобального затенения:
SSAO (Screen space ambient occlusion). Впервые появилось в Crysis — потому тот и выглядел для своего времени совершенно фантастически. Затеняются пиксели, заблокированные от источников света.
HBAO (Horizon ambient occlusion). Работает по тому же принципу, просто количество затененных объектов и зон гораздо больше, чем при SSAO.
Влияние на производительность
Глубина резкости (Depth of Field)
То самое «боке», которое пытаются симулировать камеры большинства современных объектов. В каком-то смысле это имитация особенностей человеческого зрения: объект, на который мы смотрим, находится в идеальном фокусе, а объекты на фоне — размыты. Чаще всего глубину резкости сейчас используют в шутерах: обратите внимание, что когда вы целитесь через мушку, руки персонажа и часть ствола чаще всего размыты.
Впрочем, иногда DoF только мешает — складывается впечатление, что у героя близорукость.
Влияние на производительность
Целиком и полностью зависит от игры. От ничтожного до довольно сильного (как, например, в Destiny 2).
Bloom (Свечение)
Этот параметр отвечает за интенсивность источников света в игре. Например, с включенным Bloom, свет, пробивающийся из окна в помещение, будет выглядеть куда ярче. А солнце создавать натуральные «засветы». Правда, некоторые игры выглядят куда реалистичнее без свечения — тут нужно проверять самому.
Влияние на производительность
Чаще всего — низкое.
Motion Blur (Размытие в движении)
Motion Blur помогает передать динамику при перемещениях объекта. Работает он просто: когда вы быстро двигаете камерой, изображение начинает «плыть». При этом главный объект (например, руки персонажа с оружием) остается четким.
Фильтрация анизотропная: для чего нужна, на что влияет, практическое использование
Технологии отображения 3D-объектов на экране мониторов персональных компьютеров развиваются вместе с выпуском современных графических адаптеров. Получение идеальной картинки в трёхмерных приложениях, максимально приближённой к реальному видео, является основной задачей разработчиков железа и главной целью для ценителей компьютерных игр. Помочь в этом призвана технология, реализованная в видеокартах последних поколений — анизотропная фильтрация в играх.
Что это такое?
Каждому компьютерному игроку хочется, чтобы на экране разворачивалась красочная картина виртуального мира, чтобы, взобравшись на вершину горы, можно было обозревать живописные окрестности, чтобы, нажимая до отказа кнопку ускорения на клавиатуре, до самого горизонта можно было увидеть не только прямую трассу гоночного трека, а и полноценное окружение в виде городских пейзажей. Объекты, отображаемые на экране монитора, только в идеале стоят прямо перед пользователем в самом удобном масштабе, на самом деле подавляющее большинство трёхмерных объектов находится под углом к линии зрения. Более того, различное виртуальное расстояние текстур до точки взгляда также вносит коррективы в размеры объекта и его текстур. Расчётами отображения трёхмерного мира на двумерный экран и заняты различные 3D-технологии, призванные улучшить зрительное восприятие, в числе которых не последнее место занимает текстурная фильтрация (анизотропная или трилинейная). Фильтрация такого плана относится к числу лучших разработок в этой области.
На пальцах
Чтобы понять, что даёт анизотропная фильтрация, нужно понимать основные принципы алгоритмов текстурирования. Все объёкты трёхмерного мира состоят из «каркаса» (трехмерной объёмной модели предмета) и поверхности (текстуры) — двумерной картинки, «натянутой» поверх каркаса. Малейшая часть текстуры — цветной тексель, это как пиксели на экране, в зависимости от «плотности» текстуры, тексели могут быть разных размеров. Из разноцветных текселей состоит полная картина любого объекта в трёхмерном мире.
Ближний цвет
Самым простым алгоритмом фильтрации является отображение цвета ближайшего к точке зрения каждого пискеля (Point Sampling). Всё просто: луч зрения определённой точки на экране падает на поверхность трёхмерного объекта, и текстура изображений возвращает цвет ближайшего к точке падения текселя, отфильтровывая все остальные. Идеально подходит для однотонных по цвету поверхностей. При небольших перепадах цвета тоже даёт вполне качественную картинку, но довольно унылую, так как где вы видели трёхмерные объекты одного цвета? Одни только шейдеры освещения, теней, отражений и другие готовы раскрасить любой объект в играх как новогоднюю ёлку, что же говорить о самих текстурах, которые порою представляют собой произведения изобразительного искусства. Даже серая бездушная бетонная стена в современных играх — это вам не просто прямоугольник невзрачного цвета, это испещрённая шероховатостями, порою трещинами и царапинами и другими художественными элементами поверхность, максимально приближающая вид виртуальной стены к реальным или выдуманным фантазией разработчиков стенам. В общем, ближний цвет мог быть использован в первых трёхмерных играх, сейчас же игроки стали гораздо требовательнее к графике. Что немаловажно: фильтрация ближнего цвета практически не требует вычислений, то есть очень экономична в плане ресурсов компьютера.
Линейная фильтрация
Отличия линейного алгоритма не слишком существенны, вместо ближайшей точки-текселя линейная фильтрация использует сразу 4 и рассчитывает средний цвет между ними. Единственная проблема, что на поверхностях, расположенных под углом к экрану, луч зрения образует как бы эллипс на текстуре, тогда как линейная фильтрация использует идеальный круг для подбора ближайших текселей независимо от угла обзора. Использование четырёх текселей вместо одного позволяет значительное улучшить прорисовку удалённых от точки обзора текстур, но всё равно недостаточно, чтобы корректно отразить картинку.
Mip-mapping
Билинейная фильтрация
Используя вместе линейную фильтрацию и MIP-текстурирование, получаем билинейный алгоритм, который позволяет ещё лучше отображать удалённые объекты и поверхности. Однако всё те же 4 текселя не дают технологии достаточной гибкости, к тому же билинейная фильтрация не маскирует переходы на следующий уровень масштабирования, работая с каждой частью текстуры по отдельности, и их границы могут быть видны. Таким образом, на большом удалении или под большим углом текстуры сильно размываются, делая картинку неестественной, как будто для людей с близорукостью, плюс для текстур со сложными рисунками заметны линии стыка текстур разного разрешения. Но мы же за экраном монитора, не нужна нам близорукость и разные непонятные линии!
Трилинейная фильтрация
Эта технология призвана исправить прорисовку на линиях смены масштаба текстур. Тогда как билинейный алгоритм работает с каждым уровнем mip-mapping по отдельности, трилинейная фильтрация дополнительно просчитывает границы уровней детализации. При всём этом растут требования к оперативной памяти, а улучшение картинки на удалённых объектах при этом не слишком ощутимо. Само собой, границы между ближними уровнями масштабирования получают лучшую обработку, нежели при билинейной, и более гармонично смотрятся без резких переходов, что сказывается на общем впечатлении.
Анизотропная фильтрация
Если просчитывать проекцию луча зрения каждого экранного пикселя на текстуре согласно углу обзора, получатся неправильные фигуры — трапеции. Вкупе с использованием большего количества текселей для расчётов итогового цвета это может дать гораздо лучший результат. Что даёт анизотропная фильтрация? Учитывая, что пределов количества используемых текселей в теории нет, такой алгоритм способен отображать компьютерную графику неограниченного качества на любом удалении от точки обзора и под любым углом, в идеале сравнимую с реальным видео. Фильтрация анизотропная по своим возможностям упирается лишь в технические характеристики графических адаптеров персональных компьютеров, на которые и рассчитаны современные видеоигры.
Подходящие видеокарты
Режим анизотропной фильтрации был возможен на пользовательских видеоадаптерах уже с 1999 года, начиная с известных карт Riva TNT и Voodoo. Топовые комплектации этих карт вполне справлялись с просчётом трилинейной графики и даже выдавали сносные показатели FPS с использованием анизотропной фильтрации х2. Последняя цифра указывает на качество фильтрации, которое, в свою очередь, зависит от количества текселей, занятых в расчёте итогового цвета пикселя на экране, в данном случае их используется целых 8. Плюс ко всему, при расчётах используется соответствующая углу зрения область захвата этих текселей, а не круг, как в линейных алгоритмах ранее. Современные видеокарты способны обрабатывать фильтрацию анизотропным алгоритмом на уровне х16, что означает использование 128 текселей для расчётов итогового цвета пикселя. Это сулит значительное улучшение отображения удалённых от точки обзора текстур, а также и серьёзную нагрузку, но графические адаптеры последних поколений снабжены достаточным количеством оперативной памяти и многоядерными процессорами, чтобы справляться с этой задачей.
Влияние на FPS
Преимущества понятны, но как дорого обойдётся игрокам анизотропная фильтрация? Влияние на производительность игровых видеоадаптеров с серьёзной начинкой, выпущенных не позднее 2010 года, очень незначительно, что подтверждают тесты независимых экспертов в ряде популярных игр. Фильтрация текстур анизотропная в качестве х16 на бюджетных картах показывает снижение общего показателя FPS на 5-10%, и то за счёт менее производительных компонентов графического адаптера. Такая лояльность современного железа к ресурсоёмким вычислениям говорит о непрестанной заботе производителей о нас, скромных геймерах. Вполне возможно, что не за горами переход на следующие уровни качества анизотропии, лишь бы игроделы не подкачали.
Опции и оптимизация
Управление типом и качеством фильтрации доступно благодаря специальному ПО, регулирующему драйвера графических адаптеров. Также расширенная настройка анизотропной фильтрации доступна в игровых меню. Реализация больших разрешений и использование нескольких мониторов в играх заставили производителей задуматься об ускорении работы своих изделий, в том числе за счёт оптимизации анизотропных алгоритмов. Производители карт в последних версиях драйверов представили новую технологию под названием адаптивная анизотропная фильтрация. Что это значит? Эта функция, представленная AMD и частично реализованная в последних продуктах Nvidia, позволяет снижать коэффициент фильтрации там, где это возможно. Таким образом, фильтрация анизотропная коэффициентом х2 может обрабатывать ближние текстуры, тогда как удалённые объекты пройдут рендеринг по более сложным алгоритмам вплоть до максимального х16-коэффициента. Как обычно, оптимизация даёт существенное улучшение за счёт качества, местами адаптивная технология склонна к ошибкам, заметным на ультранастройках некоторых последних трёхмерных видеоигр.
На что влияет анизотропная фильтрация? Задействование вычислительных мощностей видеоадаптеров, по сравнению с другими технологиями фильтрации, намного выше, что сказывается на производительности. Впрочем, проблема быстродействия при использовании этого алгоритма давно решена в современных графических чипах. Вместе с остальными трёхмерными технологиями анизотропная фильтрация в играх (что это такое мы уже представляем) влияет на общее впечатление о целостности картинки, особенно при отображении удалённых объектов и текстур, расположенных под углом к экрану. Это, очевидно, главное, что требуется игрокам.
Взгляд в будущее
Современное железо со средними характеристиками и выше вполне способно справиться с требованиями игроков, поэтому слово о качестве трёхмерных компьютерных миров сейчас за разработчиками видеоигр. Графические адаптеры последнего поколения поддерживают не только высокие разрешения и такие ресурсоёмкие технологии обработки изображений, как фильтрация текстур анизотропная, но и VR-технологии или поддержку нескольких мониторов.
Как работает рендеринг 3D-игр: текстурирование и фильтрация текстур
В третьей статье о рендеринге в 3D-играх мы узнаем, что происходит с 3D-миром после завершения обработки вершин и растеризации сцены. Текстурирование — один из самых важных этапов рендеринга, несмотря на то, что на нём всего лишь вычисляются и изменяются цвета двухмерной сетки разноцветных блоков.
Большинство визуальных эффектов в современных играх сводится к продуманному использованию текстур — без них игры казались бы скучными и безжизненными. Так что давайте разберёмся, как всё это работает!
Начнём с простого
Можно взять любые трёхмерные игры-бестселлеры, выпущенные за последний год, и с уверенностью сказать, что все они имеют нечто общее: в них используются текстурные карты (или просто текстуры). Это настолько распространённый термин, что думая о текстурах, большинство людей представляет одинаковую картинку: простой плоский квадрат или прямоугольник, содержащий изображение поверхности (травы, камня, металла, ткани, лица и т.д.).
Но при многослойном использовании и комбинировании с помощью сложных вычислений такие простые изображения в 3D-сцене могут создавать поразительно реалистичные изображения. Чтобы понять, как такое возможно, давайте полностью их отключим и посмотрим, как будут выглядеть объекты 3D-мира без текстур.
Как мы видели из предыдущих статей, 3D-мир составлен из вершин — простых фигур, которые перемещаются, а затем раскрашиваются. Затем они используются для создания примитивов, которые в свою очередь сжимаются в двухмерную сетку пикселей. Так как мы не будем использовать текстуры, нам нужно раскрасить эти пиксели.
Один из способов, который можно применить, называется плоским затенением: берётся цвет первой вершины примитива, а затем этот цвет применяется ко всем пикселям, покрываемым фигурой в растре. Это выглядит примерно так:
Очевидно, что чайник выглядит нереалистично, и не в последнюю очередь из-за неправильных цветов поверхности. Цвета прыгают с одного уровня на другой, плавные переходы отсутствуют. Одно из решений проблемы может заключаться в использовании затенения по Гуро.
В этом процессе берутся цвета вершин, после чего вычисляется изменение цвета по поверхности треугольника. Для этого используется линейная интерполяция. Звучит сложно, но самом деле это значит, что если, например, одна сторона примитива имеет цвет в 0.2 красного, а другая в 0.8 красного, то середина фигуры будет иметь цвет посередине между 0.2 и 0.8 (т.е. 0.5).
Этот процесс выполняется достаточно просто, и это его основное преимущество, потому что простота означает скорость. Во многих старых 3D-играх использовалась эта техника, потому что выполняющее вычисления оборудование было ограничено в своих возможностях.
Баррет и Клауд во всём величии затенения по Гуро (Final Fantasy VII, 1997 год)
Но даже такое решение имеет проблемы — если свет падает прямо в середину треугольника, то его углы (и вершины) могут не передавать это свойство. Это означает, что создаваемый светом отблеск может быть совершенно потерян.
Хотя плоское затенение и затенение по Гуро заняли достойное место в инструментарии рендеринга, показанные выше примеры — явные кандидаты на улучшение при помощи текстур. А чтобы хорошо понять, что происходит, когда текстура накладывается на поверхность, мы вернёмся назад во времени… аж в 1996 год.
История игр и GPU вкратце
Примерно 23 года назад компания id Software выпустила Quake, и он стал серьёзной вехой. Хотя это не была первая игра, использовавшая 3D-полигоны и текстуры для рендеринга окружений, но она определённо стала одной из первых, кто использовал их эффективно.
Но она сделала и ещё кое-что — показала, что можно сделать при помощи OpenGL (этот графический API тогда находился в состоянии первой версии), а также очень помогла первому поколению графических карт наподобие Rendition Verite и 3Dfx Voodoo.
Освещение вершин и простые текстуры. Чистый 1996 год, чистый Quake.
По современным стандартам Voodoo была чрезвычайно проста: ни поддержки 2D-графики, ни обработки вершин, только самое простейшая обработка пикселей. Тем не менее, она была прекрасна:
У неё был целый чип (TMU) для получения пикселя из текстуры и ещё один чип (FBI) для последующего смешения его с пикселем растра. Карта могла выполнять ещё пару дополнительных процессов, например, реализацию тумана или эффектов прозрачности, но на этом, по сути, её возможности заканчивались.
Если мы рассмотрим архитектуру, лежащую в основе структуру и работы графической карты, то увидим, как работают эти процессы.
Чип FBI получал два значения цвета и смешивал их; одним из них могло быть значение из текстуры. Процесс смешения математически довольно прост, но немного варьируется в зависимости от того, что смешивается, и какой API используется для выполнения инструкций.
Если взглянуть на то, что предлагает нам Direct3D в отношении функций и операций смешения, то мы увидим, что каждый пиксель сначала умножается на число от 0.0 до 1.0. Это определяет, насколько цвет пикселя будет влиять на готовый результат. Затем два изменённых цвета пикселя складываются, вычитаются или умножаются; в некоторых функциях выполняется логическая операция, при которой, например, всегда выбирается самый яркий пиксель.
На изображении выше показано, как это работает на практике; заметьте, что для левого пикселя в качестве коэффициента использовано значение альфы пикселя. Это число обозначает величину прозрачности пикселя.
На остальных этапах применяется значение тумана (оно берётся из созданной программистом таблицы, а затем выполняются такие же вычисления смешения); выполнение проверок и изменений видимости и прозрачности; в конце цвет пикселя записывается в память графической карты.
Зачем нужен этот экскурс в историю? Ну, несмотря на относительную простоту конструкции (особенно по сравнению с современными монстрами), этот процесс описывает фундаментальные основы текстурирования: берём значения цветов и смешиваем их, чтобы модели и окружения выглядели так, как должны в конкретной ситуации.
Современные игры делают то же самое, единственное отличие заключается в количестве используемых текстур и сложности вычислений смешения. Вместе они симулируют визуальные эффекты, которые встречаются в фильмах, или взаимодействие освещения с разными материалами и поверхностями.
Основы текстурирования
Для нас текстура — это плоское 2D-изображение, накладываемое на полигоны, из которых состоят находящиеся в кадре 3D-структуры. Однако для компьютера это всего лишь небольшой блок памяти в виде 2D-массива. Каждый элемент массива обозначает значение цвета одного из пикселей изображения текстуры (обычно называемых текселами — текстурными пикселями).
Каждая вершина полигона имеет набор из двух координат (обычно обозначаемых как u,v), сообщающий компьютеру, какой пиксель текстуры с ней связан. Сама вершина имеет набор из трёх координат (x,y,z), а процесс привязки текселов к вершинам называется наложением текстур (texture mapping).
Чтобы увидеть, как это происходит, давайте обратимся к инструменту, который мы уже несколько раз использовали в этой серии статей — Real Time Rendering WebGL. Пока мы также отбросим координату z вершин и будем рассматривать всё на ровной плоскости.
Слева направо: координаты u,v текстуры, привязанные напрямую к координатам x,y угловых вершин. На втором изображении у верхних вершин увеличены координаты y, но так как текстура по-прежнему привязана к ним, она растягивается по вертикали. На правом изображении изменена уже текстура: значения u увеличились, но в результате этого текстура была сжата, а затем повторяется.
Так получилось, потому что несмотря на то, что по сути текстура стала выше благодаря увеличенному значению u, она по-прежнему должна умещаться в примитив — по сути, текстура частично повторилась. Это один из способов реализации эффекта, который часто встречается в 3D-играх: повторения текстур. Примеры этого эффекта можно увидеть в сценах с каменистыми или травянистыми ландшафтами, а также с кирпичными стенами.
Теперь давайте изменим сцену, чтобы было больше примитивов, а также снова вернём глубину сцены. Ниже показан классический ландшафтный вид, но теперь текстура ящика скопирована и повторяется для всех примитивов.
Текстура ящика в своём исходном формате gif имеет размер 66 КБ и разрешение 256 x 256 пикселей. Исходное разрешение части кадра, покрываемого текстурами ящика, равно 1900 x 680, то есть с точки зрения пиксельной «площади» такая область должна отображать только 20 текстур ящика.
Но очевидно, что мы видим гораздо больше двадцати ящиков, и это означает, что текстуры ящика вдали должны быть намного меньше, чем 256 x 256 пикселей. Так и есть, они подверглись процессу, называемому «уменьшением текстур» (texture minification) (да, такое слово в английском существует!). А теперь давайте повторим, но на этот раз приблизим камеру к одному из ящиков.
Не забывайте, что текстура имеет размер всего 256 x 256 пикселей, но мы видим здесь текстуру размером больше половины изображения шириной 1900 пикселей. Эта текстура была подвергнута операции «увеличения текстуры» (texture magnification).
Эти два текстурных процесса постоянно происходят в 3D-играх, потому что при движении камеры по сцене модели приближаются или удаляются, и все нанесённые на примитивы текстуры должны масштабироваться вместе с полигонами. С точки зрения математики это небольшая проблема, на самом деле, даже самые простые интегрированные графические чипы с лёгкостью выполняют такую работу. Однако уменьшение и увеличение текстур представляют собой новые задачи, которые нужно каким-то образом решить.
На сцене появляются мини-копии текстур
Первая проблема, которую нужно решить для текстур — это расстояние. Если мы вернёмся к первому изображению с ландшафтом из ящиков, то находящиеся у горизонта ящики по сути имеют размер всего несколько пикселей. Поэтому стараться сжать изображение размером 256 x 256 пикселей в такое крошечное пространство бессмысленно по двум причинам.
Во-первых, меньшая текстура занимает меньше памяти графической карты, что удобно, ведь можно попробовать уместить её в меньший объём кэша. Это означает, что она с меньшей вероятностью будет удалена из кэша, то есть многократное использование этой текстуры обеспечит рост производительности, ведь данные будут находиться в близкой памяти. Ко второй причине мы скоро вернёмся, потому что она связана с той же проблемой, возникающей у приближенных к камере текстур.
Стандартным решением проблемы необходимости сжатия больших текстур в мелкие примитивы является использование mip-текстур (mipmaps). Это уменьшенные в размере версии исходной текстуры; они могут генерироваться самим движком (при помощи соответствующих команд API) или предварительно создаваться дизайнерами игры. Каждый последующий уровень mip-текстуры имеет уменьшенные в два раза размеры по сравнению с предыдущим.
То есть для текстуры ящика размеры будут такими: 256 x 256 → 128 x 128 → 64 x 64 → 32 x 32 → 16 x 16 → 8 x 8 → 4 x 4 → 2 x 2 → 1 x 1.
Все mip-текстуры упакованы вместе, поэтому текстура имеет то же имя файла, но становится больше в размерах. Текстура упакована таким образом, что координаты u,v не только определяют, какой тексел накладывается на пиксель в кадре, но и с какой mip-текстуры. Затем программисты пишут рендерер, на основании значения глубины пикселя кадра определяющий, какую нужно использовать mip-текстуру. Например, если значение очень высоко, то пиксель находится далеко, а значит, можно использовать маленькую mip-текстуру.
Внимательные читатели могли заметить недостаток mip-текстур — за них приходится расплачиваться увеличением размера текстур. Исходная текстура ящика имела размер 256 x 256 пикселей, но как видно на изображении выше, текстура с mip-текстурами теперь имеет размер 384 x 256. Да, в ней есть много пустого пространства, но как бы мы ни упаковывали более мелкие текстуры, в целом размер текстуры по одной из сторон увеличится как минимум на 50%.
Но это справедливо только для заранее созданных mip-текстур; если игровой движок запрограммирован генерировать их правильно, то увеличение составляет не более чем 33% от исходного размера текстуры. Поэтому за счёт небольшого увеличения объёма памяти для хранения mip-текстур мы получаем выигрыш в производительности и визуальном качестве.
Ниже показано сравнение изображений с отключенными/включенными mip-текстурами:
В левой части изображения текстуры ящиков использовались «как есть», что привело к появлению зернистости и так называемого муара вдалеке. Справа же использование mip-текстур позволило обеспечить более плавные переходы, а на горизонте текстура ящика размывается в однообразный цвет.
Однако кому захочется, чтобы размытые текстуры портили фоны любимой игры?
Билинейная, трилинейная, анизотропная — всё это для меня китайская грамота
Процесс выбора пикселя из текстуры для наложения его на пиксель в кадре называется сэмплированием текстур, и в идеальном мире существовала бы текстура, которая идеально соответствует примитиву, для которого она предназначена, вне зависимости от размера, позиции, направления и так далее. Другими словами, сэмплирование текстуры заключалось бы в простом сопоставлении один к одному тексела пикселю.
Но поскольку это не так, при сэмплировании текстур нужно учитывать несколько факторов:
Второй фактор проблем не вызывает, потому что mip-текстуры используются для обхода задачи сэмплирования текстур расположенных далеко примитивов, поэтому остаётся только задача отображения текстур под углом. И да, это тоже проблема. Почему? Потому что все текстуры — это изображения, сгенерированные для просмотра «строго спереди». Если говорить математическим языком, то нормаль поверхности текстуры совпадает с номралью поверхности, на которой в текущий момент отображается текстура.
Поэтому если текселов слишком мало или слишком много, или они расположены под углом, то требуется дополнительный процесс под названием «фильтрация текстур». Если этот процесс не использовать, то мы получим вот это:
Здесь мы заменили текстуру ящика текстурой с буквой R, чтобы чётче показать, в какой беспорядок превращается изображение без фильтрации текстур!
Такие графические API, как Direct3D, OpenGL и Vulkan, предоставляют одинаковый набор типов фильтрации, но используют для них разные названия. По сути, все они сводятся к следующему:
Здесь нам на помощь приходит линейная фильтрация. Требуемые координаты u,v тексела передаются оборудованию для сэмплирования, но вместо того, чтобы брать самый близкий к этим координатам тексел, сэмплер берёт четыре тексела. Это текселы, расположенные над, под, слева и справа от того тексела, который выбирается при помощи сэмплирования ближайших точек.
Затем эти четыре тексела смешиваются при помощи формулы с весами. В Vulkan, например, формула имеет такой вид:
T обозначает цвет тексела, где f — полученный фильтрацией, а 1-4 — цвет четырёх сэмплированных текселов. Значения альфы и беты берутся в зависимости от того, как далеко далеко точка с координатами u,v находится от середины текстуры.
К счастью для тех, кто связан с 3D-графикой, это происходит автоматически в графическом чипе. На самом деле, именно этим занимался чип TMU карты 3dfx Voodoo: он сэмплировал четыре тексела, а затем смешивал их вместе. В Direct3D этот процесс имеет странное назваине «билинейная фильтрация» (bilinear filtering), но со времён Quake и чипа TMU, графические карты уже научились выполнять билинейную фильтрацию всего за один такт (разумеется, если текстура уже расположена в ближайшей памяти).
Линейную фильтрацию можно использовать вместе с mip-текстурами, и если вы хотите усложнить фильтрацию, то можно взять четыре тексела из текстуры, а затем ещё четыре из следующего уровня mip-текстуры, смешав их все. И как же это называется в Direct3D? Трилинейная фильтрация. Откуда в этом процессе взялось «три»? Вот и мы не знаем…
Последний способ фильтрации, который стоит упомянуть — это анизотропная. На самом деле она является улучшением процесса, выполняемого при билинейной или трилинейной фильтрации. Изначально в ней выполняется вычисление степени анизотропии поверхности примитива (и это на удивление сложный процесс) — это значение увеличивает изменение соотношения сторон примитива вследствие его ориентации:
На рисунке выше показан одинаковый квадратный примитив с равными длинами сторон; но постепенно поворачиваясь, он превращается в прямоугольник, и его ширина изменяется сильнее, чем его высота. Поэтому примитив справа имеет бОльшую степень анизотропии, чем слева (а в случае квадрата степень равна нулю).
Многие современные 3D-игры позволяют включать анизотропную фильтрацию, а затем изменять её уровень (от 1x до 16x), но что это на самом деле меняет? Этот параметр управляет максимальным количеством дополнительных сэмплов текселов, которые берутся в каждом исходном линейном сэмплировании. Допустим, в игре включена анизотропная билинейная фильтрация 8x. Это означает, что вместо четырёх значений текселов она будет получать 32 значения.
Разница при использовании анизотропной фильтрации чётко заметна:
Просто поднимитесь к изображению выше и сравните сэмплирование ближайших точек с максимальной анизотропной трилинейной фильтрацией 16x. Потрясающе плавно!
Но за эту плавную красоту текстур приходится расплачиваться производительностью: при максимальных настройках анизотропная трилинейная фильтрация будет получать с текстуры для каждого пикселя рендеринга 128 сэмплов. Даже на самых лучших современных GPU этого нельзя достичь за один тактовый цикл.
Если взять, например, AMD Radeon RX 5700 XT, то каждый из блоков текстурирования внутри процессора может использовать до 32 адресов текселов за один тактовый цикл, а затем в следующем тактовом цикле загрузить 32 значения текселов из памяти (каждый из которых имеет размер 32 бита), после чего смешать четыре из них за ещё один такт. То есть для смешения 128 сэмплов текселов в один требуется не менее 16 тактовых циклов.
GPU AMD RDNA Radeon RX 5700 c 7-нанометровым техпроцессом
Если тактовая скорость 5700 XT равна 1605 МГц, то шестнадцать циклов занимают всего 10 наносекунд. Выполнение этих циклов для каждого пикселя в кадре размером 4K при использовании всего одного текстурного блока займёт всего 70 миллисекунд. Отлично, похоже, производительность не является особой проблемой!
Даже в 1996 году 3Dfx Voodoo и подобные ей карты довольно быстро справлялись с текстурами. Максимально они могли выдавать 1 тексел с билинейной фильтрацией за такт, а при частоте чипа TMU 50 МГц это означало, что за каждую секунду можно обрабатывать 50 миллионов текселов. Игре, работавшей при разрешении 800 x 600 и 30 fps, в секунду требуется только 14 миллионов текселов с билинейной фильтрацией.
Однако это справедливо только при предположении, что все текстуры находятся в ближайшей памяти и каждому пикселю соответствует только один тексел. Двадцать лет назад мысль о необходимости наложения на примитив нескольких текстур была совершенно инопланетной, но сегодня это стандарт. Давайте разберёмся, почему это всё меняет.
Добавляем освещение
Чтобы понять, почему текстурирование стало таким важным, взглянем на эту сцену из Quake:
Это тёмное изображение, ведь тьма была атмосферой игры, но мы видим, что темнота не везде одинакова — некоторые фрагменты стен и пола светлее остальных, что создаёт ощущение освещённости этих областей.
На примитивы, составляющие стены и пол, наложены одинаковые текстуры, но есть и ещё одна текстура под названием «карта освещения» (light map), смешиваемая со значениями текселов перед их наложением на пиксели кадра. Во времена Quake карты освещения вычислялись заранее и создавались игровым движком. Они применялись для генерации статических и динамических уровней освещения.
Преимущество их использования заключается в том, что сложные вычисления освещения производились с текстурами, а не с вершинами, что значительно улучшало внешний вид сцены ценой малых затрат скорости. Очевидно, что изображение неидеально: на полу заметно, что граница между освещёнными областями и тенями очень резка.
Во многих смыслах карта освещения — это просто ещё одна текстура (не забывайте, что все они являются обычными 2D-массивами данных), поэтому эта сцена является одним из первых примеров использования мультитекстурирования (multitexturing). Как понятно из названия, это процесс, при котором на примитив накладываются две или более текстур. Использование в Quake карт освещения стало способом преодоления ограничений затенения по Гуро, но в процессе увеличения набора возможностей графических карт расширялись и способы применения мультитекстурирования.
3Dfx Voodoo, как и многие другие карты той эпохи, была ограничена в объёме операций, которые она могла выполнить за один проход рендеринга. По сути, проход — это полный цикл рендеринга: от обработки вершин до растеризации кадра, а затем изменения пикселей и их записи в готовый буфер кадра. Двадцать лет назад в играх почти всегда использовался рендеринг в один проход.
Nvidia GeForce 2 Ultra, примерно конец 2000 года. Изображение: Wikimedia
Так происходило, потому что вторая обработка вершин только для наложения дополнительных текстур была слишком затратной с точки зрения производительности. Нам пришлось прождать после Voodoo пару лет, когда появились графические карты ATI Radeon и Nvidia GeForce 2, способные выполнять мультитекстурирование за один проход.
У этих GPU было несколько текстурных блоков на участке обработки пикселей (то есть в конвейере), поэтому получение тексела с билинейной фильтрацией из двух отдельных текстур становилось простейшей задачей. Это ещё больше повысило популярность карт освещения и позволило играм делать их полностью динамическими, меняя значения освещения в зависимости от условий игровой среды.
Но с несколькими текстурами можно было сделать гораздо больше, поэтому давайте изучим их возможности.
Менять высоту — это нормально
В этой серии статей про 3D-рендеринг мы не говорили о том, как роль GPU влияет на весь процесс (мы расскажем об этом, только не сейчас!). Но если вы вернётесь к части 1 и прочитаете обо всём сложном процессе обработки вершин, то можете подумать, что это самая сложная часть всей работы, которую должен выполнять графический процессор.
Долгое время так и было, и программисты игр делали всё возможное, чтобы снизить эту нагрузку. Им приходилось идти на всевозможные ухищрения, чтобы обеспечить такое же качество изображения, как при использовании множества вершин, но при этом их не обрабатывать.
В большинстве таких трюков использовались текстуры, называющиеся картами высот (height maps) и картами нормалей (normal maps). Эти два понятия связаны тем, что последние можно создавать из первых, но пока давайте рассмотрим только технику под названием «рельефное текстурирование» (bump mapping).
Изображения созданы в демо рендеринга Эмиля Перссона. Рельефное текстурирование отключено/включено
При рельефном текстурировании используется 2D-массив под названием «карта высот» (height map), которая выглядит как странная версия исходной текстуры. Например, на показанном выше изображении показана реалистичная кирпичная текстура, наложенная на две плоские поверхности. Текстура и её карта высот выглядят вот так:
Цвета карты высот обозначают нормали поверхности кирпичей (о нормалях мы рассказывали в части 1 серии статей). Когда процесс рендеринга доходит до этапа наложения кирпичной текстуры на поверхность, выполняется ряд вычислений для изменения цвета кирпичной текстуры на основании её нормалей.
В результате этого сами кирпичи выглядят более трёхмерными, несмотря на то, что продолжают оставаться совершенно плоскими. Если посмотреть внимательно, особенно на края кирпичей, то можно увидеть ограничения этой техники: текстура выглядит слегка искажённой. Но это быстрый трюк, позволяющий добавить больше деталей поверхности, поэтому рельефное текстурирование очень популярно.
Карта нормалей похожа на карту высот, только цвета текстуры являются самими нормалями. Другими словами, вычисления для преобразования карты высот в нормали не требуются. Вы можете задать вопрос: как цветами можно описать вектор в пространстве? Ответ прост: каждый тексел имеет набор значений r,g,b (красный, зелёный, синий) и эти значения напрямую соответствуют значениям x,y,z вектора нормали.
На левой схеме показано изменение направления нормалей на неровной поверхности. Чтобы описать те же нормали плоской текстурой (средняя схема), мы назначаем им цвета. В данном случае мы использовали значения r,g,b (0,255,0) для вектора, направленного прямо вверх, а затем увеличили значение красного для наклона влево, и синего — для наклона вправо.
Учтите, что этот цвет не смешивается с исходным пикселем, он просто сообщает процессору, в каком направлении указывает нормаль, чтобы тот мог правильно рассчитать углы между камерой, источниками освещения и текстурируемой поверхностью.
Преимущества рельефного текстурирования и карт нормалей в полную силу проявляются при использовании в сцене динамического освещения, и когда процесс рендеринга вычисляет влияние изменения освещения попиксельно, а не для каждой вершины. Сегодня современные игры используют набор текстур для улучшения качества выполнения этого трюка.
Удивительно, но эта реалистично выглядящая стена — всего лишь плоская поверхность, детали кирпичей и цемента кладки не выполнены с помощью миллионов полигонов. Вместо них достаточно всего пяти текстур и продуманного использования вычислений.
Карта высот была использована для генерации отбрасывания теней кирпичами, а карта нормалей — для симуляции всех незначительных изменений в поверхности. Текстура шероховатости (roughness texture) использовалась для изменения способа отражения света от различных элементов стены (например, гладкий кирпич отражает свет более равномерно, чем шероховатый цемент).
Последняя карта, названная на изображении AO, создаёт часть процесса, называемую ambient occlusion: подробнее мы рассмотрим эту технику в следующих статьях, а пока скажем, что она помогает повысить реализм теней.
Наложение текстур — важнейший процесс
Текстурирование совершенно необходимо при разработке игр. Возьмём для примера игру 2019 года Kingdom Come: Deliverance — RPG от первого лица, действие которой происходит в Богемии в 15-м веке. Дизайнеры стремились создать как можно более реалистичный мир того периода. А чтобы погрузить игрока в жизнь, которая была сотни лет назад, лучше всего реализовать исторически достоверный ландшафт, здания, одежду, причёски, повседневные предметы, и многое другое.
Каждая текстура в этом изображении из игры была вручную создана художниками, а также с благодаря контролируемому программистами движку рендеринга. Некоторые из них мелкие, с простыми деталями, и поэтому подвергаются незначительной фильтрации или обработке другими текстурами (например, куриные крылышки).
Другие имеют высокое разрешение и отличаются множеством мелких деталей; они подвергаются анизотропной фильтрации и смешению с картами нормалей и другими текстурами — достаточно посмотреть на лицо человека на переднем плане. Разница в требованиях к текстурированию каждого объекта сцены учитывается программистами.
Всё это происходит сегодня во многих играх, потому что игроки ожидают всё более высоких степеней детализации и реализма. Текстуры становятся крупнее, и всё большее их количество накладывается на поверхности, но сам процесс сэмплирования текселов и наложения их на пиксели по сути остаётся тем же, что и во времена Quake. Лучшие технологии никогда не умирают, сколько бы лет им ни было!