~3 мин чтения

XR / OpenXR — VR-приложения в Godot

XROrigin3D, XRCamera3D, XRController3D — базовая VR-сцена для Meta Quest и SteamVR.

Godot имеет встроенную поддержку OpenXR прямо в core, без отдельных пакетов. На фоне Unity это особенно приятно: запуск VR-проекта в Godot — буквально несколько узлов.

OpenXR в Godot — встроено

OpenXR — открытый стандарт Khronos Group для VR/AR. Заменяет SDK от Oculus, SteamVR, Vive Wave. В Godot 4.x OpenXR — часть engine, активируется в Project Settings → XR.

Активация

  1. Project Settings → XR → OpenXR → Enabled = true.
  2. Выберите interaction profiles: Oculus Touch, Khronos Simple, Valve Index. По умолчанию включены основные.
  3. Для Android (Quest): Build Profile → Android, в Export preset включите XR-permissions.

Базовая сцена

Main (Node3D)
└── XROrigin3D                ← представляет физическую комнату игрока
    ├── XRCamera3D            ← VR-камера, current=true
    ├── XRController3D (Left)  ← controller_tracker = "/user/hand/left"
    │   └── MeshInstance3D    ← визуальная модель контроллера
    └── XRController3D (Right) ← controller_tracker = "/user/hand/right"
        └── MeshInstance3D

Узлы:

  • XROrigin3D — корень VR-rig. Его позиция = центр игровой комнаты.
  • XRCamera3D — камера, привязанная к headset. Двигается, когда игрок физически ходит.
  • XRController3D — узел, отслеживающий контроллер. Position/rotation обновляются автоматически.

Минимальный код для запуска VR

extends Node3D

var xr_interface: XRInterface

func _ready() -> void:
    xr_interface = XRServer.find_interface("OpenXR")
    if xr_interface and xr_interface.is_initialized():
        print("OpenXR initialized!")
        # В Godot для VR-режима нужно выставить viewport
        get_viewport().use_xr = true
    else:
        push_warning("OpenXR not available. Falling back to desktop.")

После этого ваша сцена с XROrigin3D запустится в VR-режиме на подключённом headset.

VR-target по умолчанию — main scene в виде flat-window

Без viewport.use_xr = true ваша сцена откроется как обычное desktop-окно, даже если headset подключён. Это удобно для проверки в “невыезжая в VR”. Когда готовы — выставляете флаг.

Получение input от контроллеров

XR-controller имеет sender’ы для кнопок/осей через input actions, как обычные Input actions в Godot:

  1. В Project Settings → Input Map создайте action vr_select.
  2. Привязка: добавьте OpenXR Action Map → Bind to vr_select (через OpenXR Action Map editor).
  3. В скрипте:
extends XRController3D

func _ready() -> void:
    button_pressed.connect(_on_button)
    button_released.connect(_on_button_released)
    input_float_changed.connect(_on_float_input)

func _on_button(name: String) -> void:
    if name == "trigger_click":
        _on_trigger_pressed()

func _on_trigger_pressed() -> void:
    print("Right trigger pressed")
    # Можно выпустить raycast / instantiate projectile

XRController3D имеет встроенные сигналы:

  • button_pressed(name), button_released(name)
  • input_float_changed(name, value) — для analog axes (trigger, grip)
  • input_vector2_changed(name, value) — для thumbsticks

Grab — взять предмет

Простейший grab без community-плагинов:

extends XRController3D

@export var grab_area: Area3D  # ребёнок XRController3D со сферой ~5cm
var held_object: RigidBody3D

func _ready() -> void:
    button_pressed.connect(_on_button)

func _on_button(name: String) -> void:
    if name == "grip_click":
        if held_object == null:
            _try_grab()
        else:
            _release()

func _try_grab() -> void:
    var bodies := grab_area.get_overlapping_bodies()
    for body in bodies:
        if body is RigidBody3D and body.has_method("on_grabbed"):
            held_object = body
            held_object.freeze = true
            held_object.reparent(self)
            return

func _release() -> void:
    if held_object == null:
        return
    held_object.reparent(get_tree().current_scene)
    held_object.freeze = false
    # Можно пересчитать velocity из недавнего движения контроллера
    held_object = null

Для серьёзного VR-проекта используйте плагин godot-xr-tools (Asset Library) — он имеет готовые grabbable, teleporter, climbing, hand poses. Аналог Unity XRI.

Hand tracking

Godot 4.6 поддерживает hand tracking через OpenXR Hand Tracking extension:

  1. Project Settings → OpenXR → Extensions → Hand Tracking = enabled.
  2. Узлы XRHandModifier3D (4.6+) или OpenXRInterface.hand_tracking_enabled в коде.
  3. Получаете доступ к 26 joint’ам каждой руки через XRPose lookup.
var xr := XRServer.find_interface("OpenXR")
var left_hand_pose := XRServer.get_tracker("/user/hand/left").get_pose("default")

Performance в VR

Те же жёсткие требования, что и в Unity:

  • 72 FPS на Quest 2/3, 90+ на PCVR.
  • Mobile renderer обязателен для Quest standalone.
  • MSAA 4× — стандарт для VR.
  • Multiview rendering (single-pass) — включается через Project Settings → Rendering → Performance → Multiview.
  • Foveated rendering — Project Settings → OpenXR → Foveation Level (Low/Med/High).

Стандартный пайплайн разработки

  1. Локальный тест в editor через Quest Link (USB или AirLink).
  2. После полировки — standalone build для Quest (.apk через Android export).
  3. Установка через adb или Meta Quest Developer Hub.

Plugin godot-xr-tools

Большинство VR-проектов в Godot опираются на community-плагин godot-xr-tools (через Asset Library). Что он даёт:

  • XRToolsFunctionPointer — луч из контроллера для дальнего выбора.
  • XRToolsFunctionPickup — продвинутый grab с throw-velocity, snap-points.
  • XRToolsFunctionTeleport — teleport-locomotion с правильным fade и validation.
  • XRToolsHandPoseController — анимация поз руки в зависимости от того, что схвачено.
  • XRToolsMovementProvider — direct/snap/smooth turn, climbing, gliding.

Если планируете серьёзный VR-проект — поставьте сразу.

Сравнение Godot vs Unity для VR

GodotUnity
OpenXR в core✅ встроено❌ требует OpenXR Plugin package
Interaction toolkit⚠️ community (godot-xr-tools)✅ official (XRI)
Hand-tracking✅ с 4.6✅ XR Hands package
Performance в VRХорошоХорошо (Single-Pass Instanced)
Magic Leap / Vision ProLimitedЛучше (полная поддержка через XR Hub)
Размер билда (минимум)~40 MB~80 MB

Для hobby-проекта Quest 2 Godot часто проще. Для commercial AAA-VR Unity всё ещё впереди за счёт XRI и broader device support.