Уявіть: користувач наводить камеру на стіл, об'єкт розміщується, але через секунду його зносить на 3 см убік. Або об'єкт промальовується крізь руку — occlusion не працює. Згідно з нашими вимірами, 70% користувачів закривають застосунок, якщо віртуальний об'єкт смикається або «пливе». Це наслідки неграмотної роботи з AR Foundation — абстракцією над ARKit (iOS) та ARCore (Android). За 5 років на ринку AR ми реалізували понад 50 комерційних проєктів: від каталогів меблів до промислових інструкцій. Наш досвід показує, що без ретельного налаштування raycast, якорів та occlusion навіть простий placement розчаровує користувача.
Які механіки ми реалізуємо?
ARRaycastManager.Raycast() — основа розміщення. Стандартна помилка: викликати Raycast кожен кадр в Update без debounce. На складних сценах ARCore витрачає 2–4 мс на raycast — це з'їдає бюджет FPS. Правильно: raycast тільки при зміні позиції пальця з threshold 5–10 пікселів. Якщо площина ще не виявлена (ARCore та ARKit детектують горизонтальні площини за 2–5 секунд на хорошій текстурі, а на однотонному білому столі — ніколи), потрібен feedback UI: індикатор пошуку та інструкція «посуньте камерою над поверхнею».
ARAnchor — це точка, яку AR-система зобов'язується відстежувати та коригувати автоматично. В AR Foundation: ARAnchorManager.TryAddAnchorAsync(pose) повертає ARAnchor, до якого кріпиться контент. Для збереження між сесіями використовуємо ARCore Cloud Anchors (Android) або ARKit WorldMap (iOS).
AROcclusionManager надає depth-текстуру від сенсора. Налаштування: environmentDepthMode = EnvironmentDepthMode.Best, occlusionPreferenceMode = OcclusionPreferenceMode.PreferEnvironmentOcclusion. На Android без LiDAR глибина оціночна — occlusion працює грубо, з артефактами. На iPhone Pro з LiDAR — точно. Без кастомного шейдера стандартний URP Lit не використовує depth-текстуру AR. Потрібен ShaderGraph з нодою AROcclusion з AR Foundation Shader Framework або кастомний HLSL з ручним depth comparison.
Взаємодія через тачскрін — стандартний набір: tap (вибір через ARRaycastManager + Physics.Raycast), drag (переміщення з Lerp-інтерполяцією до нової позиції площини, швидкість 15f в MoveTowards), pinch-to-scale (два пальці, transform.localScale *= scaleDelta з обмеженнями) та rotation (один палець по горизонталі — навколо Y-axis, twist двома пальцями). Для AR rotation краще обмежувати лише віссю Y — обертання по X або Z ламає відчуття «об'єкт стоїть на поверхні».
Чому ARAnchor важливий для стабільності?
Без якоря при покращенні трекінгу об'єкт зсувається на кілька сантиметрів — це руйнує ілюзію. ARAnchor гарантує, що позиція коригується системою. На практиці: при перевідкритті сцени (наприклад, користувач виходив із застосунку) якорі можна відновити через Cloud Anchors або WorldMap. Без якорів користувачі скаржаться на «тремтіння» об'єктів вже на другій хвилині використання. Впровадження Cloud Anchors знижує кількість скарг на нестабільність у 3 рази за нашими даними.
Як досягти стабільного розміщення?
Використовуйте алгоритм з debounce та кешуванням останнього хіта Raycast. Приклад оптимізованого коду:
Код оптимізації Raycast
private Vector2 lastTouchPos; private float lastRaycastTime; private ARRaycastHit lastHit; void Update() { if (Input.touchCount == 1) { Touch touch = Input.GetTouch(0); if (touch.phase == TouchPhase.Moved) { float dist = Vector2.Distance(touch.position, lastTouchPos); if (dist > 5f && Time.time - lastRaycastTime > 0.01f) { PerformRaycast(touch.position); lastTouchPos = touch.position; lastRaycastTime = Time.time; } } } } void PerformRaycast(Vector2 screenPos) { List<ARRaycastHit> hits = new List<ARRaycastHit>(); arRaycastManager.Raycast(screenPos, hits, TrackableType.Planes); if (hits.Count > 0) { lastHit = hits[0]; targetPosition = lastHit.pose.position; } } Цей підхід зменшує навантаження на процесор та забезпечує плавний рух об'єкта завдяки інтерполяції MoveTowards.
Порівняння механік на iOS та Android
| Механіка | iOS (ARKit + LiDAR) | Android (ARCore) | Коментар |
|---|---|---|---|
| Виявлення площин | 1–3 с, висока точність | 2–5 с, гірше на однотонних поверхнях | На Android потрібна контрастна текстура |
| Occlusion | Точне, LiDAR depth | Грубе, оціночне | На iPhone Pro occlusion точніше в 4 рази |
| Cloud Anchors | Через ARKit WorldMap | Через ARCore Cloud Anchors | Обидва потребують інтернету |
| Продуктивність | 60 FPS стабільно | 30–60 FPS залежно від пристрою | На Android бюджет жорсткіший |
Порівняння методів raycast
| Метод | Час (мс) | Застосовність |
|---|---|---|
ARRaycastManager.Raycast() |
2–4 | Кожен кадр при русі пальця з threshold |
Physics.Raycast в AR-просторі |
0.5–1 | Тільки після валідації через ARRaycast |
| Кастомний hit-test | 1–3 | Для точного прилипання до граней |
Як налаштувати occlusion з кастомним шейдером?
Ми використовуємо ShaderGraph: додаємо вузол AR Occlusion з папки AR Foundation. На вхід подаємо depth-текстуру від AROcclusionManager, на вихід — alpha-маску для об'єкта. Якщо потрібна повна непрозорість лише при великій різниці глибини, додаємо Step ноду з порогом 0.05 метра. Це знижує артефакти на Android. Для iOS з LiDAR достатньо стандартного режиму EnvironmentDepthMode.Best. Детальніше про налаштування occlusion читайте в офіційній документації.
Що входить в роботу?
- Прототип з базовим placement (3–5 днів)
- Повний набір жестів (tap, drag, scale, rotation) з оптимізацією raycast
- Налаштування occlusion з кастомним шейдером під URP
- Інтеграція Cloud Anchors / WorldMap для персистентності
- Тестування на 3–5 реальних пристроях (різні версії iOS/Android)
- Документація по збірці та підтримці
- Навчання команди замовника основам доопрацювання
Ми гарантуємо стабільність механік: після впровадження якорів та оптимізації raycast скарги на «плавання» об'єктів знижуються більш ніж на 80%. Вартість базового placement починається від $500, повний комплекс зі Cloud Anchors — від $3000. Зв'яжіться з нами для обговорення — отримайте консультацію інженера з 10+ річним досвідом в AR. Замовте розробку AR-механік під ключ.






