tags: [vr-ar]
Настройка плоскостного трекинга и привязки объектов в AR играх
AR Foundation в Unity даёт доступ к ARPlaneManager и ARAnchorManager — и именно здесь начинается большинство проблем. Плоскость задетектирована, объект размещён, игрок двигается — и через три шага виртуальный стол уже висит в воздухе в полуметре от поверхности. Либо хуже: ARPlane обновился, но якорь (ARAnchor) остался привязан к старым координатам, и объект начинает «дрейфовать» по комнате.
Это не баг AR Foundation. Это неправильная архитектура сцены.
Почему якоря отвязываются от плоскостей
Главная ошибка — крепить объект напрямую к ARPlane.transform, а не к ARAnchor, привязанному к этой плоскости. ARPlane обновляет свою геометрию при каждом рефреше трекинга: центр смещается, нормаль пересчитывается. Объект, прицепленный к трансформу плоскости как дочерний, просто следует за этим хаосом.
Правильная цепочка: вызвать ARAnchorManager.AttachAnchor(plane, pose), получить ARAnchor с его собственным стабильным трансформом, и уже к нему крепить игровой объект. ARAnchor система трекинга обновляет независимо от геометрии плоскости — его позиция корректируется с учётом IMU-данных и переоценки карты пространства, а не просто пересчитывается вместе с мешем плоскости.
Второй уровень проблем — TrackingState. Якорь может уйти в TrackingState.Limited или вовсе в None, если устройство потеряло визуальные ориентиры. Нужно подписываться на ARAnchorManager.anchorsChanged и обрабатывать переход между состояниями: прятать объект, показывать индикатор «трекинг потерян», восстанавливать позицию когда TrackingState вернётся в Tracking. Большинство проектов это не делают — пользователь видит объект, который завис на последней известной позиции и не реагирует на движение.
Детектирование плоскостей: что реально работает
ARKit на iOS и ARCore на Android используют разные алгоритмы детектирования плоскостей, и это видно в поведении. ARKit агрессивнее расширяет плоскость — даже при частичной видимости поверхности он достраивает её гипотетические границы. ARCore консервативнее: плоскость растёт только там, где было реальное покрытие feature points.
Для игровых сценариев это значит: если игра требует размещения объекта до того, как пользователь обошёл всю поверхность, на Android нужно либо снижать требования к минимальному размеру плоскости в ARPlaneManager.requestedDetectionMode, либо реализовывать принудительное размещение с визуальным предупреждением. Ставить одинаковые пороги детектирования для обеих платформ — гарантированно плохой UX на одной из них.
Отдельная тема — вертикальные плоскости (PlaneDetectionMode.Vertical). На большинстве Android-устройств вертикальный трекинг значительно нестабильнее горизонтального. Игры, предполагающие размещение объектов на стенах, должны тестироваться на реальном железе, а не в ARCore Emulator — симулятор не воспроизводит шум IMU-данных и реальный дрейф.
Как это делаем на практике
Типичный кейс: мобильная AR-игра, где игрок расставляет башни на полу комнаты. Основная проблема на этапе прототипа — башни «плавали» при движении камеры. Причина — объекты крепились к ARPlane через SetParent, трекинг плоскости обновлял меш, и дочерние объекты смещались вместе с новым центром.
Решение: переход на ARAnchor-архитектуру. Каждая башня при размещении получает собственный якорь через AttachAnchor. Якорь добавляется в словарь Dictionary<ARAnchor, TowerObject> — при срабатывании anchorsChanged.removed башня получает уведомление и переходит в «ненадёжное» состояние с визуальным индикатором. При added (если это был known anchor из сохранённой сессии) — восстанавливается.
Для сохранения якорей между сессиями используем ARWorldMap (ARKit) или Cloud Anchors API (ARCore/ARKit через AR Foundation Samples). Cloud Anchors позволяют якорю пережить перезапуск приложения и даже работать между разными устройствами — это основа для многопользовательского AR.
Этапы работы над задачей
-
Аудит текущей архитектуры — проверяем, как объекты привязаны к плоскостям, есть ли обработка
TrackingState, как ведёт себя сцена при потере трекинга -
Настройка
ARPlaneManager— режимы детектирования, фильтрация по минимальному размеру, визуализация плоскостей для дебага -
Реализация
ARAnchor-архитектуры — переход от parent-child к якорям, обработка жизненного цикла якорей - Тестирование на целевых устройствах — ARKit (iPhone 12+) и ARCore (флагманы + mid-range Android)
- Опциональная интеграция Cloud Anchors — если нужна персистентность между сессиями
| Масштаб задачи | Ориентировочные сроки |
|---|---|
| Аудит + фикс существующей архитектуры | 2–5 дней |
| Настройка с нуля для новой сцены | 3–7 дней |
| Интеграция Cloud Anchors + мультиплеер | 2–4 недели |
Типичные ошибки при настройке трекинга
Не обрабатывается LimitedTrackingReason.ExcessiveMotion. При быстром движении камеры ARCore переходит в Limited, и объекты начинают «прыгать». Правильная реакция — заморозить позицию объекта на время потери трекинга, не пересчитывать физику, и восстановить плавно через Lerp после возврата в Tracking.
ARRaycastManager используется без проверки типа хита. ARRaycastHit.trackable может быть как ARPlane, так и ARPoint (feature point). Для размещения объектов на поверхностях нужно фильтровать только TrackableType.PlaneWithinPolygon — иначе пользователь будет «размещать» объекты в воздухе на feature points.
Слишком агрессивный ARPlane меш в продакшене. В дебаге удобно видеть всю геометрию плоскостей, но в финальной игре меш плоскостей либо скрывается полностью, либо заменяется декоративным вариантом. Стандартный ARFeatheredPlaneMeshVisualizer из AR Foundation Samples — хорошая отправная точка.





