例としてRengaを使用したデスクトップDirect3DアプリケーションへのOculus Riftの統合

みなさんこんにちは! この記事では、仮想現実ヘルメットをWindowsのデスクトップアプリケーションに接続するプロセスを理解したいと思います。 Oculus Riftについてです。



建築の視覚化は、さまざまな種類の実験にとって非常に豊かなトピックです。 私たちはトレンドに追いつくことにしました。 BIMシステムの次のバージョンのいずれか(ASCONと1Cの合弁会社であるRenga Softwareに勤務していることを思い出させてください): Renga Architecture-建築および構造設計およびRenga Structure-建物および構造物の構造部分の設計仮想現実のヘルメットで設計された建物を歩き回ることが可能になります。 顧客にプロジェクトをデモンストレーションし、人間工学的な観点からさまざまな設計上の決定を評価するのに非常に便利です。



画像





ヘルメット開発者向けサイトは、ダウンロードSDKで入手できます 。 執筆時点では、最新の利用可能なバージョンは1.16です。 ValveのOpenVRもあります。 私はこのことを自分で試したことはありませんが、ネイティブのOculus SDKよりもうまく機能しないという疑いがあります。



ヘルメットをアプリケーションに接続する主な段階を分析します。 まず、デバイスを初期化する必要があります。



#define OVR_D3D_VERSION 11 // in case direct3d 11 #include "OVR_CAPI_D3D.h" bool InitOculus() { ovrSession session = 0; ovrGraphicsLuid luid = 0; // Initializes LibOVR, and the Rift ovrInitParams initParams = { ovrInit_RequestVersion, OVR_MINOR_VERSION, NULL, 0, 0 }; if (!OVR_SUCCESS(ovr_Initialize(&initParams))) return false; if (!OVR_SUCCESS(ovr_Create(&session, &luid))) return false; // FloorLevel will give tracking poses where the floor height is 0 if(!OVR_SUCCESS(ovr_SetTrackingOriginType(session, ovrTrackingOrigin_EyeLevel))) return false; return true; }
      
      





初期化が完了しました。 これでセッションができました-これはovrHmdStructの内部構造へのポインターです。 oculusランタイムへのすべてのリクエストに使用します。 luidは、ヘルメットが接続されているグラフィックアダプターの識別子です。 複数のグラフィックカードまたはラップトップを使用した構成に必要です。 アプリケーションは、レンダリングに同じアダプターを使用する必要があります。



Oculus Riftヘルメットと通常モードでフレームを作成するプロセスは、それほど変わりません。

各目について、SwapChainとRenderTargetとともにテクスチャを作成する必要があります。

テクスチャを作成するために、Oculus SDKは一連の機能を提供します。



各目のSwapChainとRenderTargetを作成して保存するラッパーの例:



 struct EyeTexture { ovrSession Session; ovrTextureSwapChain TextureChain; std::vector<ID3D11RenderTargetView*> TexRtv; EyeTexture() : Session(nullptr), TextureChain(nullptr) { } bool Create(ovrSession session, int sizeW, int sizeH) { Session = session; ovrTextureSwapChainDesc desc = {}; desc.Type = ovrTexture_2D; desc.ArraySize = 1; desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; desc.Width = sizeW; desc.Height = sizeH; desc.MipLevels = 1; desc.SampleCount = 1; desc.MiscFlags = ovrTextureMisc_DX_Typeless; desc.BindFlags = ovrTextureBind_DX_RenderTarget; desc.StaticImage = ovrFalse; ovrResult result = ovr_CreateTextureSwapChainDX(Session, pDevice, &desc, &TextureChain); if (!OVR_SUCCESS(result)) return false; int textureCount = 0; ovr_GetTextureSwapChainLength(Session, TextureChain, &textureCount); for (int i = 0; i < textureCount; ++i) { ID3D11Texture2D* tex = nullptr; ovr_GetTextureSwapChainBufferDX(Session, TextureChain, i, IID_PPV_ARGS(&tex)); D3D11_RENDER_TARGET_VIEW_DESC rtvd = {}; rtvd.Format = DXGI_FORMAT_R8G8B8A8_UNORM; rtvd.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; ID3D11RenderTargetView* rtv; DIRECTX.Device->CreateRenderTargetView(tex, &rtvd, &rtv); TexRtv.push_back(rtv); tex->Release(); } return true; } ~EyeTexture() { for (int i = 0; i < (int)TexRtv.size(); ++i) { Release(TexRtv[i]); } if (TextureChain) { ovr_DestroyTextureSwapChain(Session, TextureChain); } } ID3D11RenderTargetView* GetRTV() { int index = 0; ovr_GetTextureSwapChainCurrentIndex(Session, TextureChain, &index); return TexRtv[index]; } void Commit() { ovr_CommitTextureSwapChain(Session, TextureChain); } };
      
      





このラッパーを使用して、各目のテクスチャを作成し、3Dシーンを描画します。 テクスチャサイズは、Oculus Runtimeから取得する必要があります。 これを行うには、デバイスの説明を取得し、ovr_GetFovTextureSize関数を使用して、各目の必要なテクスチャサイズを取得します。



 ovrHmdDesc hmdDesc = ovr_GetHmdDesc(session); ovrSizei idealSize = ovr_GetFovTextureSize(session, (ovrEyeType)eye, hmdDesc.DefaultEyeFov[eye], 1.0f);
      
      





いわゆるミラーテクスチャを作成することも便利です。 このテクスチャは、アプリケーションウィンドウに表示できます。 Oculus Runtimeは、後処理後に2つの目で結合された画像をこのテクスチャにコピーします。



画像



後処理を行わない場合、人はヘルメット内で正の歪みのある光学システムを使用して取得した画像を見ることになります(左の画像)。 これを補うために、oculusは負の歪み効果を課します(右の画像)。



ミラーテクスチャを作成するためのコード:



  // Create a mirror to see on the monitor. ovrMirrorTexture mirrorTexture = nullptr; mirrorDesc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; mirrorDesc.Width = width; mirrorDesc.Height =height; ovr_CreateMirrorTextureDX(session, pDXDevice, &mirrorDesc, &mirrorTexture);
      
      





テクスチャを作成する際の重要なポイント。 ovr_CreateTextureSwapChainDX関数を使用してSwapChainを作成する場合、目的のテクスチャ形式を渡します。 この形式は、Oculusランタイムによる後処理に後で使用されます。



すべてが正しく機能するために、アプリケーションはsRGB色空間でスワップチェーンを作成する必要があります。 たとえば、 OVR_FORMAT_R8G8B8A8_UNORM_SRGB 。 アプリケーションでガンマ補正を行わない場合は、sRGB形式でスワップチェーンを作成する必要があります。 ovrTextureMisc_DX_TypelessフラグをovrTextureSwapChainDescに設定します。 DXGI_FORMAT_R8G8B8A8_UNORMの形式でレンダーターゲットを作成します。 これを行わないと、画面上の画像が明るすぎます。



ヘルメットを接続し、各目のテクスチャを作成した後、対応するテクスチャにシーンを描画する必要があります。 これは、direct3dが提供する通常の方法で行われます。 ここでは何も面白くない。 ヘルメットから彼の位置を取得するだけで、これは次のように行われます。



 ovrHmdDesc hmdDesc = ovr_GetHmdDesc(session); ovrEyeRenderDesc eyeRenderDesc[2]; eyeRenderDesc[0] = ovr_GetRenderDesc(session, ovrEye_Left, hmdDesc.DefaultEyeFov[0]); eyeRenderDesc[1] = ovr_GetRenderDesc(session, ovrEye_Right, hmdDesc.DefaultEyeFov[1]); // Get both eye poses simultaneously, with IPD offset already included. ovrPosef EyeRenderPose[2]; ovrVector3f HmdToEyeOffset[2] = { eyeRenderDesc[0].HmdToEyeOffset, eyeRenderDesc[1].HmdToEyeOffset }; double sensorSampleTime; // sensorSampleTime is fed into the layer later ovr_GetEyePoses(session, frameIndex, ovrTrue, HmdToEyeOffset, EyeRenderPose, &sensorSampleTime);
      
      





さて、フレームを作成するときは、ヘルメットの位置を考慮して、各目に対して正しいビューマトリックスを設定することを忘れないでください。



それぞれの目のシーンを描いた後、Oculusランタイムで後処理のために結果のテクスチャを転送する必要があります。



これは次のように行われます。



 OculusTexture * pEyeTexture[2] = { nullptr, nullptr }; // ... // Draw into eye textures // ... // Initialize our single full screen Fov layer. ovrLayerEyeFov ld = {}; ld.Header.Type = ovrLayerType_EyeFov; ld.Header.Flags = 0; for (int eye = 0; eye < 2; ++eye) { ld.ColorTexture[eye] = pEyeTexture[eye]->TextureChain; ld.Viewport[eye] = eyeRenderViewport[eye]; ld.Fov[eye] = hmdDesc.DefaultEyeFov[eye]; ld.RenderPose[eye] = EyeRenderPose[eye]; ld.SensorSampleTime = sensorSampleTime; } ovrLayerHeader* layers = &ld.Header; ovr_SubmitFrame(session, frameIndex, nullptr, &layers, 1);
      
      





その後、完成した画像がヘルメットに表示されます。 ヘルメットの人が見るものをアプリケーションで表示するために、アプリケーションウィンドウのバックバッファーで前に作成したミラーテクスチャの内容をコピーできます。



 ID3D11Texture2D* tex = nullptr; ovr_GetMirrorTextureBufferDX(session, mirrorTexture, IID_PPV_ARGS(&tex)); pDXContext->CopyResource(backBufferTexture, tex);
      
      





以上です。 Oculus SDKには多くの良い例があります。



All Articles