Сжатие текстур, часть III. BPTC

Продолжение серии постов о сжатых текстурных форматах (часть I, часть II).

BPTC (BC6, BC7)

Block Partition Texture Compression

BPTC является частью ядра OpenGL начиная с версии 4.2. Обеспечивает лучшее качество по сравнению с семейством S3TC, при этом у него хорошая поддержка на десктопных платформах. У формата есть есть две разновидности: BC6 и BC7 (в обозначении DXGI).

BC7 используется для сжатия беззнаковых нормализованных изображений (то есть, обычных изображений глубиной цвета 8 бит на канал). Блок 4×4 преобразуется в 128 бит. Принцип сжатия во многом аналогичен S3TC – хранятся начальный и конечный пороговые цвета (endpoints), вместо пикселей сохраняются индексы интерполированных значений между ними. Отличие в том, что BPTC может хранить отдельные градиенты для каждого канала, подобно тому, как DXT5 разделяет цвет и альфу. BPTC поддерживает гибкий механизм группировки каналов: каждый блок может использовать один из 7 разных режимов группировки.

BC7 кодирует изображения с альфа-каналом. У него есть две версии – в линейном (GL_COMPRESSED_RGBA_BPTC_UNORM_ARB) и гамма-пространстве (GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB). Они математически эквивалентны, различие существует лишь для удобства интерпретации данных в приложениях (то есть, сэмплы из sRGB-текстур нужно, как обычно, переводить в линейное пространство перед тем, как использовать в каких-либо вычислениях).

BC6 (BPTC_FLOAT) – самый распространенный на сегодняшний день (и единственный на большинстве платформ) формат сжатия для HDR-изображений. Формат кодирует числа с плавающей запятой и не поддерживает альфа-канал. Первый endpoint хранится с высокой точностью, второй представляет собой смещение относительно первого, хранящееся с низкой точностью.

BC6 существует в двух версиях – COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB и COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB, которые, соответственно, кодируют знаковые и беззнаковые значения.

Сжатие текстур, часть II. RGTC

Продолжение серии постов о сжатых текстурных форматах. Первая часть тут.

RGTC (BC4, BC5)

Red Green Texture Compression

Формат сжатия для 1- и 2-канальных изображений – условно “красных” и “красно-зеленых”.

BC4 предназначен для хранения монохромных изображений (не обязательно красных, разумеется). Формат использует 64 бита на блок 4×4. Endpoint’ы хранятся в виде 8-битных значений, из них создается 6 промежуточных значений. Индексы пикселей 3-битные. Преимущество BC4 – значительно более высокое качество при хранении монохромных текстур, чем при использовании BC1. Это делает формат самым подходящим выбором для карт высот и различных нецветовых данных, таких как шероховатость и металличность. Качество градиентов почти неотличимо на глаз от несжатого оригинала.

BC5 хранит двухканальные изображения, условно называемые “красно-зелеными”. Принцип сжатия аналогичен BC4, только в данном случае каждый блок 4×4 описывается двумя каналами по 64 бита каждый, при этом красный и зеленый каналы сжимаются независимо друг от друга. В BC5 удобно хранить, например, совмещенные текстуры шероховатости и металличности.

Стандарт RGTC определяет текстуры со знаком и беззнаковые. Они полностью идентичны, разница лишь в том, что формат со знаком кодирует значения от -128 до 127, а не от 0 до 255. Для формата со знаком действует правило: если первый endpoint равен -127, второй не должен быть -128.

Сжатие текстур, часть I. S3TC

Я как-то обещал написать пост с подробным разбором всех форматов сжатия текстур и соответствующего инструментария – и вот, наконец, начинаю публиковать частями. Сегодня рассмотрим один из старейших и самых популярных – S3TC (DXTn).

Тот или иной способ сжатия сегодня используется почти во всех стандартных графических форматах. Однако такие форматы, как PNG или JPEG, хотя и сжимают весьма эффективно, для текстур в видеопамяти не годятся – они предназначены для хранения на диске и передачи по сети. В качестве текстур их можно использовать только после декомпрессии. Для хранения текстур в сжатом виде были созданы специализированные форматы, которые позволяют считывать пиксели на лету, без полной декомпрессии данных.

(далее…)

Hald CLUT

В Dagon появилась поддержка 3D-текстур, что позволило реализовать цветокоррекцию с использованием цветовых таблиц формата Hald CLUT. CLUT расшифровывается как color lookup table – таблица поиска цвета: в памяти хранится текстура, в которой стандартным цветам sRGB сопоставлены какие-то другие цвета – вместо оригинальных цветов пикселей на вывод идут значения, прочитанные из 3D-таблицы. Принцип примерно тот же, что использовался в индексированных цветовых режимах, только в данном случае таблица охватывает более широкий диапазон RGB. Чаще всего CLUT используется для имитации характерной «пленочной» цветовой гаммы на цифровых снимках, но ее возможности гораздо шире. В таблице цвета могут быть абсолютно любые – с математической точки зрения, она является функцией, которая переносит цвет из одного пространства в другое. Чем больше таблица, тем точнее ее охват.

Оргинал таблицы в формате Hald CLUT выглядит следующим образом (PNG можно скачать тут):

Если отредактировать это изображение в графическом редакторе – например, изменить яркость, контраст, насыщенность и т. д. – результат будет хранить информацию, необходимую для того, чтобы повторить эти же операции на другом изображении. Единственное условие: цветокоррекция должна выполняться для каждого пикселя параллельно и независимо от остальных. Если фильтр использует оконную свертку и другие алгоритмы, работающие с несколькими пикселями одновременно, то метод с использованием CLUT не будет с ним работать.

Преимущество Hald CLUT состоит в эффективном расположении значений – таблица размером 4096×4096 охватывает весь 24-битный диапазон sRGB (16777216 цветов) и при этом отлично сжимается в PNG. Для хранения таблицы важно использовать lossless-формат, так как сжатие с потерями вносит мелкие искажения в цвета, а в данном случае важно сохранить точность информации.

Еще одна немаловажная фича формата – прямая совместимость с 3D-текстурами OpenGL. Достаточно просто декодировать картинку в буфер RGB и создать из этого буфера текстуру функцией glTexImage3D – никаких промежуточных конвертаций не требуется. Эта текстура затем передается в шейдер постобработки, который выглядит совсем элементарно:

vec3 inputColor = texture(colorBuffer, texCoord).rgb;
vec3 outputColor = texture(lookupTable, inputColor).rgb;

В Dagon поддержка создания 3D-текстуры из двумерного буфера встроена в класс Texture. Нужно загрузить таблицу как ассет ImageAsset, создать текстуру и проинициализировать ее методом createHaldCLUT. Результат передается в стандартный стек постобработки (game.postProcessingRenderer):

ImageAsset aCLUT;

override void beforeLoad()
{
    aCLUT = addImageAsset("data/food.png");
}

override void afterLoad()
{
    Texture clut = New!Texture(assetManager);
    clut.createHaldCLUT(aCLUT.image, 256);
    game.postProcessingRenderer.colorLookupTable = clut;
    game.postProcessingRenderer.lutEnabled = true;
}

Поддерживаются таблицы любых разрешений, но вы должны сами правильно вычислить размер 3D-текстуры, соответствующей вашей CLUT. Например, для таблицы 4096×4096 это будет 256x256x256, как в моем примере. Если в этот параметр передать неправильное значение, то будет построена некорректная текстура (в релизе обязательно добавлю валидацию).

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

PBR-текстуры при помощи нейросети

Обнаружил интересную ESRGAN-модель Material Map Generator, которая генерирует карты нормалей и шероховатости из фототекстур. Работает довольно быстро и показывает весьма качественные результаты – у меня, например, из картинки с ракушками получилось вот такое:

Канал G пришлось инвертировать для совместимости с Blender, а диффузную текстуру я сделал с помощью утилиты Agisoft De-Lighter – тоже, кстати, очень полезный инструмент.

Для запуска нужен Python с установленными numpy, opencv-python и torch.