设置 XR
Godot 的 XR 系统简介
Godot 引擎内置了一套模块化扩展现实(XR)系统,该系统通过抽象化不同 XR 平台的底层实现细节,以简化跨平台 XR 应用的开发流程。该系统的核心是 XRServer 类,它作为整个 XR 架构的中枢接口,允许开发者通过该接口发现并连接各类 XR 运行时环境。
Each supported XR platform is implemented as an XRInterface.
A list of supported platforms can be found on the list of features page here.
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.
警告
已注册的接口仅意味着该接口可用,如果主机系统不支持接口,初始化可能会失败并返回 false。不幸的是,初始化失败的原因在不同平台上各不相同:可能是因为用户没有安装所需软件,或者是根本没插入头戴设备。作为开发者,你必须对接口初始化失败的情况准备好应对措施。
由于 XR 对输出有特殊要求——尤其是头戴设备要为双眼提供不同的图像输出,Godot 中的 XRServer 将覆盖渲染系统的大部分功能。对于独立设备来说,最终输出由 XRInterface 处理,而 Godot 的常规输出系统将被禁用。对于作为第二屏幕使用的桌面 XR 设备来说,可以使用独立的 Viewport 来处理 XR 输出,从而使 Godot 的主窗口能显示其他内容。
备注
请注意,只能有一个主接口负责处理输出到 XR 设备,默认情况下它将是第一个被初始化的接口。 Godot 目前仅支持单个头戴设备的实现。不过,也有可能存在第二个接口(比如为仅支持 3DOF 的设备添加跟踪功能),但这种情况已经愈发少见。
There are three XR specific node types that you will find in nearly all XR applications:
XROrigin3D 在所有意图和目的上都代表了游戏空间的中心点。这是一个过于简单的说法,但我们稍后会更详细地解释。XR 平台在物理空间中跟踪的所有对象都相对于此点定位。
XRCamera3D 代表着在为 XR 设备渲染输出时使用的(立体)摄像机。该节点的定位由 XR 系统控制,并基于 XR 平台提供的跟踪信息自动更新。
XRController3D 代表玩家使用的控制器,通常有两个:左右手各一个。该节点提供对控制器上各种状态的访问,并在玩家按下按钮时发送信号。节点的定位由 XR 系统控制,并基于 XR 平台提供的跟踪信息自动更新。
还有其他与 XR 相关的节点,并且关于这三个节点还有更多内容可以讨论,具体将稍后再谈。
使用哪些渲染器
Godot 为项目提供了 3 种渲染器:兼容(Compatibility)、移动(Mobile)和 Forward+。目前的建议是,对于任何桌面 VR 项目使用移动渲染器,对于在独立头显(如 Meta Quest 3)上运行的项目使用兼容渲染器。XR 项目可以使用 Forward+ 渲染器运行,但与另外两种渲染器相比,目前它针对 XR 的优化还不够完善。
OpenXR
OpenXR is a new industry standard that allows different XR platforms to present themselves through a standardized 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 包含为核心接口的主要决定因素之一。
This also means OpenXR needs to be enabled when Godot starts in order to set things up correctly. Check the Enabled setting in your project settings under XR > OpenXR.
You can find several other settings related to OpenXR here as well. These can't be changed while your application is running. The default settings will get us started, but for more information on what's here see OpenXR 设置.
You'll also need to go to XR > Shaders in the project settings and check the Enabled box to enable them. Once you've done that click the Save & Restart button.
警告
Many post process effects have not yet been updated to support stereoscopic rendering. Using these will have adverse effects.
设置 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:
The warning icons are expected and should go away after you configure the controllers. Select the left hand and set it up as follows:
将脚本添加到节点:
现在,所有节点都在场景的平面上,它们将在运行时自动正确定位。为了帮助开发期间的调试,可以将相机向上移动,再把 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:
extends Node3D
var xr_interface: XRInterface
func _ready():
xr_interface = XRServer.find_interface("OpenXR")
if xr_interface and xr_interface.is_initialized():
print("OpenXR initialized successfully")
# Turn off v-sync!
DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED)
# Change our main viewport to output to the HMD
get_viewport().use_xr = true
else:
print("OpenXR not initialized, please check if your headset is connected")
using Godot;
public partial class MyNode3D : Node3D
{
private XRInterface _xrInterface;
public override void _Ready()
{
_xrInterface = XRServer.FindInterface("OpenXR");
if(_xrInterface != null && _xrInterface.IsInitialized())
{
GD.Print("OpenXR initialized successfully");
// Turn off v-sync!
DisplayServer.WindowSetVsyncMode(DisplayServer.VSyncMode.Disabled);
// Change our main viewport to output to the HMD
GetViewport().UseXR = true;
}
else
{
GD.Print("OpenXR not initialized, please check if your headset is connected");
}
}
}
上述代码片段假设我们正在使用 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.
在接下来的基础教程中,我们将创建一个只使用单场景的游戏作为练习。