Kris

От Blender до продакшена: сквозное сжатие на практике

3D-сжатиеКонвейерСжатие текстурСжатие вершинglTF

В этой серии мы уже разобрали инструменты, принципы и критерии выбора. В финальной статье соберём всё в работающий конвейер: возьмём реальную модель из Blender, будем сжимать её шаг за шагом, фиксируя изменения размера файла, видеопамяти и времени загрузки, и посмотрим, удастся ли превратить «толстяка» на 50 МБ в модель на 5 МБ, которая мгновенно открывается на телефоне.

Для кого: вы прочитали предыдущие 5 статей и готовы применять на практике. Здесь не будет новой теории — только готовые команды, скрипты и воспроизводимый процесс.

Отправная точка: реальная PBR-модель

Возьмём типичную модель для витрины интернет-магазина: высокополигональный продукт с полным набором PBR-текстур.

Исходные показателиЗначение
Исходник Blender~120 МБ (включая неэкспортированную высокополигональную модель)
Экспорт в GLB (float32 + PNG)~50 МБ
Количество вершин~180 000
Текстуры6 × 4096×4096 (albedo, normal, roughness, metallic, AO, emissive)
Видеопамять (все 6 в распакованном виде)~520 МБ
Цельфайл ≤ 5 МБ, контролируемая видеопамять, мгновенный запуск на мобильных

Файл на 50 МБ и 520 МБ видеопамяти — такая модель гарантированно уронит мобильное устройство. Разбираем по шагам.

Шаг 0: правильный экспорт из Blender

Первый рубеж сжатия — это экспорт. Многие теряют здесь кучу времени и размера.

Ключевые настройки экспорта glTF из Blender:

  • Формат: glTF Binary (.glb) (один файл, удобно передавать)
  • Геометрия: включить Normals и Tangents (для PBR-карт нормалей нужны касательные)
  • UV: убедиться, что экспортируются (по умолчанию включено)
  • Текстуры: Automatic или JPEG (формат на этом этапе не важен — пережмём позже, главное, чтобы они экспортировались)
  • Сжатие: не включать встроенное сжатие мешей Blender — используем более профессиональные инструменты
  • Преобразования: +Y Up (стандарт glTF)
  • Данные: экспортировать только нужное (анимации, камеры, свет не нужны — не экспортируем, экономим объём)

После экспорта model.glb: 50 МБ, 6 PNG-текстур, вершины float32. Это наша базовая точка.

Частая ошибка на этом шаге: Blender по умолчанию экспортирует неиспользуемые меши и скрытые вспомогательные объекты. Перед экспортом выполните File > Clean Up > Purge Orphans и выберите в аутлайнере только нужные объекты.

Обзор сквозного конвейера

Нарисуем полную схему, чтобы видеть картину целиком:

Исходник Blender
   │  Экспорт .glb (float32 + PNG)            50 МБ
   ▼
[1] Удаление лишнего + сварка дубликатов вершин (gltf-transform)   ~45 МБ
   │
[2] Сжатие вершин: MeshOpt (gltfpack / gltf-transform) ~30 МБ
   │
[3] Сжатие текстур: PNG → KTX2 (ETC1S/UASTC)     ~6 МБ
   │
[4] (опционально) Упрощение геометрии LOD (simplify)         ~4-5 МБ
   ▼
Итог: model-final.glb                          ~5 МБ
   │
Загрузка в движок (Three.js / Babylon.js) → транскодирование на лету → продакшен

Каждый шаг отслеживается в таблицах ниже.

Инструменты: что выбрать

Инструментов сжатия несколько — сравним, чтобы не ошибиться:

ИнструментСильные стороныСлабые стороныПодходит для
gltf-transformУниверсал: текстуры + вершины, API, скриптуемостьМаксимальное сжатие уступает специализированнымОсновной инструмент, большинство сценариев
gltfpackПрофи в сжатии вершин, нативная поддержка MeshOptСлабое сжатие текстурПлотные вершины, нужен тонкий контроль MeshOpt
toktxМаксимально профессиональное сжатие текстур, все параметрыТолько текстуры, не работает с моделью целикомТонкая настройка отдельных текстур
gltf-pipelineВетеран, поддержка DracoСлабо поддерживается, мало функцийСтарые проекты на Draco
Онлайн-инструменты (gltf.report)Без установкиНе подходят для автоматизации и пакетной обработкиЭксперименты, разовые задачи

Основная линия: gltf-transform для всего процесса, при необходимости gltfpack для вершин и toktx для отдельных текстур. Все шаги ниже основаны на gltf-transform.

Шаг 1: удаление лишнего + сварка

В моделях часто встречаются дубликаты вершин, неиспользуемые узлы и материалы. Сначала чистим.

gltf-transform optimize model.glb step1.glb --weld --prune
ЭтапРазмер файлаВидеопамятьИзменение
Базовая точка50 МБ~520 МБ
Шаг 1: чистка45 МБ~520 МБ-5 МБ (память не изменилась — текстуры на месте)

Видеопамять почти не изменилась — это ожидаемо: чистка экономит вершины и структуру, а основной объём памяти занимают текстуры.

Шаг 2: сжатие вершин MeshOpt

gltf-transform optimize step1.glb step2.glb --meshopt --weld --prune

Флаг --meshopt квантует вершины до 16 бит и применяет lossless-кодирование MeshOpt, автоматически добавляя расширение EXT_meshopt_compression.

ЭтапРазмер файлаВидеопамятьИзменение
Шаг 145 МБ~520 МБ
Шаг 2 + MeshOpt30 МБ~520 МБ-15 МБ (часть вершин)

Видеопамять всё ещё ~520 МБ? Верно — вершины занимают лишь 10–20% памяти, их сжатие мало влияет на общий объём. Настоящий пожиратель памяти — текстуры, и им займёмся на следующем шаге.

Шаг 3: сжатие текстур PNG → KTX2

Этот шаг даёт максимальную отдачу.

gltf-transform optimize step2.glb step3.glb \
  --texture-compress basisu \
  --meshopt --weld --prune

Флаг --texture-compress basisu автоматически определяет тип каждой текстуры: цветовые (albedo, emissive) — в ETC1S, data-текстуры (normal, roughness, metallic, AO) — в UASTC.

ЭтапРазмер файлаВидеопамятьИзменение
Шаг 230 МБ~520 МБ
Шаг 3 + KTX26 МБ~70 МБ-24 МБ файл / -450 МБ память

Это переломный момент всего конвейера:

  • Файл уменьшился с 30 до 6 МБ
  • Видеопамять упала с 520 до ~70 МБ — шесть текстур 4096 превратились из «распакованных пикселей» в блоковое сжатие: каждая с ~87 МБ до ~11–14 МБ

Память снизилась на порядок — именно это определяет, запустится ли модель на мобильном устройстве.

Шаг 4: (опционально) упрощение геометрии

Если нужно ещё меньше, а сцена допускает снижение точности вершин, добавляем упрощение геометрии.

gltf-transform optimize step3.glb final.glb \
  --texture-compress basisu \
  --meshopt \
  --simplify --simplify-ratio 0.5 \
  --weld --prune

--simplify-ratio 0.5 означает сохранение примерно 50% вершин.

ЭтапРазмер файлаВидеопамятьИзменение
Шаг 36 МБ~70 МБ
Шаг 4 + упрощение 0.54.5 МБ~70 МБ-1.5 МБ (память почти без изменений)

Упрощение в основном экономит размер файла, на память влияет слабо. Цена — снижение детализации: при близком рассмотрении будет заметно. Для витрин товаров обычно не рекомендуется чрезмерное упрощение, а вот для архитектуры и больших сцен — в самый раз.

Итоговая таблица эффективности

Сложим все четыре шага (на основе нашего примера; цифры иллюстрируют порядок величин):

ШагРазмер файлаВидеопамятьСуммарное снижение
Базовая точка (float32 + PNG)50 МБ~520 МБ
+ чистка и сварка45 МБ~520 МБ-10%
+ MeshOpt для вершин30 МБ~520 МБ-40%
+ KTX2 для текстур6 МБ~70 МБ-88% файл / -87% память
+ упрощение геометрии (0.5)4.5 МБ~70 МБ-91% файл

Вывод: сжатие текстур даёт основной выигрыш и по объёму, и по памяти. Сжатие вершин — приятное дополнение, сжатие текстур — необходимость. Это полностью подтверждает тезис из первой статьи: текстуры занимают 80% объёма, и их оптимизация окупается больше всего.

Версия одной командой: для ленивых

Если не нужно смотреть по шагам, применяем всю оптимизацию сразу:

gltf-transform optimize model.glb model-final.glb \
  --texture-compress basisu \
  --meshopt \
  --simplify --simplify-ratio 0.5 \
  --weld --prune

Эта одна команда = чистка + сварка + MeshOpt для вершин + KTX2 для текстур + упрощение геометрии. Для 90% сценариев её достаточно; пошаговый подход нужен для понимания и настройки параметров.

Не хотите настраивать окружение? Онлайн-сжатие в Any3D

Описанные команды и скрипты gltf-transform требуют установки Node, настройки инструментов и запоминания параметров. Онлайн-инструмент сжатия Any3D избавляет от всего этого:

  • Никаких скриптов и окружения — открыли страницу и работаете
  • Модель не загружается на сервер — всё обрабатывается локально в браузере, файл не покидает ваше устройство
  • Визуальная настройка — текстуры KTX2, вершины MeshOpt, упрощение геометрии: ползунки и предпросмотр в реальном времени
  • Один клик — несколько версий — экспорт результатов под мобильные / десктоп / VR

Выбираете GLB, указываете целевую платформу, нажимаете кнопку — получаете сжатую модель. В основе тот же gltf-transform, что и в командной строке, но без порога входа и терминала.

FAQ: частые ошибки

После сжатия модель почернела / текстуры не отображаются

  • В 99% случаев проблема в цветовом пространстве: для цветовых текстур забыли указать sRGB. В Three.js: texture.colorSpace = THREE.SRGBColorSpace.
  • При использовании toktx для цветовых текстур забыли флаг --srgb.

После сжатия карты нормалей освещение некорректное

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

На мобильных долгая загрузка первого экрана

  • Проверьте, не загружается ли wasm-декодер Draco (лишний запрос). На мобильных предпочтителен MeshOpt.
  • Неверно указан путь к транскодеру KTX2 — при сбое транскодирования происходит откат к распаковке на CPU.

После сжатия файл стал больше

  • Текстуры слишком маленькие (< 128 px): сжатие в KTX2 невыгодно, у блокового сжатия есть фиксированные накладные расходы.
  • Модель уже была сжата ранее — повторное сжатие не даёт выигрыша (или даёт отрицательный).

После упрощения геометрии появились артефакты

  • --simplify-ratio слишком низкий — поднимите до 0.7–0.8.
  • Упрощение хорошо работает для жёстких поверхностей (механика, архитектура), но плохо для органических форм (персонажи) — возможны разрывы.

KTX2 не загружается в некоторых браузерах

  • Старые Safari / WebView не поддерживают. Подготовьте запасной вариант PNG/WebP или используйте поле fallback в KHR_texture_basisu для запасных текстур.

Шпаргалка по всей серии

Квинтэссенция всех шести статей в одной таблице. Сохраните себе.

Структура объёма

КомпонентДоляИнструменты оптимизации
Текстуры70–85%KTX2 (максимальный выигрыш)
Вершины10–20%MeshOpt / квантование / Draco
Анимации0–15%Сокращение ключевых кадров / сжатие
Прочее< 2%Чистка

Формула видеопамяти

Память для обычных форматов = ширина * высота * 4 байта * 1.333 (с mipmap)
Память для KTX2 с блоковым сжатием ≈ предыдущее / 4 (
Поддержите нас