设置 XR

Godot 的 XR 系统简介

Godot provides a modular XR system that abstracts many of the different XR platform specifics away from the user. At the core sits the XRServer which acts as a central interface to the XR system that allows users to discover interfaces and interact with the components of the XR system.

Each supported XR platform is implemented as an XRInterface. Supported interfaces register themselves with the XRServer and can be queried with the find_interface method on the XRServer. When the desired interface is found it can be initialized by calling initialize on the interface.

警告

A registered interface means nothing more than that the interface is available, if the interface is not supported by the host system, initialization may fail and return false. This can have many reasons and sadly the reasons differ from platform to platform. It can be because the user hasn’t installed the required software, or that the user simply hasn’t plugged in their headset. You as a developer must thus react properly on an interface failing to initialize.

Due to the special requirements for output in XR, especially for head mounted devices that supply different images to each eye, the XRServer in Godot will override various features in the rendering system. For stand-alone devices this means the final output is handled by the XRInterface and Godot’s usual output system is disabled. For desktop XR devices that work as a second screen it is possible to dedicate a separate Viewport to handle the XR output, leaving the main Godot window available for displaying alternative content.

备注

Note that only one interface can be responsible for handling the output to an XR device, this is known as the primary interface and by default will be the first interface that is initialized. Godot currently thus only supports implementations with a single headset. It is possible, but increasingly uncommon, to have a secondary interface, for example to add tracking to an otherwise 3DOF only device.

There are three XR specific node types that you will find in nearly all XR applications:

  • :ref:`XROrigin3D <class_xrorigin3d>`代表着游戏空间的中心点。这种说法易于理解,但有些过于简化,我们稍后会详细解释。XR 平台跟踪的所有物体都是相对于这一点定位的。

  • :ref:`XRCamera3D <class_xrcamera3d>`代表着在为 XR 设备渲染输出时使用的(立体)摄像机。该节点的定位由 XR 系统控制,并基于 XR 平台提供的跟踪信息自动更新。

  • :ref:`XRController3D <class_xrcontroller3d>`代表玩家使用的控制器,通常有两个:左右手各一个。该节点提供对控制器上各种状态的访问,并在玩家按下按钮时发送信号。节点的定位由 XR 系统控制,并基于 XR 平台提供的跟踪信息自动更新。

There are other XR related nodes and there is much more to say about these three nodes, but we’ll get into that later on.

在 Godot 4 中使用 XR 的先决条件

While in Godot 3 most things worked out of the box, Godot 4 needs a little more setup. This is mainly due to the more advanced nature of the Vulkan renderer. There are many rendering features in Vulkan the XR system uses that aren’t enabled by default. They are very easy to turn on, simply open up your project settings and tick the XR shaders tickbox in the XR section:

../../_images/xr_shaders.png

警告

由于 Godot 4 仍在开发中,许多后期处理效果尚未更新以支持立体渲染。使用这些效果将产生不良影响。

备注

Godot 4 has 3 renderer options, Compatibility, Mobile, and Forward+. In the future XR desktop projects should use Forward+, and projects for stand-alone headsets should use Mobile. However Compatibility is the recommended renderer for now due to it having the best XR performance.

OpenXR

OpenXR is a new industry standard that allows different XR platforms to present themselves through a standardised API to XR applications. This standard is an open standard maintained by the Khronos Group and thus aligns very well with Godot’s interests.

OpenXR 的 Vulkan 实现与 Vulkan 紧密集成,并接管了 Vulkan 系统的一部分。这就要求在设置 XR 系统之前,需要对 Vulkan 渲染器中的某些核心图形功能先行集成。这是将 OpenXR 包含为核心接口的主要决定因素之一。

这也意味着需要在 Godot 启动时启用 OpenXR,以便正确设置。启动页面可在项目设置中找到:

../../_images/openxr_settings.png

你还可以在这里找到与 OpenXR 相关的其他设置。这些设置在应用程序运行时无法更改。默认设置即可让我们开始工作,并且我们将在文档的另一部分详细介绍这些设置。

设置 XR 场景

Every XR application needs at least an XROrigin3D and an XRCamera3D node. Most will have two XRController3D, one for the left hand and one for the right. Keep in mind that the camera and controller nodes should be children of the origin node. Add these nodes to a new scene and rename the controller nodes to LeftHand and RightHand, your scene should look something like this:

../../_images/xr_basic_scene.png

接下来,你需要配置控制器。选择左手控制器,并按如下方式进行设置:

../../_images/xr_left_hand.png

将脚本添加到节点:

../../_images/xr_right_hand.png

现在,所有节点都在场景的平面上,它们将在运行时自动正确定位。为了帮助开发期间的调试,可以将相机向上移动,再把 y 轴设置为 1.7,并将控制器节点分别移动到 ``-0.5, 1.0, -0.5``(左手)和 ``0.5, 1.0, -0.5``(右手)。

Next we need to add a script to our root node. Add the following code into this script:

GDScriptC#

  1. extends Node3D
  2. var xr_interface: XRInterface
  3. func _ready():
  4. xr_interface = XRServer.find_interface("OpenXR")
  5. if xr_interface and xr_interface.is_initialized():
  6. print("OpenXR initialized successfully")
  7. # Turn off v-sync!
  8. DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED)
  9. # Change our main viewport to output to the HMD
  10. get_viewport().use_xr = true
  11. else:
  12. print("OpenXR not initialized, please check if your headset is connected")
  1. using Godot;
  2. public partial class MyNode3D : Node3D
  3. {
  4. private XRInterface _xrInterface;
  5. public override void _Ready()
  6. {
  7. _xrInterface = XRServer.FindInterface("OpenXR");
  8. if(_xrInterface != null && _xrInterface.IsInitialized())
  9. {
  10. GD.Print("OpenXR initialized successfully");
  11. // Turn off v-sync!
  12. DisplayServer.WindowSetVsyncMode(DisplayServer.VSyncMode.Disabled);
  13. // Change our main viewport to output to the HMD
  14. GetViewport().UseXR = true;
  15. }
  16. else
  17. {
  18. GD.Print("OpenXR not initialized, please check if your headset is connected");
  19. }
  20. }
  21. }

上述代码片段假设我们正在使用 OpenXR,如果你希望使用其他接口,可以更改``find_interface`` 调用。

警告

正如你看到的,我们在代码中关闭了垂直同步(DisplayServer.VSYNC_DISABLED)。在使用 OpenXR 时,将渲染结果输出到一个头戴显示器(HMD)通常需要以 90Hz 或更高的频率运行。如果你的显示器是 60Hz 且开启了垂直同步,那么输出将限制在每秒 60 帧。

像 OpenXR 这样的 XR 接口会执行它们自己的同步。

同时请注意,默认情况下物理引擎以 60Hz 运行,渲染和物理帧数不一致可能会导致物理效果不流畅。你应该将 Engine.physics_ticks_per_second 设置为更高的值。

If you run your project at this point in time, everything will work but you will be in a dark world. So to finish off our starting point add a DirectionalLight3D and a WorldEnvironment node to your scene. You may wish to also add a mesh instance as a child to each controller node just to temporarily visualise them. Make sure you configure a sky in your world environment.

完成配置后运行项目,你应该会漂浮在某个空间中,并能够四处观察。

备注

While traditional level switching can definitely be used with XR applications, where this scene setup is repeated in each level, most find it easier to set this up once and loading levels as a subscene. If you do switch scenes and replicate the XR setup in each one, do make sure you do not run initialize multiple times. The effect can be unpredictable depending on the XR interface used.

在接下来的基础教程中,我们将创建一个只使用单场景的游戏作为练习。