Сжатие текстур, часть I. S3TC
Я как-то обещал написать пост с подробным разбором всех форматов сжатия текстур и соответствующего инструментария – и вот, наконец, начинаю публиковать частями. Сегодня рассмотрим один из старейших и самых популярных – S3TC (DXTn).
Тот или иной способ сжатия сегодня используется почти во всех стандартных графических форматах. Однако такие форматы, как PNG или JPEG, хотя и сжимают весьма эффективно, для текстур в видеопамяти не годятся – они предназначены для хранения на диске и передачи по сети. В качестве текстур их можно использовать только после декомпрессии. Для хранения текстур в сжатом виде были созданы специализированные форматы, которые позволяют считывать пиксели на лету, без полной декомпрессии данных.
Памятка о сокращенных обозначениях: традиционно все форматы сжатия текстур обозначаются двумя аббревиатурами. Первая – сокращение полного названия алгоритма, второе – обозначение в стиле DirectX Graphics Infrastructure: BCn, где n – число. BC означает “block compression”, поскольку все форматы BCn оперируют блоками по 4×4 пикселей. Размер каждого блока фиксированный – 64 или 128 бит. Размер блока – важная характеристика формата, поскольку, не зная его, вы не сможете правильно прочитать мип-уровни текстуры из DDS.
Разбиение на блоки необходимо для оптимизации считывания на GPU: вместо того, чтобы считывать пиксели последовательно, как это делают потоковые форматы сжатия, TMU сначала вычисляет смещение блока, в котором находится нужный пиксель, и декодирует только этот блок. Полученные 16 пикселей помещаются в текстурный кэш, и последующие операции считывания из этого блока уже не требуют повторного декодирования, что делает всю процедуру весьма эффективной.
Блочное сжатие основано на идее “ограниченной цветовой вариативности”: как правило, в отдельно взятом блоке 4×4 не очень много разных цветов. Это похоже на индексированные цветовые форматы (8-битные картинки с палитрой), которые были популярны в раннем вебе. Только тут у каждого блока пикселей палитра своя, и хранится она в виде параметров функции-интерполятора – кодируются только начальный и конечный цвета (так называемые endpoints или color_0 и color_1 в документации Microsoft), а остальные вычисляются уже при чтении – как промежуточные на этом отрезке. Поэтому такие форматы лучше всего себя показывают на текстурах без резких цветовых переходов. Строго говоря, цвета в блоке в идеале должны располагаться на одной прямой в пространстве RGB: если в одном блоке присутствуют, например, красный, зеленый и синий цвета одновременно, то качество текстуры заметно пострадает.
Наверное, не лишним будет оговориться, что сжатые текстуры предназначены только для чтения. Записывать в них GPU, естественно, не может, так как запись в данном случае не может быть распараллелена попиксельно.
S3TC (BC1, BC2, BC3)
S3 Texture Compression, также DirectX Texture Compression (DXTC)
Семейство форматов текстур DirectX, чаще всего используемых в контейнере DDS. Свое название получило от ныне малоизвестной компании S3 Graphics, которая занималась производством чипов для видеокарт. К S3TC относятся самые распространенные форматы сжатия, используемые в играх, так как DDS с незапамятных пор поддерживается многими популярными игровыми движками. Несмотря на устоявшуюся ассоциацию с DirectX, эти форматы полноценно поддерживаются и в OpenGL.
Все форматы семейства S3TC кодируют цвет одинаково, различаясь лишь способом кодирования альфа-канала. Существует не менее 5 разновидностей S3TC, но обычно используются следующие:
DXT1 (BC1) – обеспечивает самое сильное сжатие. Блок 4×4 преобразуется в 64 бита. Палитра блока хранится в виде двух 16-битных значений в формате RGB 5:6:5 – то есть, 5 бит на красный канал, 6 бит на зеленый, 5 бит на синий. Значения пикселей хранятся в виде 2-битных индексов. Низкая точность endpoint’ов приводит к тому, что этот формат не очень качественно сжимает градиенты, но для обычных цветовых текстур, где градиентов нет, до сих пор является одним из самых подходящих.
DXT1 не поддерживает полноценный альфа-канал, однако может помечать некоторые пиксели как полностью прозрачные, поэтому в этом формате можно хранить, например, текстуры решеток, сеток, листьев и т.д. – то есть, любые текстуры, для которых ваш движок использует alpha cutout. Для этого используется хитрый трюк с порядком хранения данных: если первый endpoint численно больше второго, то цвета хранятся как обычно. В противном случае палитра хранит три непрозрачных цвета, а четвертый считается черным и прозрачным. Таким образом, использование прозрачности приводит к уменьшению цветовой точности в блоке, но чаще всего это не критично – ведь это касается только блоков по краям изображения.
DXT3 (BC2) – блок 4×4 преобразуется в 128 бит: 64 бита под цвет и 64 бита под альфа-канал. Цветовые данные хранятся точно так же, как и в DXT1. Значения альфа хранятся в виде 4 бит на пиксель, без сжатия. Таким образом, DXT3 – это просто расширение DXT1, которое используется в текстурах с полупрозрачностью. Низкая точность альфа-канала, впрочем, не позволяет хранить в этом формате качественные градиенты прозрачности.
DXT5 (BC3) – блок 4×4 преобразуется в 128 бит: 64 бита под цвет и 64 бита под альфа-канал. Цветовые данные хранятся точно так же, как и в DXT1. Для хранения прозрачности используется метод, аналогичный сжатию цвета: два граничных значения альфа на блок. Если первый endpoint больше второго, создается 6 промежуточных значений альфа и два особых значения 0 и 1, в противном случае – 8 промежуточных значений. Значения альфа для пикселей хранятся в виде 3-битных индексов. Эта разновидность формата лучше всех подходит для текстур с плавной прозрачностью.
Есть также редко встречающиеся DXT2 и DXT4 – они аналогичны DXT3 и DXT5, соответственно, отличаясь только тем, что приложение должно интерпретировать цвет как уже умноженный на альфу (premultiplied alpha).
Примечание: текстуры в форматах S3TC могут отличаться по качеству в зависимости от алгоритмов, используемых кодировщиками. Ведь отобразить 16 цветов в точки на отрезке можно по-разному – что называется, “в лоб”, или как-то умнее, адаптивно. Есть мнение, что лучшее соотношение времени работы и качества результата показывает NVIDIA Texture Tools.