Kris

Почему 3D-модели такие большие?

3D-сжатиеglTFWebGLПроизводительность

Ваша модель тайно набирает вес

Вы экспортировали GLB-файл — 10 МБ, вроде нормально. Открываете на телефоне — белый экран, тормоза или даже вылет.

На компьютере всё работает, на телефоне — взрыв. Это не баг кода, а неочевидное свойство 3D-моделей: размер на диске и в видеопамяти — это совершенно разные вещи.

JPG-картинка на диске может весить всего 200 КБ. Но GPU не понимает JPG, ему нужны сырые пиксели. Поэтому перед загрузкой в видеопамять изображение полностью распаковывается. Текстура 2048×2048 после распаковки занимает около 22 МБ видеопамяти. Если вы используете 6 текстур (albedo, normal, roughness, metallic, AO, emissive), то один материал съест 132 МБ.

На телефоне обычно 2–4 ГБ видеопамяти, и одна текстура модели уже занимает 3–6%. А если в сцене 10 моделей?

Разбираем, куда уходит объём

Типичная GLB-модель состоит из трёх частей: вершинные данные, текстуры, а также метаданные и анимация.

Возьмём реальную PBR-модель:

КомпонентКонкретное содержимоеТипичная доляПримечание
Текстурыalbedo, normal, roughness, metallic, AO и др.70–85%Почти всегда главный «тяжеловес»
Вершиныпозиция, нормаль, UV, tangent, цвет10–20%Зависит от сложности модели
Анимацияскелет, скиннинг, ключевые кадры0–15%Только если есть анимация
Прочееописание материала, структура сцены, камера< 2%Можно не учитывать

Текстуры занимают около 80%. Часто кажется, что нужно оптимизировать вершины, но на самом деле основное место — это текстуры.

Разбор PBR-текстур 3D-модели

«Мало на диске» ≠ «Мало в видеопамяти»

Это, пожалуй, ключевой момент для понимания производительности 3D.

PNG и JPG созданы для передачи по сети — на диске они маленькие, быстро скачиваются. Но GPU не может использовать их напрямую, сначала нужно полностью распаковать в сырые пиксели. Формула расчёта:

Занимаемая видеопамять = ширина × высота × 4 байта (RGBA) × 1,333 (с мип-картами)

Текстура RGBA 4096×4096:

ПараметрЗначение
Размер PNG-файла~8 МБ
Размер JPG-файла~1,5 МБ
Видеопамять (с мип-картами)~87 МБ

JPG в 1,5 МБ превращается в 87 МБ видеопамяти.

Что такое мип-карты? GPU создаёт для текстуры серию последовательно уменьшенных копий — от исходного размера до 1×1 пикселя, каждый уровень в два раза меньше предыдущего. Это ускоряет рендеринг удалённых объектов и улучшает качество, но требует примерно на 33% больше видеопамяти. Практически все 3D-приложения используют мип-карты, так что эти накладные расходы — стандарт.

Таким образом, PNG/JPG похожи на вакуумные пакеты для вещей: сжатые они компактны и удобны в транспортировке, но на месте их нужно полностью расправить. Скачивание ускорилось, а видеопамять не сэкономилась.

Сравнение объёма на диске и занимаемой видеопамяти GPU

Что происходит, когда видеопамяти не хватает

Никакого всплывающего окна «Недостаточно видеопамяти» не будет. Всё гораздо хуже:

  • Мобильные устройства: белый экран, или система просто убивает вкладку браузера.
  • VR-шлемы: падение кадров. В VR падение кадров — это не «немного тормозит», а вызывает тошноту.
  • Десктопы: текстуры мерцают, качество падает, рендеринг замедляется.

На Пикабу один разработчик делал WebXR-галерею и загрузил в Quest 60 стереоизображений. Сначала всё было нормально, потом становилось всё нестабильнее, пока не вылетело. Он потратил несколько дней на отладку кода, а в итоге понял, что никогда не задумывался о видеопамяти — просто пихал в GPU JPG-файлы.

Два пути сжатия

Сжатие 3D-моделей делится на два направления:

Сжатие вершин — хранение координат, нормалей, UV и других геометрических данных более компактно. Например, замена 32-битных чисел с плавающей точкой на 16-битные целые (это называется квантование). Представители: Draco, MeshOpt, KHR_mesh_quantization.

Сжатие текстур — чтобы текстуры оставались сжатыми и в видеопамяти. GPU декодирует отдельные пиксели на лету при выборке, почти без потери производительности. Представители: KTX2 + Basis Universal.

Сжатие вершинСжатие текстур
Что уменьшаетГеометрические данныеТекстуры
Типичный эффектУменьшение на 50–90%Диск: 50–70%, видеопамять: 75%
Потери?Да, снижение точностиДа, ухудшение качества
Где применятьМодели с большим числом вершинПочти любые PBR-модели
ПодробнееСтатья 2Статьи 3, 4

Распространённая ошибка: сжать вершины через Draco и считать, что всё в порядке. Но текстуры занимают 80% объёма модели; если вы сократите вершины вдвое, итоговый вес уменьшится всего на 10%. Нужно работать с обеими частями.

Нет единого метода для всех случаев

Это центральная идея всего цикла статей:

Разные платформы, устройства и сценарии использования требуют разных стратегий сжатия.

СценарийГлавное узкое местоНа что обратить внимание
Десктопный веб-показСкорость загрузкиРазмер файла
Мобильный браузерВидеопамятьСжатие текстур
VR-шлемыВидеопамять + частота кадровСжатие текстур + упрощение вершин
VK Mini Apps / Telegram Mini AppsРазмер пакета + совместимостьЛёгкие решения (MeshOpt)
Большие сценыВидеопамять + draw callВсестороннее сжатие + LOD

В каждой следующей статье мы не будем просто говорить «используйте X — и всё». Мы объясним: для каких сценариев X подходит, когда он может навредить, и в каких случаях стоит выбрать Y.

Что дальше

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

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