Set up an OpenXR project
Startup settings, XR rig, tracker/pose, action map and diagnostics.
This section configures an OpenXR project and minimal XR rig. It requires an OpenXR-enabled engine build and the target device’s runtime. A registered XRInterface does not establish that a headset is connected or a session can be created.
Settings before startup
Save the project and configure:
| Project Settings | Value |
|---|---|
xr/openxr/enabled | true |
xr/shaders/enabled | true for the XR rendering described here |
xr/openxr/default_action_map | Prepared map path; initially asset://openxr_action_map.rdata |
Perform the required editor restart. These control startup and graphics preparation: changing them in _Ready() does not replace launching with the correct configuration. On PC, check the device’s active OpenXR runtime before starting the project.
The example can use Mobile or Forward+, depending on target budget and required effects. The runtime and device must also support the chosen graphics path. Do not assume one renderer is universally fastest across headsets; measure the project on its target. OpenXR configuration is not WebXR configuration.
Use CLI --xr-mode off for a separate ordinary run. This disables XR at startup rather than connecting a headset. --xr-mode on neither installs a missing runtime nor guarantees initialization.
Build the rig
Example Entity hierarchy:
Main (Entity3D)
├── XRSession (Entity, XrStartup.cs, ProcessMode=Always)
├── XROrigin3D (ProcessMode=Always)
│ ├── XRCamera3D
│ ├── LeftHand (XRController3D)
│ └── RightHand (XRController3D)
├── Gameplay (Entity3D, ProcessMode=Pausable)
└── Interface (CanvasLayer, ProcessMode=Always)XROrigin3D places the XR-space origin in the game world. Camera and controllers must be its direct child Entities. Move the origin or its controlling object for player locomotion rather than overwriting the tracked head pose each frame.
Set LeftHand.Tracker=left_hand and RightHand.Tracker=right_hand. With the default map, choose Pose=grip. Naming Entities LeftHand/RightHand does not select a tracker. Default-map pose actions grip_pose, aim_pose and default_pose are published on trackers as grip, aim and default. Account for the action name when using a custom pose.
Convenient initial editor positions do not establish tracking. Without data, XRController3D remains inactive; a stationary controller model is not proof of successful connection.
Map and startup
Prepare the action map before XR-session creation. That guide’s minimal select map contains only a selection button. Add appropriate Pose actions and bindings or configure the default map for hand tracking; one button does not create pose tracking.
Attach the complete startup script to XRSession. One controller should serve one selected Viewport. After initialization succeeds, it sets UseXR on its Viewport. It restores the original value when leaving the tree. It does not free the interface borrowed from XRServer or the borrowed Viewport.
Initialize()==true and IsInitialized()==true do not mean the game has focus. Wait for Focused before game input. Visible means the image is visible but XR input is unavailable; that transition does not mean headset disconnection. OpenXR session states.
Check on the device
- The headset receives an image; UseXR belongs to the Viewport providing XR output.
- Head rotation/translation changes the view without manually driving the camera from a script.
- Both hands receive tracking; tracker and pose match the map.
selectworks in Focused; a system menu causes the game to handle focus loss and stop unsafe game actions.- Regaining focus does not clear an independent game-menu pause. Session stopping follows the intended XR-exit or ordinary-mode policy.
Black image: check startup failure, camera, intended Viewport, UseXR, runtime and graphics path. Missing hands: check tracker, pose, map actions and tracking data, then model visibility. No presses: check focus, active set and bindings. Map changes absent: check its path and restart the session.
Rig construction, tracker/pose properties and disabled-XR script failure were checked in the current engine without a headset. Positive initialization, stereo output, tracking, editor interaction and the device checks above were not performed. Complete them on the target runtime.