Реализация построения 3D-сетки окружения (Scene Reconstruction) в AR
Scene Reconstruction — это не просто «AR видит пол». Это живой меш окружения, который ARKit обновляет в реальном времени по мере движения камеры. ARMeshAnchor накапливает геометрию комнаты, поверхности классифицируются, а приложение получает данные, с которыми можно работать: детектировать препятствия, строить навигационные графы, запускать физическую симуляцию.
Реализовать это так, чтобы не убить производительность — отдельная задача.
Архитектура меша и главные ловушки
ARMeshGeometry хранит вершины, нормали и индексы треугольников. Обновляется через делегат session(_:didUpdate:) — каждый кадр ARKit может присылать десятки обновлённых ARMeshAnchor. Наивная реализация, которая на каждый update пересоздаёт MeshResource или SCNGeometry, убивает main thread за секунды.
Правильный подход: обновляем меш только для изменившихся анкоров, используем MDLMesh как промежуточный формат и передаём данные в Metal буферы напрямую. В RealityKit это выглядит так:
func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) {
for anchor in anchors.compactMap({ $0 as? ARMeshAnchor }) {
updateMeshVisualization(for: anchor)
}
}
func updateMeshVisualization(for anchor: ARMeshAnchor) {
let geometry = anchor.geometry
// Работаем с geometry.vertices, geometry.faces напрямую
// Не создаём новый MeshResource каждый раз — патчим существующий
}
Вторая ловушка — классификация поверхностей. ARMeshClassification даёт: .floor, .ceiling, .wall, .door, .window, .seat, .table, .none. Но классификация работает только при sceneReconstruction = .meshWithClassification и только на устройствах с LiDAR. Без проверки ARWorldTrackingConfiguration.supportsSceneReconstruction(.meshWithClassification) — краш или молчаливое игнорирование.
Третья — координаты меша в мировом пространстве. ARMeshGeometry.vertices дают локальные координаты относительно ARMeshAnchor.transform. Чтобы получить мировые координаты, нужно умножить каждую вершину на матрицу трансформации анкора. Забыли — меш рендерится в неправильном месте.
Как мы строим Scene Reconstruction
Базовый стек: ARKit 5+ + RealityKit 2 + Metal. SceneKit не используем для меша — он не оптимизирован под динамические геометрии.
Настройка сессии:
let config = ARWorldTrackingConfiguration()
config.sceneReconstruction = .meshWithClassification
arView.debugOptions = [.showSceneUnderstanding] // для отладки
arView.session.run(config)
Для визуализации меша в режиме отладки рисуем wireframe через arView.debugOptions. В продакшене видимость меша отключаем, но используем его данные для:
- Окклюзии — объекты за стенами не видны
-
Физики —
CollisionComponentвзаимодействует с реальной геометрией - Raycast — точное попадание в реальные поверхности, не только в плоскости
Кейс из практики: навигационное AR-приложение для склада. Нужно было детектировать препятствия (стеллажи, паллеты) и строить маршрут. Использовали Scene Reconstruction для построения occupancy grid: каждую вершину меша с классификацией .none (нераспознанный объект) добавляли в граф препятствий. NavMesh обновлялся каждые 2 секунды — баланс между актуальностью и нагрузкой на CPU. На iPad Pro M2 это держит 60 FPS без просадок.
Fallback и диагностика
На нон-LiDAR устройствах Scene Reconstruction недоступен. Предлагаем деградацию до plane detection с manual mesh capture через ARPlaneAnchor. Это хуже, но лучше чем пустой экран.
Для диагностики качества меша — ARView.debugOptions.insert(.showSceneUnderstanding): зелёный wireframe показывает, что ARKit видит. Полезно при тестировании в нестандартных средах (глянцевые полы, зеркала — LiDAR работает плохо из-за отражения).
Сроки
Базовая интеграция с визуализацией меша — 1–2 недели. Если нужны классификация поверхностей, физические коллизии и навигация на основе меша — 4–6 недель. Стоимость рассчитывается после детального обсуждения требований.







