Oculus 控制台 本节介绍了 PC-SDK 的 Oculus 控制台。
Oculus 控制台将所有 Rift 菜单和用户界面集成到了一个中心,让用户可以在 VR 体验中的任何地方立即访问。在您当前的 VR 体验中,控制台会显示为悬窗,这样您就可以快速从一个应用切换到下一个应用,打开资源库,与朋友联系,甚至无需任何额外步骤即可使用电脑的其他功能。这不仅让 VR 变得更直观、更便捷,还让您以前所未有的方式同时处理多项任务,这对使用 VR 工作的创作者和开发者来说是一个巨大的优势。
控制台使用前准备
您需要确保您的电脑(台式或笔记本电脑)已准备好尽力提供最佳体验。我们整理了以下几点,以便帮助您做好准备:
推荐使用 Windows 10 :Rift Core 2.0 是控制台的基础,突破了 VR 计算的极限。控制台的多任务处理、窗口固定和 Oculus 桌面功能是我们引入的资源密集型系统任务,同时仍然能保持当前的性能标准。Oculus 桌面需要使用 Windows 10。您仍可以使用 Windows 7 和 Windows 8,并享受 Rift Core 2.0 的核心功能,包括全新控制台系统菜单和 Oculus 主控室。但是,您将无法使用 Oculus 桌面等功能进行虚拟计算,控制台也无法在您当前运行的 VR 应用上以悬窗形式运行。更新 GPU 驱动程序 :我们与 AMD 和 NVIDIA 合作,集成驱动程序级别的控制台支持。您需要使用 NVIDIA 和 AMD 的最新驱动程序来运行控制台。点击此处 ,详细了解 GPU 参数。触控优先设计: 我们重新设计了 Rift 核心体验,使其真正实现触控原生体验,您可尽享在直观、易于使用的界面 上进行手势操作的各种优势。虽然许多功能仍可继续在 Xbox 控制器上使用,但一些新功能(例如自定义主控室)只能在 Touch 控制器上使用。简单地说,如果您想充分利用 Rift Core 2.0 的全部功能,请使用 Touch。使用控制台
我们建议在您的应用中添加控制台支持,以尽力提供最佳用户体验。体验可能有所差异,具体取决于您的应用是否提供控制台支持:
如果应用提供控制台支持,当应用暂停时,控制台菜单用户界面将显示在暂停的应用程序上。 如果应用不提供控制台支持,当应用暂停时,系统将在空房间中显示控制台菜单用户界面,类似于早期 Oculus 运行时通用菜单显示的方式。 当启用控制台用户界面时,运行时会渲染出在场景中与菜单进行交互的追踪控制器。您的应用应暂停、静音并隐藏其在场景中渲染的任何追踪控制器,这样就不会出现重复的双手。
当您实施对控制台的支持时,需要考虑三个方面:
输入焦点处理
Oculus CAPI 焦点处理
当启用控制台用户界面时,运行中的应用会失去输入焦点,ovrSessionStatus::HasInputFocus 标记将变回 false。在这种状态下,运行时会渲染出在场景中与菜单进行交互的追踪控制器。
当 HasInputFocus 为 false 时,您的应用应暂停所有动态,静音音频播放,隐藏场景中的任何追踪控制器,避免出现重复的双手,以及隐藏任何近场对象(距离用户一米内)。根据具体的应用,当失去输入焦点时,还可能需要采取额外操作。例如,在多玩家战斗游戏中,您可以希望表明玩家已下线,并采取任何其他适当操作。
当 HasInputFocus 为 False 时,VR 合成器在每个帧周期可能使用多达 3 毫秒的额外渲染时间。因此,只要 HasInputFocusis 为 False 时,如有可能,不妨将应用切换为较低性能模式。等待 HasInputFocus 再次变为 True 时,再恢复此操作。这种方法不是必需的,而且在启用控制台用户界面期间不强制执行性能 VRC 要求。
请注意,当出现应用失去输入焦点的任何其他情况时,HasInputFocus 会变回 false,例如 HMD 从头戴设备移除时。
您可以使用以下代码检查 HasInputFocus 标记:
ovrSessionStatus sessionStatus = {};
ovr_GetSessionStatus(Session, &sessionStatus);
if (!sessionStatus.HasInputFocus) {/*Handle situation where your app has lost input focus*/}
此代码应在每个帧渲染周期执行一次。
OpenXR 焦点处理
当启用控制台用户界面时,运行中的应用会失去输入焦点,会话状态会从 XR_SESSION_STATE_FOCUSED 变为 XR_SESSION_STATE_VISIBLE。在这种状态下,运行时会渲染出在场景中与菜单进行交互的追踪控制器。请注意,XR_SESSION_STATE_FOCUSED 状态也意味着可见状态。
当会话状态从 XR_SESSION_STATE_FOCUSED 切换为 XR_SESSION_STATE_VISIBLE 时,您的应用应暂停所有动态,静音音频播放,隐藏场景中的任何追踪控制器,避免出现重复的双手,以及隐藏任何近场对象(距离用户一米内)。根据具体的应用,当失去输入焦点时,还可能需要采取额外操作。例如,在多玩家战斗游戏中,您可以希望表明玩家已下线,并采取任何其他适当操作。
当控制台可见时,VR 合成器在每个帧周期可能使用多达 3 毫秒的额外渲染时间。因此,只要应用没有焦点时,如有可能,不妨将应用切换为较低性能模式。等待变回 XR_SESSION_STATE_VISIBLE 后,再恢复此操作。这种方法不是必需的,而且在启用控制台用户界面期间不强制执行性能 VRC 要求。
请注意,当出现应用失去输入焦点的任何其他情况时,输入焦点会丢失,例如 HMD 从头戴设备移除时。
会话状态变更可以用以下代码识别:
do {
XrEventDataBuffer event{XR_TYPE_EVENT_DATA_BUFFER};
XrResult result = xrPollEvent(instance, &event);
if (result == XR_SUCCESS) {
switch (event.type) {
case XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED: {
const XrEventDataSessionStateChanged& sessionStateChanged =
*reinterpret_cast<XrEventDataSessionStateChanged*>(&event);
switch(sessionStateChanged.state){
case XR_SESSION_STATE_FOCUSED:
// Application is now focused (and visible)...
break;
case XR_SESSION_STATE_VISIBLE:
// Application is now merely visible and not focused...
break;
...
}
break;
}
}
}
} while(result == XR_SUCCESS)
xrPollEvent 应在每个帧周期重复调用,直至没有更多消息。
深度缓冲支持
CAPI 深度缓冲支持
如果您在用户附近渲染很多几何图形,当控制台面板在与玩家距离更近(相较于与控制台面板的距离)的几何图形顶部渲染时,可能会造成不舒服的视觉差异。为了避免这种差异,您可以使用眼部缓冲区提交深度。这将允许控制台绘制 X 射线效果,防止出现这种不适的情况。出于这个原因,且为了今后的改进,我们建议使用眼部缓冲区提交深度数据。不过,如果您无法做到这一点,我们还是建议最好能支持控制台(并允许差异存在)。
要提交深度数据,请使用如以下示例代码所示的 ovrLayerType_EyeFovDepth。此代码来自 OculusRoomTiny DX11 代码示例(位于 {sdk_folder}\OculusSDK\Samples\OculusRoomTiny\OculusRoomTiny (DX11)\Projects\Windows\VS2015):
// Initialize our single full screen Fov layer.
ovrLayerEyeFovDepth ld = {};
ld.Header.Type = ovrLayerType_EyeFovDepth;
ld.Header.Flags = 0;
for (int eye = 0; eye < 2; ++eye)
{
ld.ColorTexture[eye] = pEyeRenderTexture[eye]->TextureChain;
ld.DepthTexture[eye] = pEyeRenderTexture[eye]->DepthTextureChain;
ld.Viewport[eye] = eyeRenderViewport[eye];
ld.Fov[eye] = hmdDesc.DefaultEyeFov[eye];
ld.RenderPose[eye] = EyeRenderPose[eye];
ld.SensorSampleTime = sensorSampleTime;
ld.ProjectionDesc = posTimewarpProjectionDesc[eye];
}
ovrLayerHeader* layers = &ld.Header;
result = ovr_SubmitFrame(session, frameIndex, nullptr, &layers, 1);
// exit the rendering loop if submit returns an error, will retry on ovrError_DisplayLost
if (!OVR_SUCCESS(result))
goto Done;
frameIndex++;
OpenXR 深度缓冲支持
要启用深度数据提交,请启用 XR_KHR_composition_layer_depth 扩展程序。要提交深度数据,为每个提交到 xrEndFrame 的 XrCompositionLayerProjectionView 结构的下一内容链添加 XrCompositionLayerDepthInfoKHR 实例。深度缓冲由 xrCreateSwapchain 创建,类似于颜色缓冲。
使用示例:
XrFrameEndInfo frameEndInfo = ...;
XrCompositionLayerProjectionView compositionLayerProjection = ...;
XrCompositionLayerDepthInfoKHR depthInfoLayer{XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR};
depthInfoLayer.subImage.swapchain = depthSwapChain;
depthInfoLayer.subImage.imageArrayIndex = 0;
depthInfoLayer.subImage.imageRect = {0, 0, depthSwapChainWidth, depthSwapChainHeight};
depthInfoLayer.minDepth = 0.0;
depthInfoLayer.maxDepth = 1.0;
depthInfoLayer.nearZ = cameraNearZ;
depthInfoLayer.farZ = camearFarZ;
compositionLayerProjection.next = &depthInfoLayer;
const XrCompositionLayerBaseHeader* headerPtrArray[1] = {
reinterpret_cast<const XrCompositionLayerBaseHeader*>(&compositionLayerProjection)};
frameEndInfo.layerCount = 1;
frameEndInfo.layers = headerPtrArray;
XrResult result = xrEndFrame(session.GetSession(), &frameEndInfo);
...
声明以 CAPI 为基础的应用可以感知输入焦点
以 CAPI 为基础的应用应表明它是否准备好响应 ovrSessionStatus 焦点状态,包括 HasInputFocus。如果您的应用已准备好处理焦点丢失,如输入焦点处理 (上文)下所述,请将 ovrInit_FocusAware 标记设为 True,否则将 ovrInit_FocusAware 设为 False。
以 OpenXR 为基础的应用具有原生的输入焦点感知能力,不需要特殊处理。
声明应用可以感知输入焦点
您的应用应表明它是否准备好响应 ovrSessionStatus 焦点状态,包括 HasInputFocus。如果您的应用已准备好处理焦点丢失,如输入焦点处理 (上文)下所述,请将 ovrInit_FocusAware 标记设为 True,否则将 ovrInit_FocusAware 设为 False。
以下代码示例展示了如何设置 ovrInit_FocusAware。此代码来自 OculusRoomTiny DX11 代码示例(位于 {sdk_folder}\OculusSDK\Samples\OculusRoomTiny\OculusRoomTiny (DX11)\Projects\Windows\VS2015):
int WINAPI WinMain(HINSTANCE hinst, HINSTANCE, LPSTR, int)
{
// Initializes LibOVR and the Rift
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.");
VALIDATE(DIRECTX.InitWindow(hinst, L"Oculus Room Tiny (DX11)"), "Failed to open window.");
DIRECTX.Run(MainLoop);
ovr_Shutdown();
return(0);
}