Any3DAny3D
·Any3D Team

KTX2 на практике: правильный путь сжатия текстур

3d-compressiontexture-compressionktx2basis-universalgltf

Предыдущая статья разобрала форматы текстур GPU, Basis Universal и KTX2. Теория понятна; эта статья — полностью практическая: как выбирать между ETC1S и UASTC, какие инструменты использовать, какие команды вводить и как загружать их в движке.

Вы можете следовать инструкциям и выполнять шаги по мере чтения.

Первое и самое важное: ETC1S или UASTC

Basis предлагает два режима промежуточного кодирования. Выберите неправильно — и проблема будет не в «недостаточном качестве», а в том, что ваша карта нормалей превратится в кашу. Запомните эту таблицу:

ETC1SUASTC
Коэффициент сжатияОчень высокий (аналог JPG)Средний (качественный, аналог PNG)
КачествоПодходит для цветовых картПочти оригинальное качество
VRAM (после транскодирования)Обычно 4bpp (~1/8 оригинала)Обычно 8bpp (~1/4 оригинала)
Скорость кодированияМедленная (настраиваемый уровень)Быстрее
Использовать дляальбедо/диффузия, эмиссиянормали, металличность-шероховатость, данные
Не использовать длянормали, изображения, требующие точных значенийЦветовые карты (избыточно, размер растёт)

Почему карты нормалей нельзя использовать с ETC1S? Потому что карта нормалей хранит векторы направлений, и RGB-каналы каждого пикселя взаимно ограничивают друг друга (длина вектора ≈ 1). ETC1S — блочное сжатие, разработанное для того, чтобы «цвета выглядели правильно»; оно не чувствительно к точности отдельных каналов, поэтому после сжатия направление вектора «уходит», и освещение сразу выглядит неправильно — особенно позиции бликов и высокочастотные детали. UASTC лучше сохраняет числовые значения и выдерживает требования к точности.

Практические правила:

  • Цветовые карты (альбедо, эмиссия) → ETC1S
  • Карты данных (нормали, шероховатость, металличность, AO, толщина) → UASTC
  • Не уверены, но хотите сэкономить размер → попробуйте сначала ETC1S; если при приближении становится размытым, переключитесь на UASTC

Одно изображение, четыре формата для сравнения

В качестве эталона используется карта альбедо 2048x2048 (значения взяты из типичных community-данных, только для справки):

ФорматРазмер на дискеИспользование VRAM (с мипмапами)Загрузка в GPUКроссплатформенность
PNG~5 МБ~22 МБМедленная
WebP~1 МБ~22 МБМедленная
KTX2 (ETC1S)~0.5-0.8 МБ~2.8 МББыстрая
KTX2 (UASTC)~3-4 МБ~5.6 МББыстрая

Обратите внимание: использование VRAM у WebP такое же, как у PNG — он только маленький на диске; в VRAM он всё равно распаковывается в сырые пиксели. KTX2 с ETC1S одновременно снижает и размер на диске, и VRAM — именно в этом его ценность.

Инструменты: три дороги ведут к одной цели

Для сжатия KTX2 существует несколько инструментов, упорядоченных по «простоте получения»:

1. toktx (официальный, самый мощный)

Официальный инструмент Khronos, с наибольшим количеством параметров, подходит для обработки текстур по отдельности.

# Конвертировать PNG в KTX2 с кодировкой ETC1S
toktx --bcmp --uastc 0 albedo.ktx2 albedo.png

# Конвертировать PNG в KTX2 с кодировкой UASTC
toktx --uastc 1 normal.ktx2 normal.png

Основные параметры:

# ETC1S + уровень качества (1-255, по умолчанию 128; больше = лучше качество и больший размер)
toktx --bcmp --uastc 0 --qlevel 200 albedo.ktx2 albedo.png

# UASTC + суперсжатие (Zstandard, дополнительно уменьшает размер на диске)
toktx --uastc 1 --zcmp 19 normal.ktx2 normal.png

# Автоматическая генерация мипмап (настоятельно рекомендуется)
toktx --bcmp --genmipmap albedo.ktx2 albedo.png

# Указание цветового пространства sRGB (обязательно для цветовых карт)
toktx --bcmp --srgb albedo.ktx2 albedo.png

--bcmp — ключ режима ETC1S (базовый режим Basis Universal), а --uastc 1 — режим UASTC. Оба взаимоисключающие.

2. gltf-transform (самый простой, настоятельно рекомендуется)

Если у вас есть целая модель glTF/GLB, используйте gltf-transform, чтобы заменить все её текстуры на KTX2 одной командой, автоматически выбирая ETC1S/UASTC по назначению текстуры.

# Установка
npm install -g @gltf-transform/cli

# Однократное сжатие всей модели
gltf-transform optimize model.glb model-optimized.glb \
  --texture-compress basisu

Он внутренне определяет назначение текстуры: цветовые типы используют ETC1S, типы данных — UASTC, и автоматически записывает расширение KHR_texture_basisu. Это лучший выбор для 90% случаев — не нужно набирать toktx по одному вручную.

3. Онлайн-инструменты (самый быстрый старт)

Когда не хочется настраивать окружение, используйте браузерные инструменты: gltf.report (онлайн gltf-transform), KTX2 Converter и т.д. Загрузите, скачайте, готово. Подходит для начальных экспериментов или разовых задач.

Полный конвейер: от исходника до продакшена

Вот стандартный поток (схема):

Исходный файл (PNG/JPG/PSD/TGA)
        │
        ├── [целая модель] gltf-transform optimize model.glb → автоопределение типа текстуры
        │            └─ цветовые карты → ETC1S
        │            └─ карты данных → UASTC
        │            └─ запись расширения KHR_texture_basisu
        │
        └── [одна текстура] toktx → ручное указание ETC1S/UASTC + цветовое пространство + мипмапы
        │
        ▼
Сжатый KTX2 / GLB
        │
        ▼
Загрузка в движок (Three.js / Babylon.js) ── транскодирование на лету → нативный формат GPU

Загрузка KTX2 в Three.js

Three.js поддерживает KTX2 нативно с версии r129. Подключите KTX2Loader — указывающий на basis-transcoder wasm и проверяющий поддержку GPU — к GLTFLoader; любой glTF с текстурами KTX2 затем автоматически транскодируется при загрузке.

const ktx2Loader = new KTX2Loader().setTranscoderPath("/basis/").detectSupport(renderer);
gltfLoader.setKTX2Loader(ktx2Loader); // также подключите DRACOLoader / MeshoptDecoder, если модель их использует

detectSupport(renderer) обязателен — он определяет, в какой нативный формат транскодировать. А для цветовых карт установите texture.colorSpace = THREE.SRGBColorSpace; пропуск этого шага — классическая ошибка «всё выглядит серым» (карты данных, такие как нормали/шероховатость, остаются в линейном пространстве).

Загрузка KTX2 в Babylon.js

В Babylon ещё проще — GLTFFileLoader по умолчанию включает KHR_texture_basisu и автоматически загружает basis-transcoder с CDN, поэтому glTF с текстурами KTX2 просто работает. Для офлайн/внутрисетевых сред вручную настройте BASISFileLoader.TranscoderModule.

Настройка параметров сжатия: баланс между качеством и размером

Основной параметр ETC1S — --qlevel (1-255). Как он влияет на результат:

qlevelРазмерКачествоВремя кодированияПрименение
128 (по умолчанию)МаленькийДостаточноеСреднееБольшинство случаев
200-255Бо́льшийПочти без потерьДлинное (в несколько раз)Высокие требования к качеству
60-100Очень маленькийВидимые блочные артефактыБыстроеДалёкие/маленькие текстуры

Размер UASTC относительно фиксирован; настройка размера на диске в основном осуществляется через --zcmp (суперсжатие Zstandard), которое не влияет на VRAM (после распаковки всё равно 8bpp).

Рекомендуемый порядок настройки:

  1. Сначала сожмите один раз с настройками по умолчанию и проверьте размер и качество
  2. Не устраивает → настройте --qlevel (ETC1S) или добавьте --zcmp (UASTC)
  3. Карта нормалей стала размытой → убедитесь, что используется UASTC, а не ETC1S
  4. Цвета кажутся тёмными → проверьте настройки цветового пространства (флаг sRGB, colorSpace в движке)

Типичные проблемы и их решение

Ошибка транскодирования / ошибка загрузки

  • Проверьте, что путь к wasm транскодера корректен (Three.js требует setTranscoderPath)
  • Проверьте, поддерживает ли ваша версия движка текущую версию KTX2 (старые кодировки Basis не поддерживаются новыми транскодерами)
  • В консоли обычно есть конкретная ошибка; ищите по ключевым словам

Цвета слишком тёмные / слишком светлые

  • Цветовая карта (альбедо) не была установлена в sRGB или установлена наоборот
  • Вы забыли указать --srgb в toktx (цветовые карты требуют его)
  • Карта данных (нормали) по ошибке получила sRGB

Отсутствуют мипмапы, мерцание на расстоянии

  • При сжатии не добавлен --genmipmap
  • Движок не включил texture.generateMipmaps (в Three.js KTX2 следует файлу по умолчанию, но minFilter материала всё равно требует режим мипмап)

Неправильное направление нормалей при приближении

  • Карта нормалей использовала ETC1S; переключитесь на UASTC
  • Убедитесь, что карта нормалей в стиле OpenGL (зелёный канал вверх); стиль DirectX требует инвертирования канала G в некоторых движках

Файл стал больше вместо уменьшения

  • Маленькие текстуры (< 128x128) не стоят KTX2 — блочное сжатие имеет фиксированный overhead и заполняет целый блок
  • Не используйте KTX2 для текстуры сплошного цвета; значение цвета материала будет дешевле

Что дальше

Это в целом закрывает тему сжатия текстур. Но «знать, как пользоваться инструментами» — это не одно и то же, что «использовать правильные инструменты». Следующая статья свяжет все знания из предыдущих четырёх в единую рамку выбора: десктоп, мобильные, VR, Mini Programs — какая комбинация подходит каждому сценарию.

Поддержите нас