VR та AR розробка
Перший раз запустивши проект у VR-гарнітурі, більшість команд стикається з одною й тією ж проблемою: технічно все працює, але в гарнітурі або укачує, або руки «плавають» із затримкою, або сцена виглядає дергано на периферії взгляду. Це не баги у звичайному сенсі — це наслідок того, що VR/AR розробка вимагає іншого підходу до архітектури рендера, взаємодії та UX з самого початку проекту.
Платформи та SDK
Працюємо з усім актуальним стеком:
| Платформа | SDK / Framework |
|---|---|
| Meta Quest 2/3/Pro | Meta XR SDK, OpenXR |
| PC VR (SteamVR) | SteamVR Plugin, OpenXR |
| PlayStation VR2 | Sony PSVR2 SDK |
| HoloLens 2 | Mixed Reality Toolkit (MRTK) |
| ARKit (iOS) | AR Foundation + ARKit XR Plugin |
| ARCore (Android) | AR Foundation + ARCore XR Plugin |
| WebXR | Unity WebXR Export |
OpenXR використовуємо як базовий шар всюди, де це можливо — він дає кросс-платформеність між Meta, Valve Index, HP Reverb та іншими PC VR-пристроями. Поверх OpenXR будуємо на XR Interaction Toolkit (Unity) або VR Expansion Plugin (Unreal).
Взаємодія в VR: захват, бросок, телепорт
Це найнедооцінена частина VR-розробки. Клієнти часто сприймають її як «просто анімація рук», але насправді — це складна система, де фізична коректність, відзивчивість та комфорт вступають у протиріччя одне з одним. Розберемо детально.
Grab (захват об'єктів)
XR Interaction Toolkit надає три типи Interactable для захвату:
-
XRGrabInteractable— стандартний захват, об'єкт слідує за контролером через фізичний joint або direct position/rotation -
XRSimpleInteractable— для об'єктів без фізичного переміщення (кнопки, рички) - Кастомні Interactable через наслідування від
XRBaseInteractable
Ключовий вибір при реалізації захвату — Kinematic vs Physics-based movement:
Kinematic (trackPosition/trackRotation через Transform): об'єкт миттєво слідує за рукою. Відзивчиво, але нереалістично — об'єкт проходить крізь стіни. Підходить для більшості casual VR та experience-проектів.
Physics-based (через Rigidbody + Joint): об'єкт утримується фізичним суглобом. Реалістична взаємодія з оточенням, об'єкти коректно стикаються зі столами та стінами. Проблема — при швидких рухах joint може «розтягнутися», об'єкт дрижить або вибивається з рук. Лікується через velocity damping, max joint force та детектор «розриву» joint при екстремальних швидкостях.
Attach Transform — часто ігнорована деталь. Кожен Interactable повинен мати правильно налаштований Attach Transform (точка, до якої рука «прилипає»). Без нього рукоятка пістолета опиниться в центрі меша, а не там, де її тримають.
Для зброї та інструментів із дворучним захватом — окрема система TwoHandGrab: ведуча рука визначає позицію, друга — орієнтацію. XR Interaction Toolkit підтримує це через XRTwoHandGrabInteractable або кастомну логіку з двома Attach Points.
Throw (бросок)
Фізично коректний бросок у VR — це нетривіально. Проблема в тому, що Rigidbody.velocity у момент відпускання контролера відображає миттєву швидкість, яка часто некоректна через дискретизацію трекінгу. Користувач робить швидкий рух запястям — а об'єкт летить вдвічі повільніше, ніж очікується.
Рішення: velocity smoothing за останні N кадрів (типово 5-10 кадрів, ~80-160 мс при 60 Hz) перед відпусканням. XR Interaction Toolkit робить це через VelocityEstimator. Додатково застосовуємо velocity scaling multiplier — невелике множення швидкості (1.2-1.5x) робить броски суб'єктивно задовільнішими.
Кутову швидкість (для об'єктів, які повинні крутитися в польоті) теж усереднюємо аналогічним способом.
Teleport (переміщення)
Locomotion — головне джерело motion sickness для недосвідчених VR-користувачів. Teleportation — стандартний способ навігації, коли плавне переміщення небажане.
Компоненти з XR Interaction Toolkit: TeleportationArea, TeleportationAnchor, TeleportationProvider. Базова реалізація працює «з коробки», але для продакшену доробляємо:
-
Дуга телепортації (
XRRayInteractorз Bend Ray): дуга виглядає натуральніше прямого променя, краще читається користувачами - Валідна зона приземлення: візуальний індикатор змінює колір при наведенні на перешкоду — червоний/зелений
- Fade transition: плавне затухання екрана (black fade) перед телепортом знижує дезорієнтацію
- Rotation snapping: після телепорту пропонуємо snap-поворот на 45° або 90° замість плавного — знижує ризик укачування
Для проектів, де потрібна плавна локомоція (екшн-ігри, симуляторы), використовуємо comfort settings: віньєтування при русі, зниження FOV під час прискорення. Налаштування доступні користувачу в меню — різні люди мають різний поріг чутливості.
AR: Plane Tracking та робота з оточенням
AR додає інший клас проблем — роботу з реальним, непередбачуваним оточенням.
AR Foundation — кросс-платформенний шар поверх ARKit та ARCore. Більшість базових функцій (plane detection, raycasting, image tracking, face tracking) доступні через єдиний API.
Plane Detection
ARPlaneManager виявляє горизонтальні та вертикальні площини. Практичні нюанси:
- Ініціалізація займає час — користувач повинен осмотрити приміщення, поки система будує карту. Потрібен явний onboarding з інструкцією «повільно проводьте камерою по поверхнях»
-
Площини нестабільні — їхні границі та позиція оновлюються по мірі накопичення даних. Об'єкти, розміщені на площині, потрібно через
parentingприв'язувати до ARPlane, а не до світових координат -
Злиття площин — два виявлені сегменти підлоги можуть злитися в один, що рухає якір. Для критичних якорів використовуємо
ARAnchorзамість прямої прив'язки до площини
Image Tracking та Object Tracking
ARTrackedImageManager — для маркерів. Важливо: якість трекінгу прямо залежить від якості reference image. Зображення з високою частотою деталей та контрастними краями (мається на увазі: QR-код, але красивий) трекаються надійніше, ніж гладкі логотипи.
ARCore Geospatial API — для outdoor AR з прив'язкою до реальних координат. Використовує VPS (Visual Positioning System) на основі вуличних даних Google. Точність до 10 см у добре картованих зонах.
Оптимізація для VR: фреймрейт та комфорт
VR вимагає стабільного високого фреймрейту. Просадка нижче цільового значення викликає у користувачів дискомфорт значно гостріше, ніж у звичайних іграх.
| Пристрій | Цільовий Hz | Критичний поріг |
|---|---|---|
| Meta Quest 2 | 72 / 90 Hz | < 72 Hz — помітно |
| Meta Quest 3 | 90 / 120 Hz | < 90 Hz — помітно |
| Valve Index | 90 / 120 / 144 Hz | < 90 Hz — помітно |
| PSVR2 | 90 / 120 Hz | < 90 Hz — помітно |
Single Pass Instanced Rendering
Головна оптимізація рендера в VR. Без неї сцена рендерится двічі (для кожного ока), що подвоює draw calls. Single Pass Instanced рендерить обидва ока за один прохід через instancing: геометрія обробляється один раз, шейдер отримує два view/projection matrix через GPU instancing.
Включається в Unity через XR Plug-in Management > Rendering Mode: Single Pass Instanced. Важливо: кастомні шейдери повинні підтримувати SPI — стандартні URP/HDRP шейдери підтримують, кастомні HLSL вимагають правки (UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX та пов'язані макроси).
Foveated Rendering
На Meta Quest доступен Fixed Foveated Rendering (FFR) — зниження розрізнення на периферії кадру, де гострота сприйняття нижча. Налаштовується через OVRManager або Meta XR SDK:
OVRManager.fixedFoveatedRenderingLevel = OVRManager.FixedFoveatedRenderingLevel.High;
OVRManager.useDynamicFixedFoveatedRendering = true;
Dynamic FFR автоматично підвищує рівень при просадці фреймрейту — зручніше за фіксований у сценах зі змінною навантаженням.
IPD та Comfort Settings
IPD (Inter-Pupillary Distance) — відстань між зіницями, впливає на сприйняття глибини та комфорт при довгому носінні. На програмному рівні в більшості пристроїв доступно тільки читання IPD (OVRPlugin.GetSystemDisplayFrequency), фізична настройка — на гарнітурі. Для додатків із точним позиціюванням (медичні симулятори, тренінги) враховуємо IPD у розрахунках масштабу сцени.
Haptics
Тактильний фідбек — недооцінений інструмент. Навіть простий вібраційний відклик при захваті об'єкту або влученні значно підвищує відчуття присутності.
XR Haptics через OpenXR:
var hapticImpulse = new UnityEngine.XR.HapticCapabilities();
InputDevice device = InputDevices.GetDeviceAtXRNode(XRNode.RightHand);
device.SendHapticImpulse(0, amplitude: 0.5f, duration: 0.1f);
Для складних паттернів (тактильна «текстура» поверхні при дотику, нарастаюча вібрація при натягу тятиви лука) використовуємо Meta Haptics Studio — дозволяє дизайнити haptic-клипи візуально.
Що впливає на вартість та строки
VR/AR проекти дорожчі звичайних ігор аналогічного обсягу з кількох причин:
- Ітерації повільніші — кожну правку потрібно тестувати в гарнітурі, емулятор не передає реальний досвід
- Motion sickness — частину концептуальних рішень доводиться переробляти після першого плейтесту в залізі
- Оптимізація займає істотну долю часу, особливо для мобільного VR (Quest)
- QA вимагає фізичного обладнання, відтворити баги на скриншоті неможливо
Для проектів під Quest починаємо оптимізацію з першого спринту, а не наприкінці — ретрофіт VR-оптимізації у готовий проект у рази дорожче, ніж правильна архітектура з самого початку.





