Реализация AR-сканирования плоскостей в мобильном приложении
Мы часто сталкиваемся с ситуацией: клиент хочет разместить виртуальный диван в комнате, но приложение показывает «плавающий» объект без чёткой привязки к полу. Пользователь разочарован, а разработчик упирается в ограничения платформенных SDK. Стабильное определение плоскостей — ключ к убедительному AR. Без него любой AR-объект воспринимается как инородный элемент. Мы научились доводить plane detection до состояния «стоит как настоящее» за 5-8 дней.
Платформенные API и их реальные ограничения
ARKit (iOS). ARWorldTrackingConfiguration с planeDetection: [.horizontal, .vertical]. ARKit возвращает ARPlaneAnchor с ARPlaneGeometry — mesh плоскости, который обновляется по мере сканирования. Проблема: на первых секундах ARKit возвращает маленький прямоугольник, который агрессивно меняет размер и ориентацию. Если разместить объект сразу — он «прыгнет» при следующем обновлении.
Решение — минимальный confidence threshold и debounce на обновления. ARPlaneAnchor не имеет явного поля confidence, но размер плоскости (extent) служит косвенным показателем зрелости: не показывать UI для размещения, пока extent.x < 0.3 и extent.z < 0.3 метра.
ARCore (Android). Plane с TrackingState.TRACKING и PlaneType.HORIZONTAL_UPWARD_FACING / VERTICAL. ARCore дополнительно предоставляет Plane.getSubsumedBy() — когда две плоскости сливаются в одну. Это ломает логику, если якоря были привязаны к исходным плоскостям — нужно переносить Anchor на subsuming plane.
Vertical planes. ARKit стабильно определяет вертикальные плоскости на текстурированных поверхностях (стена с обоями — хорошо, монотонно белая стена — плохо). ARCore с vertical detection работает ещё менее уверенно. Для продуктов, где критична навеска на стену (картины, полки), лучше использовать комбинацию plane detection + LiDAR (iPhone 12 Pro+) для достройки недостающей геометрии.
Как LiDAR меняет правила игры?
На устройствах с LiDAR (iPhone 12 Pro, 13 Pro, 14 Pro, 15 Pro, iPad Pro) ARKit строит dense mesh окружения через ARMeshAnchor. Plane detection с LiDAR работает принципиально иначе: плоскости выводятся из mesh, а не из визуального SLAM. Это даёт:
- Детектирование плоскости за 1-2 секунды вместо 5-10
- Стабильные границы даже на монотонных поверхностях
- Корректное определение ступеней, пандусов, наклонных плоскостей
Для приложений, где LiDAR-устройства — основная ЦА (профессиональная съёмка, ремонт, строительство), переключение между ARWorldTrackingConfiguration и конфигурацией с sceneReconstruction: .mesh даёт качественный скачок.
Почему плоскость "прыгает" и как это исправить?
Основная причина — размещение объекта до того, как плоскость стабилизировалась. Confidence threshold и debounce решают проблему на 80%. Проверенный подход:
- Не показывать кнопку размещения, пока размер плоскости не превысит 0.3 метра по каждой оси.
- При обновлении плоскости плавно перемещать якорь с анимацией (например,
SCNActionв SceneKit илиUIView.animateв RealityKit). - Использовать
ARWorldTrackingConfiguration.isAutoFocusEnabledдля улучшения качества кадра.
Детальный чек-лист стабильного размещения
- Проверять `ARPlaneAnchor.extent.x > 0.3` и `extent.z > 0.3` - Игнорировать обновления плоскости в течение 0.5 секунд после первого детектирования - На LiDAR-устройствах использовать `ARMeshAnchor` для более точной геометрии - Всегда обрабатывать `ARCamera.TrackingState` и блокировать UI при `LIMITED`Визуализация прогресса сканирования
Пользователь не знает, что нужно «поводить» камерой — нужна чёткая подсказка. Типовые паттерны:
- Анимированный сканирующий луч из нижней части экрана
- Outline плоскости, который «растёт» по мере обнаружения
- Текстовая инструкция с автоскрытием после первого успешного detection
Для отрисовки границ плоскости в RealityKit — ModelEntity с wireframe материалом, привязанный к PlaneAnchor. В SceneKit — SCNNode с SCNGeometry из ARPlaneGeometry.boundaryVertices. В ARCore Scenekit/Filament — собственный меш из Plane.getPolygon().
Типичные проблемы в production
Плоскость «ломается» при сильном движении камерой — tracking state переходит в LIMITED(.excessiveMotion). Нужно блокировать размещение объектов и показывать предупреждение, а не крашиться.
На тёмных поверхностях (тёмный ламинат, чёрный ковёр) ARKit и ARCore теряют features для визуального SLAM. Предупреждение через ARCamera.TrackingState.Reason.insufficientFeatures — обязательно обрабатывать и сообщать пользователю.
Что входит в работу
- Тестирование на целевых устройствах с оценкой стабильности
- Оптимизация под LiDAR (если поддерживается)
- Реализация multi-plane selection (возможность выбора плоскости касанием)
- Сохранение ARWorldMap для повторного использования сцены
- Документация по интеграции и настройке
- Гарантия стабильной работы: мы даём 30 дней безплатной поддержки после сдачи
| Платформа | API | Особенности |
|---|---|---|
| iOS (ARKit) | ARPlaneAnchor, ARWorldTrackingConfiguration | Быстрый старт, но требуется debounce |
| Android (ARCore) | Plane, getSubsumedBy() | Слияние плоскостей, перенос якорей |
| LiDAR-устройства | ARMeshAnchor | Детектирование за 1-2 сек, стабильность |
Сравнение методов визуализации
| Инструмент | Визуализация границ | Производительность | Гибкость |
|---|---|---|---|
| RealityKit | ModelEntity с wireframe | Высокая | Средняя |
| SceneKit | SCNNode из boundaryVertices | Средняя | Высокая |
| ARCore + Filament | Меш из getPolygon() | Средняя | Высокая |
Apple ARKit documentation: ARKit Plane Detection Google ARCore documentation: Plane Detection
Сроки ориентировочно
Реализация базового plane detection с визуальной подсказкой и размещением объекта — от 5 до 8 дней. Доработка под LiDAR, multi-plane selection, сохранение ARWorldMap — ещё 5-7 дней. Стоимость рассчитывается индивидуально, в зависимости от сложности. Получите консультацию — свяжитесь с нами для оценки вашего проекта.
Наша команда имеет 5+ лет опыта в AR-разработке и более 20 успешных проектов. Закажите реализацию под ключ и получите консультацию бесплатно.







