Оптимизация производительности AR-приложения
AR-приложение на ARKit греет iPhone 12 до 45°C за 8 минут сессии и разряжает батарею на 1% в минуту. Frame rate — 45–50 FPS вместо 60. Это не «немного тормозит» — это приложение, которым нельзя пользоваться. Оптимизация AR — особая дисциплина: нельзя пожертвовать качеством трекинга ради FPS, нельзя убрать освещение и потерять реализм, нужно работать одновременно с CPU (ARKit/ARCore обработка), GPU (рендеринг) и Neural Engine (если есть ML-модели).
Архитектура AR-сессии и где возникают проблемы
ARKit/ARCore работают непрерывно: захват кадра с камеры → feature detection → плоскостная оценка → обновление мировой модели → рендеринг. Каждый этап — вычислительная нагрузка. На iPhone — ARKit использует Neural Engine для плоскостного трекинга, что сильно разгружает CPU/GPU. На Android ARCore — тяжелее для GPU на устройствах без NPU.
Типичные узкие места:
Загрузка тяжёлых 3D-моделей в ARSCNView без оптимизации: SCNNode с 500K полигонов без LOD, текстуры 4096×4096 без mipmapping. GPU рендерит одинаково детально объект на переднем плане и в 10 метрах от камеры.
Включённые фичи трекинга, которые не используются. ARWorldTrackingConfiguration с isAutoFocusEnabled = true и environmentTexturing = .automatic без реальной необходимости — постоянная нагрузка на систему.
Физика в SCNScene с SCNPhysicsBody на каждом объекте при десятках AR-объектов — физический движок SceneKit не оптимизирован для мобильных AR-сцен с большим количеством тел.
Оптимизация ARKit
Конфигурация сессии
let configuration = ARWorldTrackingConfiguration()
// Включаем только то что реально нужно
configuration.planeDetection = [.horizontal] // не .vertical если не нужно
configuration.isAutoFocusEnabled = false // фиксированный фокус — меньше нагрузки
configuration.environmentTexturing = .none // отключаем если нет PBR-материалов
// Для простых сцен — lighter tracking
let simpleConfig = AROrientationTrackingConfiguration() // только ориентация, без world tracking
Для приложений где нужен только face tracking — ARFaceTrackingConfiguration вместо ARWorldTrackingConfiguration. Разница в нагрузке на CPU — ощутима.
Рендеринг через Metal вместо SceneKit
ARSCNView удобен, но для сложных сцен MTKView + кастомный Metal-рендерер даёт полный контроль над draw calls. SceneKit добавляет overhead на управление нодами и физику. С ARSession + MTKView:
func session(_ session: ARSession, didUpdate frame: ARFrame) {
let commandBuffer = commandQueue.makeCommandBuffer()!
// Рендерим captured image (камера)
renderCapturedImage(frame.capturedImage, commandBuffer: commandBuffer)
// Рендерим AR-контент
renderVirtualContent(frame, commandBuffer: commandBuffer)
commandBuffer.present(drawable)
commandBuffer.commit()
}
Это даёт 20–30% прирост FPS на сценах с 10+ AR-объектами по сравнению с ARSCNView.
Culling и LOD
SCNNode.isHidden = true для объектов вне поля зрения — SceneKit не рендерит скрытые ноды, но выполняет physics и update. Правильно — убирать объекты из сцены: node.removeFromParentNode().
// Frustum culling вручную
func shouldRenderNode(_ node: SCNNode, camera: ARCamera) -> Bool {
let screenPoint = camera.projectPoint(node.worldPosition,
orientation: .portrait,
viewportSize: viewportSize)
return screenPoint.x > -0.1 && screenPoint.x < 1.1 &&
screenPoint.y > -0.1 && screenPoint.y < 1.1
}
Оптимизация ARCore (Android)
Session config:
val config = Config(session)
config.planeFindingMode = Config.PlaneFindingMode.HORIZONTAL_ONLY
config.lightEstimationMode = Config.LightEstimationMode.DISABLED // +15% battery
config.depthMode = Config.DepthMode.DISABLED // если глубина не нужна
session.configure(config)
LightEstimationMode.ENVIRONMENTAL_HDR — самый дорогой режим, даёт реалистичные отражения. На устройствах без Depth API (большинство mid-range) использовать только если это ключевая фича.
Rendering через Filament (Google's PBR renderer): ARCore-приложения с Filament рендерят PBR-материалы через Vulkan на поддерживаемых устройствах — заметно быстрее чем через OpenGL ES. Готовый пример — arcore-android-sdk samples с Filament-интеграцией.
Кейс: AR мебельный каталог
Клиент: приложение для просмотра мебели в AR. Диваны и столы — 3D-модели от дизайнеров, по 800K–1.2M полигонов каждый. На iPhone 13 — 24 FPS при размещении 2 объектов. Проблема очевидна.
Работа: экспорт моделей через Blender с decimation до 50K полигонов для AR-версии (потеря детализации незаметна с расстояния 1–2 метра на телефоне). Конвертация текстур из PNG 4096×4096 в ASTC 2048×2048. Добавление LOD: высокая детализация для объектов ближе 1.5 метра, средняя — дальше. Результат: 58–60 FPS стабильно, температура нормализовалась.
Мониторинг производительности AR-сессии
// Получаем метрики рендеринга
arView.renderOptions.insert(.disableMotionBlur) // убираем тяжёлые post-effects
// Логируем frame stats
arView.session.delegate = self
func session(_ session: ARSession, didUpdate frame: ARFrame) {
print("Tracked features: \(frame.rawFeaturePoints?.points.count ?? 0)")
}
На Android: Frame.getTimestamp() разница между кадрами — если > 33ms, пропущен кадр.
Сроки
Аудит производительности AR-приложения — 2–3 дня. Оптимизация рендеринга и конфигурации сессии — 1–2 недели. Если нужна оптимизация 3D-моделей — дополнительно, зависит от количества ассетов.







