tags: [vr-ar]
Настройка серверной синхронизации положений рук и головы в играх
Позиции в VR обновляются с частотой 72–120 Гц. Если отправлять каждый кадр всем игрокам, трафик на 8 человек составит порядка 50–100 KB/s только на трансформы — и это до игровой логики. Задача сетевой синхронизации VR-аватаров: максимальная точность движений при минимальном трафике и воспринимаемой латентности.
Простое решение — NetworkTransform из Photon Fusion или Netcode for GameObjects — работает, но не оптимизировано под специфику VR. Оно шлёт данные каждый FixedNetworkUpdate без учёта того, двигался ли объект.
Dead Reckoning и предсказание для рук
Техника Dead Reckoning пришла из морской навигации и авиасимуляторов. Для VR-аватаров она работает так: вместо позиции на каждый фрейм клиент отправляет позицию + скорость + угловую скорость. Получатель экстраполирует следующую позицию на основе последнего известного состояния + физической модели движения. Когда приходит следующий пакет — сверяем с предсказанной позицией и корректируем.
В Photon Fusion это реализуется через кастомный NetworkBehaviour с [Networked] свойствами для позиции, ротации и производных. Interpolation и Extrapolation настраиваются в NetworkTransform через InterpolationDataSource:
-
Predicted— клиент-авторитетное предсказание, минимальная воспринимаемая латентность для локального игрока -
Interpolated— с задержкой, но гладко для remote игроков -
Auto— Fusion выбирает сам в зависимости от State Authority
Для рук VR принципиально важно, что Predicted режим применяется только к StateAuthority объекта. Удалённые руки всегда интерполируются, и задержка неизбежна — вопрос в том, насколько гладко она скрывается.
Компрессия трансформов: квантизация и дельта-кодирование
Позиция руки в VR занимает 3 × float32 = 12 байт. Ротация в виде квантерниона — 4 × float32 = 16 байт. Итого 28 байт на одну руку, 56 на две + 28 на голову = 84 байта на игрока без учёта заголовков.
Квантизация снижает это до 3–4 байт на компонент: позиция в рабочей зоне VR (3×3×3 м) с точностью 1 мм кодируется в 15 битов на ось. Ротация через сжатый квантернион (три компонента, четвёртый восстанавливается) — 10 битов на компонент. Итого ~15–20 байт на игрока вместо 84.
В Photon Fusion квантизация включается через NetworkTransform.Precision и RotationPrecision. Для кастомных данных используем INetworkStruct с ручной квантизацией через BitStream.
Дельта-кодирование — следующий уровень: передаём только изменение относительно предыдущего состояния. Рука, которая не двигалась (игрок держит объект неподвижно), отправляет почти нулевую дельту, которая компрессируется до нескольких бит. На практике для VR это даёт 30–60% снижение трафика по сравнению с полными позициями каждый тик.
Авторитетный сервер vs клиентская авторитетность
Это архитектурный выбор с прямыми последствиями для геймплея. Клиентская авторитетность для рук — позиция принимается как есть от клиента — минимальная латентность, максимальная отзывчивость. Но открывает возможность для читов: клиент может присылать «руку» в позиции, куда физически невозможно дотянуться.
Серверная авторитетность — сервер валидирует каждое перемещение руки против физических ограничений (максимальная скорость, зона досягаемости от торса) — устойчиво к читам, но требует RTT-компенсации для ощущения отзывчивости.
Для VR-игр без соревновательной составляющей (совместный опыт, кооперативы) — клиентская авторитетность с базовой серверной валидацией аномалий. Для соревновательных VR — серверная авторитетность с агрессивным клиентским предсказанием и rollback.
Кейс: синхронизация рукопожатия в социальном VR
В VR-социальном пространстве требовалась синхронизация захвата рук между игроками: игроки буквально «жмут руки», и это должно выглядеть корректно для обоих. Проблема: при RTT 80–120 мс позиции рук у двух игроков в момент «контакта» расходились на 5–12 см — рукопожатие выглядело как пустой жест в воздухе.
Решение: специальный «snap» протокол. Когда одна рука входит в коллайдер другой (проверяется на сервере), сервер уведомляет обоих клиентов о событии захвата. Оба клиента переходят в режим «anchor»: один становится ведущим, второй — ведомым. Ведомый интерполирует свою позицию к ведущей с Lerp по 80 мс. Визуально — плавное соединение без телепортации.
| Сложность синхронизации | Ориентировочные сроки |
|---|---|
| Базовая синхронизация трансформов (Photon/NGO) | 1–2 недели |
| Оптимизация трафика + квантизация | +3–5 дней |
| Авторитетный сервер с rollback | 3–6 недель |
| Кастомные взаимодействия (захваты, рукопожатия) | +1–3 недели |
Стоимость рассчитывается после аудита текущей сетевой архитектуры и требований по числу игроков и жанру игры.





