VR 焦点管理
提交应用程序时需提供必要的应用程序和元数据,以确保其能够在 Rift Store 列出,并从 Oculus Home 启动。
当从 Oculus Home 启动后,您需要编写一个循环来轮询会话状态。ovr_GetSessionStatus 返回包含以下布尔值的结构:
ShouldQuit - 如果应用程序应该发起关闭,则为 True。HmdPresent - 如果存在 HMD,则为 True。DisplayLost - 如果 HMD 已拔出,或显示驱动程序被手动禁用或出现 TDR,则为 True。HmdMounted - 如果 HMD 戴在用户头上,则为 True。IsVisible - 如果游戏或体验有 VR 焦点并在 HMD 中可见,则为 True。ShouldRecenter - 如果应用程序应调用 ovr_RecenterTrackingOrigin,则为 True。这在用户通过通用菜单发起重新居中时触发。OverlayPresent - 如果存在系统叠加(例如面板),则为 True。DepthRequested - 如果运行时要求应用程序提供带投影层的深度缓冲区,则为 True。
当 ShouldQuit 为 true 时,保存应用程序状态并关闭,或者不保存状态直接关闭。用户将自动返回 Oculus Home。
依据应用程序的类型,您可以在下次打开时提示用户从上次中断处继续(如多关卡游戏),或者从体验起始点重新开始(如被动视频)。如果是多人游戏,则您可能想要在本地退出游戏,而不结束游戏。
当 ShouldRecenter 为 true 时,应用程序应调用 ovr_RecenterTrackingOrigin 或 ovr_SpecifyTrackingOrigin,为以后根据不同的原点进行位置追踪做好准备。
某些应用程序可能会选择忽略此请求,或通过 ovr_RecenterTrackingOrigin 以外的内部机制来实现该请求。在此情况下,应用程序可调用 ovr_ClearShouldRecenterFlag 清除重新居中请求。
如果 DisplayLost 为 true:
- 暂停应用程序,包括音频。
- 在显示器上显示头戴设备已拔出的提示。
- 销毁所有 TextureSwapChains 或镜像纹理。
- 调用
ovrDestroy。 - 轮询
ovrSessionStatus::HmdPresent,直到 true。 - 调用
ovrCreate 重新创建会话。 - 重新创建任何
TextureSwapChain 或镜像纹理。 - 恢复应用程序。
如果 ovrDetect 在指定时间内未返回 true,则按 ShouldQuit 返回 true 处理。如果用户未在指定时间内执行任何操作,则选择默认操作(保存会话或不保存直接关闭)并关闭应用程序。
注:在多人游戏中,您可能想按照相同的流程进行,而不是暂停游戏。
如果用户取下头戴设备,或应用程序失去 VR 焦点,则 HmdMounted 或 IsVisible 返回 false。暂停应用程序,直到返回 true。
如果您的应用程序失去 VR 焦点,则自动停止接收输入。如果您的应用程序不使用 Oculus 输入 API,则应忽略任何接收到的输入。
注:在多人游戏中,您可能希望游戏在不暂停的情况下继续。
当您的应用程序失去 Windows 焦点时,Oculus Remote、Xbox 控制器和 Touch 控制器仍会继续正常运作。但是,应用程序将无法继续控制鼠标和键盘。
如果您的应用程序失去 Windows 焦点但保持 VR 焦点(IsVisible),应继续接收输入,确保应用程序正常运行。如果继续操作需要键盘或鼠标,提示用户取下头戴设备并通使用 Alt-Tab 恢复 Windows 焦点。
随着面板的引入,现在您的应用程序应表明其是否准备好响应 ovrSessionStatus 焦点状态,包括
ovrSessionStatus::HasInputFocus。如需了解更多信息,请参阅
Oculus Dash。
bool shouldQuit = false;
void RunApplication()
{
ovrInitParams initParams = { ovrInit_RequestVersion | ovrInit_FocusAware, OVR_MINOR_VERSION, NULL, 0, 0 };
ovrResult result = ovr_Initialize(&initParams);
VALIDATE(OVR_SUCCESS(result), "Failed to initialize libOVR.");
if (OVR_SUCCESS(result))
{
ovrSession session;
ovrGraphicsLuid luid;
result = ovr_Create(&session, &luid);
result = ovr_WaitToBeginFrame(session, 0);
result = ovr_BeginFrame(session, 0);
if (OVR_SUCCESS(result))
{
ovrSessionStatus ss;
<create graphics device with luid>
<create render target via ovr_CreateTextureSwapChain>
while (!shouldQuit)
{
<get next frame pose, e.g. via ovr_GetEyePoses>
<render frame>
result = ovr_EndFrame(...);
if (result == ovrSuccess_NotVisible)
{
<turn off audio output>
do { // Wait until we regain visibility or should quit
<sleep>
result = ovr_GetSessionStatus(session, &ss);
if (ss.ShouldQuit)
shouldQuit = true;
} while (OVR_SUCCESS(result) && !ss.IsVisible && !shouldQuit);
<possibly re-enable audio>
}
else if (result == ovrError_DisplayLost)
{
// We can either immediately quit or do the following:
<destroy render target and graphics device>
ovr_Destroy(session);
do { // Spin while trying to recreate session.
result = ovr_Create(&session, &luid);
} while (OVR_FAILURE(result) && !shouldQuit);
if (OVR_SUCCESS(result))
{
<recreate graphics device with luid>
<recreate render target via ovr_CreateTextureSwapChain>
}
}
else if (OVR_FAILURE(result))
{
shouldQuit = true;
}
ovr_GetSessionStatus(session, &ss);
if (ss.ShouldQuit)
shouldQuit = true;
if (ss.ShouldRecenter)
{
ovr_RecenterTrackingOrigin(session); // or ovr_ClearShouldRecenterFlag(session) to ignore the request.
<do anything else needed to handle this>
}
}
<destroy render target via ovr_DestroyTextureSwapChain>
<destroy graphics device>
ovr_Destroy(session);
}
ovr_Shutdown();
}
}
应用程序在 OpenXR 下的行为预期与在 LibOVR CAPI 下相同,唯一的区别是 OpenXR API 主要通过会话状态变更事件来呈现焦点状态的变化。OpenXR 的会话状态与 LibOVR CAPI ovrSessionStatus 类似,具体如下:
ShouldQuit - XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED / XR_SESSION_STATE_EXITINGHmdPresent - 没有 OpenXR 对应功能。OpenXR 应用程序可使用 ovr_Detect。DisplayLost - XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED / XR_SESSION_STATE_LOSS_PENDINGHmdMounted - XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED / XR_SESSION_STATE_READY,XR_SESSION_STATE_STOPPINGIsVisible - XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED / XR_SESSION_STATE_VISIBLE,XR_SESSION_STATE_SYNCHRONIZEDShouldRecenter - XR_TYPE_EVENT_DATA_RECENTER_REQUESTED_OCULUS,由 XR_OCULUS_recenter_event 扩展启用。HasInputFocus - XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED / XR_SESSION_STATE_FOCUSED,XR_SESSION_STATE_VISIBLEOverlayPresent - 不需要或没有 OpenXR 对应功能。DepthRequested - 没有 OpenXR 对应功能。当 XR_KHR_composition_layer_depth 扩展启用时,应始终提供深度缓冲区。