Ключевые слова
BC1,BC2, BC3, BC4, BC4u, BC4s, BC5, BC5s, BC5u, BC6H, BC7, DDS, S3TC, DXTC, ASTC, DXT1, DXT2, DXT3, DXT4, DXT5, DXT5u, pre multiplied alpha, преумноженная альфа, текстурное сжатие, алгоритмы текстурного сжатия, UNORM, SNORM, текстуры, pvr.
Ааннотация
В статье подробно разбирается алгоритмы сжатия текстур S3TC(DXTC/ВС) и ASTC на примере проектов «Леста Игры»: алгоритмы сжатия, форматы, артефакты, особенности, строение и сравнения.
ВведениеТекстуры, за редким исключением, это всегда бОльшая часть места, занимаемого игрой. К примеру, в клиенте «Мира Танков» текстуры занимают более половины от общего объёма.Проблема сжатия графических данных игр для хранения и отображения появилась вместе с играми. Это важная работа по оптимизации контента необходима как для хранения игры на носителе, так и для вывода его на экран. Иными словами, вопрос о грамотном использовании места для хранения данных стоял всегда, и разработчики шли на разные ухищрения что бы сэкономить (см. рис. 1).
Рисунок 1. Darkwing Duck (1993) от Capcom на NES.
Весь задний состоит из ограниченного набора тайлов 8х8 пикселей, что позволяет экономить место на картридже.
Причины сжимать текстуры
- Итоговый объём дистрибутива/игры будет меньше, это означает что будет меньше проблем с распространением.
- Оптимизация самой игры – повышение быстродействия, снижения характеристик машин для комфортной игры, что в свою очередь увеличивает охват аудитории.
- Снижение трафика между графическим процессором и памятью – уменьшение энергопотребления и температуры устройства, это особенно критично для ноутбуков и телефонов.
Специфика применения использования текстур в играх
Одно из главных требований к алгоритму сжатия текстуры является возможность доступа к произвольному участку текстуры без распаковки всего файла. Это связано со спецификой рендеринга кадра и архитектурой видеокарт. В видеопамяти текстура хранится в сжатом виде,
поскольку занимает много места, а нужна она целиком далеко не всегда. Более того в процессе построения кадра на 1 пиксель экрана может приходится несколько полигонов замапанных в разные участки текстуры (см. рис.2).
Рисунок 2. Обратите внимание, что для отрисовки триплекса используются пиксели текстуры, разбросанные по всей площади квадрата.
Стоит отметить, что в большинстве современных игр используются сложные шейдеры, работающие сразу с комплектом текстур, что делает невозможность их хранения в несжатом виде в видеопамяти в силу их большого размера (см. рис. 3).
Рисунок 3. Набор текстур для танка. Показаны только основные. В среднем на 1 танк приходится около 35 текстур.
Помимо многократных запросов на одни и те же участки текстур объекта, запросы могут быть и в разные места в случае, если объект имеет несколько US-set (см. рис. 4).
Рисунок 4. На данной модели применяется 2 UV сета для смешения двух текстур: одна — тайловая с тримами кирпичной стены и бетона, вторая — уникальная с грязью.
Таким образом у нас сформировалось одно из главных требований: произвольный доступ к любому участку текстуры без распаковки всей текстуры. В алгоритмах сжатия, о которых мы поговорим в этой статье, для решения этой задачи используется общий принцип – разбиение текстуры на блоки и сжатие их порознь, но по одним правилам.
Семейство S3TC
Разработан компанией S3 Graphic, сокращение от S3 Graphic Texture Compression. Наиболее распространённый алгоритм сжатия текстур. Появился в конце 90х. Поскольку вошёл в API DirectX c 6 версии также именуется какDXTC (DirectX Texture Compression), с 10ой версии именуется BC (Block Compression). Формат файлов по умолчанию: *.dds.
Основная идея сжатия – разбиение текстуры на блоки фиксированного размера 4х4 пикселя с последующим пожатием каждого блока. При на каждый блок отводится одинаковое количество бит, даже если он весь заполнен одним цветом. Ещё важная особенность: каждый сжатый блок самостоятелен, а это значит, что его можно распаковать без распаковки всей текстуры. В семействе на данный момент существует 7 представителей. Поскольку в DirectX10 набор был переработан и переназван, то в статье новые и старые названия приводятся вместе. Далее разберём каждый алгоритм в отдельности.
Схематично сжатый файл представлен на рисунке 5.
Рисунок 5. Схематическое представление структуры фала dds.
В начале файла есть заголовок фиксированной длинны. В нём содержаться основные сведения о файле – высота, ширина, алгоритм сжатия, формат пикселя и остальные. На каждую запись отводится одно DWORD – 32 бита.
Суммарно на заголовок выделено 124 байта, причём есть пустые dword которые можно использовать по своему усмотрению и записывать техническую информацию. К примеру, на проекте «Мир кораблей» в пустых dword текстур хранится информация о текстуре источнике: при экспорте корабля/объекта экспортёр сравнивает исходник и сжатую текстуру для определения их идентичности, после его принимает решение конвертировать текстуру заново или это не имеет смысла (текстура не менялась). Всего пустот 6:
- dwReserved11(3 шт.)
- dwCaps3
- dwCaps4
- dwReserved2
После заголовка идут блоки основного изображения. Онитоже фиксированной длинны: 64 или 128 килобит в зависимости от алгоритма.
Причём даже если блок полностью чёрный, то его длинна будет равна блоку с любым изображением.
После блоков основного изображения идут мипы. Это уменьшенное изображение оригинальной текстуры (см. рис. 6)
Рисунок 6. Визуальное представление графическим редактором основного изображения и его мипов. Пустые чёрные блоки – не пустоты в файле, а особенность отображения технологии редактором.
Мипы используются так же как и лоды – чем дальше до камеры тем мельче мип используется. Они подменяют основную текстуру на лету. Это
хорошо видно на рисунке 7.
Рисунок 7. синий цвет – основное изображение, зелёный и жёлтый – 1 и 2 мипы соответственно.
DXT1 (BC1)
Во многом это базовый алгоритм для семейства. В каждом сжатом блоке весом по 64 бита есть по 4 цвета: 2 крайних цвета (рис. 4) и восстановленных (интерполированных):
Рисунок 8. кодировка крайних цветов.
На крайние цвета отводится по 16 бит, которые неровно поделены между каналами – на зелёный отводится на 1 бит больше, чем на остальные. Это означает в 2 раза больший диапазон цветов чем в синем или красном: 64 градации против 32. Кстати именно по этой причине получить 127 серый после распаковки не получится – он будет либо с зеленцой либо с фиолетовым.Ещё 2 не хранятся в явном виде, они восстанавливаются смешиванием крайних цветов в разных пропорциях.
Полученные 4 цвета кодируются в таблицу индексов, на которую тоже отведено 32 бита (рис. 9).
Рисунок 9 кодировка крайних цветов
Кроме того данный алгоритм поддерживает 1 битную альфа-карту (прозрачно/непрозрачно). В таком случае цвет 01 считается прозрачным, цвет 10 восстанавливается смешиванием крайних цветов в равных пропорциях, а на 1 блок фактически будет приходится только 3 цвета.
Из-за ограничения в 4 цвета на блок, хороший результат алгоритм может дать не всегда. К примеру блоки с большим количеством контрастных цветовпожмутся с большими потерями:
Рисунок 10. Слева исходный блок, справа уже в сжатом виде.Как видите получилось не очень.
Однако если жать не эксцентричные примеры, а реальные текстуры (к примеру альбедо), то результат будет незаметендля невооруженного глаза (рис. 11).
Рисунок 11. При сжатии альбедо текстуры танка потери в качестве в глаза не бросаются.
Однако при попытке пожать нормал с контрастными цветами качество будет низким, что повлечёт артефакты в игре:
Рисунок 12. Фрагмент нормал мапы линкора.
Слева исходник, справа пожатая ткестура в DXT1.Это критично если мы говорим о нормал мапе с множеством контрастных мест и плавных переходов. Однако эту проблему можно скрыть фактурой в других текстурах.
Рисунок 13. Слева нормал мапа с артефактами от сжатия, справа то как это выглядит с остальными текстурами.
Сейчас на проекте для нормал мапы используются более совершенные алгоритмы сжатия (ВС7), поэтому артефакты в нормале сведены к минимуму.
Рисунок 14. Та же текстура, но сжатая алгоритмом ВС7.
В плюс DXT1 (BC1) можно поставить размер файлов: исходники комплекта текстур на линкор весят около 300 мегабайт, а в пожатом виде всего 65.
Несмотря на большой возраст алгоритм находит применение и сейчас поскольку имеет высокую степень сжатия при приемлемых потерях и артефактах. К примеру, на проекте «Мир танков» все альбедо текстуры танков жмутся этим алгоритмом. Так же он хорошо подходит для хранения RGB текстуры без альфа-канала, но плохо для хранения нормал мапа из-за влияния каналов друг на друга и высокой степени сжатия.
Продолжение будет в следующем посте.