Oculus Dash このセクションでは、PC-SDKのOculus Dashを紹介します。
Oculus Dashは、RiftのすべてのメニューとUIを、VRエクスペリエンス内のどこからでもすぐにアクセスできるセントラルハブにまとめて表示します。Dashは現在のVRエクスペリエンス内でオーバーレイとして実行されるので、1つのアプリから次のアプリに素早く切り替える、ライブラリを開く、友達とつながる、さらにはPCの他の機能を使用するといった操作が追加の手順なしで可能です。VRがさらに直感的で使いやすくなるだけでなく、これまでになかったようなマルチタスク操作が可能になります。このことは、作業中にVRを使用するクリエイターや開発者にとっては大きなメリットです。
Dashを使用するための準備
最良のエクスペリエンスを実現するためには、コンピューター(デスクトップまたはノートパソコン)の準備をしておく必要があります。開始する上で役立ついくつかの指針を次に示します。
Windows 10を推奨: Dashの基盤となるRift Core 2.0は、VRコンピューティングの境界線を押し広げるものです。Dashのマルチタスキング、ウィンドウのピン留め、Oculusデスクトップの機能は、現行のパフォーマンス水準を維持しつつ導入した、リソースを大量に消費するシステムタスクです。Oculusデスクトップを使用するにはWindows 10が必要です。Windows 7およびWindows 8であっても、新しいDashシステムメニューやOculusホームなど、Rift Core 2.0のコア機能は利用できます。ただし、バーチャルコンピューティング用のOculusデスクトップなどの機能を使用したり、現在実行中のVRアプリの上でオーバーレイとしてDashを実行したりすることはできません。GPUドライバーのアップデート: Oculusでは、AMDとNVIDIAの両社と連携して、Dashのサポートをドライバーレベルで組み込みました。Dashを実行するには、NVIDIAおよびAMDの最新のドライバーが必要です。GPUの仕様について詳しくは、こちらをクリック してください。Touchファースト設計: Oculusでは、真のTouchネイティブとなるようRiftのコアエクスペリエンスを設計し直し、直感的で使いやすいインターフェイス でハンドプレゼンスのすべての利点を提供できるようにしました。多くの機能は引き続きXboxコントローラーで動作しますが、ホームのカスタマイズなど、一部の新機能にはTouchが必要です。つまり、Rift Core 2.0のすべての機能を最大限に活用するには、Touchが必要です。Dashの使用
最良のユーザーエクスペリエンスを実現するために、Dashサポートをアプリに追加することをおすすめします。アプリがDashをサポートしているかどうかによってエクスペリエンスが異なってきます。
Dashをサポートするアプリの場合、一時停止すると、DashメニューUIが一時停止したアプリの上に表示されます。 Dashをサポートしないアプリの場合、一時停止すると、以前のOculusランタイムでユニバーサルメニューが表示されていたときに同じように、DashメニューUIが何もない空間に表示されます。 Dash UIがアクティブになると、ランタイムはトラッキングされているコントローラーをシーン内にレンダリングし、メニューを操作できるようにします。アプリは一時停止し、ミュートし、シーン内にレンダリングされているトラッキングされたコントローラーを非表示にするので、手が重複して表示されることはありません。
Dashサポートを実装する際には、次の3つの分野を考慮する必要があります。
入力フォーカスの処理 深度バッファのサポート アプリが入力フォーカス対応であることを宣言する 入力フォーカスの処理
Oculus CAPIのフォーカス処理
Dash UIがアクティブになると、実行中のアプリは入力フォーカスを失い、ovrSessionStatus::HasInputFocusフラグがfalseを返すようになります。この状態で、ランタイムはメニューを操作できるように、トラッキングされているコントローラーをシーン内にレンダリングします。
HasInputFocusがfalseの場合、アプリはすべてのアクティビティを一時停止し、オーディオ再生をミュートし、トラッキングされているコントローラーをシーン内で非表示にするので、手が重複して表示されることはなく、近く(ユーザーから約1メートル以内)にあるフィールドオブジェクトは非表示になります。アプリによっては、入力フォーカスが失われたときに、追加のアクションが必要になる場合があります。たとえばマルチプレイヤーによる格闘ゲーム中に、プレイヤーが不在であることを示し、他の適切なアクションを実行することが必要な場合があります。
VRコンポジターは、HasInputFocusがFalseの間、それぞれのフレームサイクル中に最大3ミリ秒の追加レンダリング時間を使用することがあります。この理由から、HasInputFocusisがFalseの間は、可能であれば、アプリを低パフォーマンスモードに切り替えることをおすすめします。HasInputFocusが再びTrueになるまで待ってから、このアクションを元に戻してください。このアプローチは不要ですし、Dash UIがアクティブになっている間はパフォーマンスに関するVRC要件は適用されません。
HasInputFocusは、HMDを頭から外したときなど、アプリが入力フォーカスを失うその他の状況でもfalseを返すことにご注意ください。
次のコードでHasInputFocusフラグを確認できます。
ovrSessionStatus sessionStatus = {};
ovr_GetSessionStatus(Session, &sessionStatus);
if (!sessionStatus.HasInputFocus) {/*Handle situation where your app has lost input focus*/}
このコードは、それぞれのフレームレンダリングサイクル中に一度実行する必要があります。
OpenXRのフォーカス処理
Dash UIがアクティブになると、実行中のアプリは入力フォーカスを失い、セッション状態がXR_SESSION_STATE_FOCUSEDからXR_SESSION_STATE_VISIBLEに変わります。この状態で、ランタイムはメニューを操作できるように、トラッキングされているコントローラーをシーン内にレンダリングします。XR_SESSION_STATE_FOCUSED状態も可視化された状態を示唆することに注意してください。
セッション状態がXR_SESSION_STATE_FOCUSEDからXR_SESSION_STATE_VISIBLEに変わった場合、アプリはすべてのアクティビティを一時停止し、オーディオ再生をミュートし、トラッキングされているコントローラーをシーン内で非表示にするので、両手が重複して表示されることはなく、近く(ユーザーから約1メートル以内)にあるフィールドオブジェクトは非表示になります。アプリによっては、入力フォーカスが失われたときに、追加のアクションが必要になる場合があります。例えば、マルチプレイヤーによる格闘ゲーム中に、プレイヤーが不在であることを示し、他の適切なアクションを実行することが必要な場合があります。
VRコンポジターは、Dashが可視化されている間、それぞれのフレームサイクル中に最大3ミリ秒の追加レンダリング時間を使用することがあります。この理由から、アプリがフォーカスを失っている間は、可能であれば、アプリを低パフォーマンスモードに切り替えることをおすすめします。XR_SESSION_STATE_VISIBLEに戻るまで待ってから、このアクションを元に戻してください。このアプローチは不要ですし、Dash UIがアクティブになっている間はパフォーマンスに関する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の深度バッファのサポート
ユーザーの近くに多数のジオメトリーをレンダリングする場合、DashパネルがそのDashパネルよりプレイヤーに近いジオメトリーの上にレンダリングされると、不快な両眼視差が生じることがあります。このような視差を回避するために、アイバッファを含む深度を送信することができます。これにより、このような不快感のないX線エフェクトをDashで描画できるようになります。こうした理由から、また今後の改善のためにも、アイバッファを含む深度データを送信することをおすすめします。ただし、これを行うことができない場合でも、DashをサポートしないよりはDashをサポートする(視差があっても受け入れる)ことをおすすめします。
深度データを送信するには、次のサンプルコードのように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拡張機能を有効にします。深度データを送信するには、XrCompositionLayerDepthInfoKHRのインスタンスを、xrEndFrameに送信する個々のXrCompositionLayerProjectionView構造の次のチェーンに追加します。深度バッファは、カラーバッファと同様に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ベースのアプリは、HasInputFocusを含め、ovrSessionStatusフォーカスステートに応答する準備ができているかどうかを示す必要があります。入力フォーカスの処理 (上記)に記載にとおり、アプリがフォーカスの消失に対応できる場合は、ovrInit_FocusAwareフラグをTrueに設定します。それ以外の場合は、ovrInit_FocusAwareをFalseに設定します。
OpenXRベースのアプリはネイティブで常に入力フォーカスを認識し、特別な処理を必要としません。
アプリが入力フォーカス対応であることを宣言する
アプリは、HasInputFocusを含め、ovrSessionStatusフォーカスステートに応答する準備ができているかどうかを示す必要があります。入力フォーカスの処理 (上記)に記載にとおり、アプリがフォーカスの消失に対応できる場合は、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);
}