Профилирование сцены в браузере

Библиотека A-Frame построена поверх Three.js и использует WebGL для рендеринга. Это означает, что производительность сцены определяется сразу несколькими уровнями:

  • браузерный JavaScript-движок;
  • система компонентов A-Frame;
  • рендерер Three.js;
  • графический драйвер и GPU;
  • устройство ввода и XR-подсистема.

Профилирование сцены в браузере необходимо для выявления узких мест на каждом из этих уровней: перегруженный цикл обновления, чрезмерное количество draw call’ов, частые аллокации памяти, блокирующие операции в основном потоке или избыточная геометрия.


Основные метрики производительности

FPS (Frames Per Second)

Частота кадров отражает, сколько раз сцена полностью перерисовывается за секунду. Для обычного экрана целевой показатель — 60 FPS, для VR — 72, 90 или 120 FPS в зависимости от устройства.

Снижение FPS обычно связано с:

  • большим количеством объектов;
  • тяжёлой геометрией;
  • дорогими материалами и шейдерами;
  • сложной логикой в tick;
  • частыми перерасчётами layout или DOM.

Frame Time

Время кадра — более точный показатель, чем FPS. При 60 FPS один кадр должен занимать ~16.6 мс. Если обработка занимает 25–30 мс, появляется заметная потеря плавности.

Frame Time делится на:

  • JavaScript execution
  • Style & Layout
  • Paint
  • GPU rendering

Память

Утечки памяти в сцене приводят к деградации производительности и сбоям. Основные причины:

  • неосвобождённые геометрии и материалы;
  • повторное создание текстур;
  • накопление слушателей событий;
  • постоянное создание объектов внутри tick.

Использование встроенной статистики A-Frame

A-Frame предоставляет базовый инструмент диагностики — компонент stats.

<a-scene stats>

Визуальная панель отображает:

  • FPS
  • время кадра
  • количество draw calls
  • число треугольников
  • число текстур
  • количество программ (shader programs)

Показатель draw calls особенно критичен: каждый вызов отрисовки — отдельная операция для GPU. Большое количество мелких объектов резко увеличивает нагрузку.


Профилирование через DevTools браузера

Chrome DevTools

Браузер Google Chrome предоставляет мощные инструменты профилирования.

Вкладка Performance

Позволяет записать временной профиль выполнения:

  1. Начать запись.
  2. Выполнить действия в сцене.
  3. Остановить запись.
  4. Проанализировать график загрузки CPU и рендеринга.

Ключевые области анализа:

  • Long Tasks (задачи > 50 мс)
  • Перегруженные функции tick
  • Частые перерасчёты layout
  • Garbage Collection spikes

Flame Chart

Flame Chart показывает стек вызовов. Если компонент A-Frame тратит значительное время в tick, это становится очевидно в диаграмме.

Вкладка Memory

Используется для:

  • создания Heap Snapshot;
  • анализа удерживаемых объектов;
  • обнаружения утечек.

При удалении сущности (el.parentNode.removeChild(el)) необходимо убедиться, что:

  • удалены слушатели событий;
  • очищены ссылки;
  • освобождены ресурсы Three.js.

Профилирование цикла tick

Каждый компонент может реализовать метод:

tick: function (time, deltaTime) {
}

Этот метод вызывается на каждый кадр. Ошибки в проектировании tick — частая причина падения FPS.

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

1. Создание объектов в каждом кадре

Плохо:

tick: function () {
  const v = new THREE.Vector3();
}

Создание объектов приводит к частым сборкам мусора.

Правильнее:

init: function () {
  this.v = new THREE.Vector3();
}

2. Сложные вычисления

Тригонометрия, парсинг строк, поиск по большим массивам должны быть вынесены за пределы tick, если возможно.

3. Частые DOM-операции

Работа с DOM внутри tick крайне затратна. A-Frame оперирует DOM-элементами, но их изменение инициирует дорогостоящие перерасчёты.


Анализ draw calls и геометрии

Так как A-Frame основан на Three.js, производительность сцены зависит от:

  • количества мешей;
  • числа материалов;
  • сложности геометрии;
  • прозрачности объектов.

Оптимизация через объединение геометрии

Использование батчинга (batching) позволяет объединять меши с одинаковыми материалами.

В Three.js применяется BufferGeometryUtils.mergeBufferGeometries, а в A-Frame можно использовать сторонние компоненты для batching.

Instancing

Для повторяющихся объектов предпочтительно использовать InstancedMesh. Это резко снижает draw calls.


Работа с текстурами

Текстуры — один из главных факторов нагрузки на GPU.

Размер текстур

Текстуры 4096×4096 значительно нагружают память. Рекомендуется использовать размеры, кратные степени двойки:

  • 256
  • 512
  • 1024
  • 2048

Сжатие

Использование сжатых форматов (KTX2, Basis) снижает потребление памяти и ускоряет загрузку.

Mipmaps

Автоматически создаются для текстур степени двойки. Их отсутствие может ухудшить производительность при масштабировании.


Анализ работы шейдеров

Кастомные шейдеры через shader-компоненты могут стать узким местом.

Проблемные признаки:

  • сложные циклы во фрагментном шейдере;
  • большое количество условных операторов;
  • heavy branching;
  • использование высокоточных типов (highp) без необходимости.

Инструменты WebGL Inspector (или встроенные средства DevTools) позволяют оценить время выполнения GPU-команд.


Профилирование XR-сцен

В режиме WebXR нагрузка возрастает:

  • сцена рендерится дважды (по одному кадру на глаз);
  • увеличивается требуемый FPS;
  • добавляется отслеживание положения.

Браузеры на базе Chromium используют WebXR через GPU-композицию, поэтому стабильность кадров особенно критична.

При тестировании VR-сцен необходимо:

  • проверять FPS именно в XR-режиме;
  • учитывать разрешение устройства;
  • анализировать время кадра GPU.

Оптимизация системы компонентов

Каждый компонент A-Frame участвует в жизненном цикле:

  • init
  • update
  • tick
  • remove

Частые обновления через setAttribute вызывают повторный вызов update, что может быть дорогостоящим.

Лучше:

  • кэшировать ссылки на object3D;
  • изменять параметры напрямую через Three.js API;
  • избегать частого пересоздания компонентов.

Работа с анимациями

Компонент animation удобен, но множественные анимации создают дополнительную нагрузку.

Альтернатива —:

  • объединение анимаций;
  • использование requestAnimationFrame вне компонента;
  • применение GPU-анимаций (через шейдеры).

Анализ сетевых ресурсов

Загрузка моделей формата glTF может стать причиной лагов.

Оптимизация включает:

  • уменьшение числа полигонов;
  • удаление невидимых мешей;
  • оптимизацию материалов;
  • использование DRACO-сжатия.

Использование Lighthouse

Инструмент Lighthouse в Chrome позволяет анализировать:

  • производительность загрузки;
  • блокирующие скрипты;
  • размер бандла;
  • влияние сторонних библиотек.

Хотя Lighthouse ориентирован на web-страницы, его отчёты помогают выявить узкие места в A-Frame-приложении.


Отладка сборки мусора

Garbage Collector может вызывать резкие падения FPS.

Способы снижения:

  • object pooling;
  • повторное использование векторов, матриц, массивов;
  • отказ от анонимных функций в горячих местах;
  • минимизация временных объектов.

В DevTools вкладка Performance показывает события GC как отдельные блоки.


CPU vs GPU bottleneck

Важно определить, где возникает узкое место:

  • если загрузка CPU высокая — проблема в JavaScript или логике;
  • если CPU низкий, но FPS падает — вероятна перегрузка GPU.

Методы определения:

  • отключение теней;
  • уменьшение разрешения;
  • временное удаление сложных шейдеров;
  • отключение прозрачности.

Тени и освещение

Динамические тени — дорогостоящая операция.

Факторы влияния:

  • размер shadow map;
  • количество источников света;
  • тип света (spot, directional);
  • динамичность объектов.

Оптимизация:

  • ограничение области тени;
  • уменьшение разрешения shadow map;
  • отключение теней для второстепенных объектов.

Постпроцессинг

Эффекты Bloom, SSAO, DOF реализуются через дополнительные проходы рендеринга. Каждый проход увеличивает время кадра.

В сценах с ограничениями по производительности следует:

  • минимизировать количество постэффектов;
  • снижать их качество;
  • отключать на мобильных устройствах.

Стратегия системного профилирования

Комплексный подход включает:

  1. Измерение FPS.
  2. Запись профиля CPU.
  3. Анализ draw calls.
  4. Проверку памяти.
  5. Тестирование на целевых устройствах.
  6. Оптимизацию и повторное измерение.

Профилирование — итеративный процесс. Изменения должны измеряться количественно, а не оцениваться субъективно.


Практический алгоритм поиска узкого места

  1. Включить stats.
  2. Зафиксировать FPS.
  3. Отключить тени — сравнить.
  4. Удалить сложные модели — сравнить.
  5. Закомментировать логику tick.
  6. Записать Performance-профиль.
  7. Проанализировать Flame Chart.
  8. Проверить Heap Snapshot.

Такой системный подход позволяет локализовать источник деградации производительности и оптимизировать сцену без хаотичных изменений.