id: 237 slug: vr-network-motion-interpolation-algorithm-development title_ua: "Розробка алгоритмів інтерполяції рухів у мережевих VR-іграх" tags: [vr-ar]
Розробка алгоритмів інтерполяції рухів у мережевих VR-іграх
У звичайному мережевому шутері інтерполяція позиції персонажа з затримкою 50–80 мс непомітна: модель чуть запізнюється, але це норма сприйняття. У VR це не працює. Голова та руки іншого гравця повинні рухатися без ривків — інакше мозок сприймає це як щось неприродне та це руйнує відчуття присутності. При цьому HMD відправляє дані трекінгу з частотою 72–120 Гц, а мережа доставляє пакети нерегулярно.
Чому стандартна інтерполяція погано працює для VR-аватарів
Типова помилка — застосовувати для VR-аватара ті ж алгоритми, що для ігрових об'єктів. Vector3.Lerp між двома отриманими позиціями з фіксованим t=0.1 дає «гумове» запаздування, особливо помітне на рухах кистей рук: рука продовжує рухатися до старої цілі, коли вже отримана нова позиція.
Корінь проблеми в різниці частот: рендер VR-сцени — 90 Hz (11 мс/кадр), мережеві оновлення — 20–30 пакетів в секунду (33–50 мс/пакет). Між двома мережевими снімками потрібно сгенерувати 3–4 проміжних состояния. І робити це потрібно з врахуванням того, що jitter (варіація затримки пакетів) може досягати 20–30 мс навіть на хорошому з'єднанні.
Голова та руки аватара — специфічна задача: голова рухається плавно й передбачувано (слідує за фізичним рухом у просторі), руки — швидко й непередбачувано. Один алгоритм для обох неоптимальна.
Алгоритми інтерполяції для VR-трекінгу
Dead Reckoning з коректировкой (Predictive Interpolation). Зберігаємо буфер останніх N станів (позиція + орієнтація + швидкість + час). При рендері обчислюємо передбачену позицію на основі останньої відомої швидкості: predictedPos = lastKnownPos + velocity * deltaTime. При отриманні нового мережевого пакета плавно коригуємо до реальної позиції за 3–5 кадрів. Швидкість обчислюємо як (currentPos - prevPos) / packetDeltaTime та згладжуємо через EMA (Exponential Moving Average) з α=0.3.
Цей підхід добре працює для голови, де рух інерційна. Для рук — гірше: рука може миттєво зупинитися або різко змінити напрямок.
Hermite Spline Interpolation — для плавних криволінійних рухів. Будуємо сплайн через останні 4 точки трекінгу з дотичними (похідними). Значно краще, ніж лінійна інтерполяція на жестах та повільних рухах. Реалізується як HermiteInterpolate(p0, p1, m0, m1, t) де m0/m1 — дотичні у точках.
Jitter Buffer — обов'язковий компонент системи. Тримаємо буфер вхідних пакетів на 2–3 мережевих кадра (60–100 мс). Рендеримо завжди з буфера, а не з останнього пакета. Це додає затримку, але убирає ривки від нерегулярного приходу пакетів. Розмір буфера адаптуємо динамічно: якщо jitter зростає (визначаємо через стандартне відхилення interpacket interval за останні 10 пакетів) — збільшуємо буфер, якщо стабілізується — зменшуємо.
Орієнтація через Quaternion Slerp, не Lerp. Quaternion.Lerp дає нелінійну швидкість обертання при великих кутах. Quaternion.Slerp — правильний вибір для трекінгу голови. Для IK-розв'язувача запястя при відновленні з motion data важливо також нормалізувати кватерніон після інтерполяції — накопичені float-помилки за кілька кадрів дають артефакти в FK.
Inverse Kinematics для тіла аватара
HMD + два контролери дають 3 точки трекінгу. З них потрібно відновити пози плеч, ліктів, хребта. Для цього використовуємо IK-розв'язувач:
У Unity — Animation Rigging (пакет com.unity.animation.rigging) з TwoBoneIK Constraint для рук та ChainIKConstraint для хребта. Налаштування hint objects для ліктів критично: без них руки складаються в неприродні пози. Позицію hint обчислюємо аналітично від позиції контролера та напрямку до тіла.
Для складніших тіл та Full Body IK — FinalIK (Ootii) або кастомний FABRIK-розв'язувач. FABRIK (Forward And Backward Reaching IK) ітеративно сходиться за 5–10 ітерацій, достатньо для real-time.
Етапи роботи
Профілювання мережі. Замір реального jitter, packet loss, RTT на цільовій аудиторії.
Вибір алгоритмів під вимоги. Баланс між візуальною плавністю та затримкою відклику.
Реалізація Jitter Buffer + інтерполяції. Окремий NetworkAvatarController з ізольованою логікою.
IK налаштування. Калібрування під цільові антропометрії, тест на крайніх значеннях (короткі/довгі руки).
Тестування при деградації мережі. Симуляція через tc netem (Linux) або Clumsy (Windows): 200 мс latency, 10% packet loss, 50 мс jitter.
| Масштаб | Орієнтовні строки |
|---|---|
| Базова інтерполяція (голова + руки) | 1–2 тижні |
| Full Body IK + адаптивний Jitter Buffer | 3–6 тижнів |
| Повна система з аналітикою та навантажувальним тестом | 2–3 місяці |
Вартість розраховується після аналізу вимог точності та цільових умов мережі.





