前回、Windows Mixed Reality OpenXR Runtimeについて書きました。
このときはソースコードの話がなかったので、今回はOpenXRのサンプルコードを元に動かした話を書きました。
以下の環境で動作を確認しています。
Open XR API (version 1.0)
Windows 10 Pro (version 1903)
Visual Studio 2017 (version 15.9.9)
HoloLens2 Emulator(10.0.18362.1021)
Windows Mixed Reality Acer AH100
- 1. 2019/8/4時点では、サンプルコードを動かせるのはWindows Mixed Realityヘッドセット(またはエミュレータ)のみ
- 2. OpenXRサンプルコードのビルドと動作確認(Windows Mixed Reality)
- 3. 参考:OpenXRサンプルコードのビルドと動作確認(HoloLens2 エミュレータ)
- 4. サンプルコードの一部を紹介
- 5. 参考:OpenXR APIリファレンスガイド
- 6. おわりに
1. 2019/8/4時点では、サンプルコードを動かせるのはWindows Mixed Realityヘッドセット(またはエミュレータ)のみ
大雑把に言うと、OpenXRのAPIは2種類あります。
(1) アプリ開発するとき、デバイスの差異を気にしなくてよくなるためのOpenXR API(Application Interface)
(2) XRデバイス製造ベンダーが、開発環境の差異を気にしなくてよくなるためのOpenXR API (Device Plugin Interface)
XRデバイス:HMD、スマートフォン、タブレットです。
(2)を実現するために、開発環境のPCやXRデバイスには、個別のRuntimeインストールが必要です。2019/8/4時点では、Runtimeが提供されているのはWindows Mixed RealityとHoloLens2エミュレータのため、動作確認対象もその2つのみです。
2. OpenXRサンプルコードのビルドと動作確認(Windows Mixed Reality)
前回の記事で紹介したRuntimeに入っていたサンプルコードがあると思っていたのですが、そちらは見つけられませんでした。今のところ、見つけられたのは、Microsoftから提供されている下記のリポジトリのみです。
このリポジトリには、コントローラの入力を検出して、Cubeを増やすというサンプルが入っています。ビルドすると、Windows Mixed Realityヘッドセット(またはエミュレータ)で動作を確認できます。
まず、Githubからクローンし、OpenXR-SDK-VisualStudio-master/samples/BasicXrApp/BasicXrApp_uwp.vcxprojをVisual Studio 2017で開きます。
開くと、このような警告が出ることがあります。この場合、指示に沿ってC++ Universal Windows Platform toolsをインストールします。
警告が消えたら、CPUタイプをx86、デプロイ先をLocal Machineに変更し、Build/Deploy Solutionをクリックします。
ビルドが成功するとWindowx Mixed Reality のポータルが起動して、Windows Mixed Reality ヘッドセットにCubeが表示されます。
このサンプルでは、コントローラとCubeが連動して動きます。ボタンを押すたびに、もう1つのCubeが固定表示されます。次にボタンを押すと、前回のCubeは消えて新たなcubeが固定表示されます。
少し変更してみます。Visual Studio 2017で以下のc++ファイルを開きます。
OpenXR-SDK-VisualStudio-master/samples/BasicXrApp/CubeGraphics.cpp
//L34付近 constexpr XrVector3f Red{1, 0, 0}; constexpr XrVector3f DarkRed{0.25f, 0, 0}; constexpr XrVector3f Green{0, 1, 0}; constexpr XrVector3f DarkGreen{0, 0.25f, 0}; constexpr XrVector3f Blue{0, 0, 1}; constexpr XrVector3f DarkBlue{0, 0, 0.25f}; constexpr XrVector3f White{1, 1, 1}; //追加
//L.58付近 constexpr Vertex c_cubeVertices[] = { // CUBE_SIDE(LTB, LBF, LBB, LTB, LTF, LBF, DarkRed) // -X //コメントアウト // CUBE_SIDE(RTB, RBB, RBF, RTB, RBF, RTF, Red) // +X //コメントアウト CUBE_SIDE(LTB, LBF, LBB, LTB, LTF, LBF, White) // -X :追加 CUBE_SIDE(RTB, RBB, RBF, RTB, RBF, RTF, White) // +X:追加 CUBE_SIDE(LBB, LBF, RBF, LBB, RBF, RBB, DarkGreen) // -Y CUBE_SIDE(LTB, RTB, RTF, LTB, RTF, LTF, Green) // +Y CUBE_SIDE(LBB, RBB, RTB, LBB, RTB, LTB, DarkBlue) // -Z CUBE_SIDE(LBF, LTF, RTF, LBF, RTF, RBF, Blue) // +Z };
これで表示されるCubeの6面のうち2つの面が白色になります。
ここではコントローラを2つ使ってみました。左右どちらかのコントローラでボタンを押すと、前回のCubeが消えて、新しいCubeが表示されます。
3. 参考:OpenXRサンプルコードのビルドと動作確認(HoloLens2 エミュレータ)
こちらは動作しませんでしたが、参考までに構築方法を記載します。
まず、エミュレータを使うにはWindows 10 Pro(Homeでは動かない)であること、仮想化機能に対応したCPUであることが必要です。
3年近く前の記事ですが、確認方法は下記も参考ください。今回、当時と同じ構成のPCでHoloLens2エミュレータを起動できました。
インストール方法、およびエミュレータ概要は、下記にわかりやすくまとまってますのでご参考ください。
akihiro-document.azurewebsites.net
エミュレータの準備ができたら、Windows Mixed Realityのときに使ったVisual Studioプロジェクトを再起動して開きます。CPUをx86にすると、デプロイ先にHoloLens2 Emulatorが表示されます。
HoloLens2 Emulatorを選択してデプロイを実行すると、ビルド、デプロイが終了し、HoloLens2 Emulatorが起動します。
(起動には1分半前後かかりました)
しかし、このような表示が出て実行できませんでした。
Unhandled exception at 0x76F033F2 in BasicXrApp_uwp.exe: Microsoft C++ exception: std::logic_error at memory location 0x006FF220.
ちなみに、ダメ元でCPUをx64にしてから実行しましたが、メモリアドレスが変わっただけで表示内容は同じでした。
Unhandled exception at 0x00007FFEE664A839 in BasicXrApp_uwp.exe: Microsoft C++ exception: std::logic_error at memory location 0x000000A92CF7EAA8.
エミュレータからメニューを開くとアプリアイコンは表示されるので、デプロイまでは成功しています。もし原因がわかったら追記します。
4. サンプルコードの一部を紹介
CubeGraphics.cpp とOpenXrProgram.cppが主なファイルで、Windows Mixed RealityのHMDとコントローラに関する処理が書かれているのはOpenXrProgram.cppです。代表的な箇所を抜粋しました。
4.1 コントローラの宣言
OpenXR-SDK-VisualStudio-master/samples/BasicXrApp/OpenXrProgram.cpp
//L153付近 // Setup suggest bindings for simple controller. { std::vector<XrActionSuggestedBinding> bindings; bindings.push_back({m_placeAction.Get(), GetXrPath("/user/hand/right/input/select/click")}); bindings.push_back({m_placeAction.Get(), GetXrPath("/user/hand/left/input/select/click")}); bindings.push_back({m_poseAction.Get(), GetXrPath("/user/hand/right/input/grip/pose")}); bindings.push_back({m_poseAction.Get(), GetXrPath("/user/hand/left/input/grip/pose")}); bindings.push_back({m_vibrateAction.Get(), GetXrPath("/user/hand/right/output/haptic")}); bindings.push_back({m_vibrateAction.Get(), GetXrPath("/user/hand/left/output/haptic")}); XrInteractionProfileSuggestedBinding suggestedBindings{XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING}; suggestedBindings.interactionProfile = GetXrPath("/interaction_profiles/khr/simple_controller"); suggestedBindings.suggestedBindings = bindings.data(); suggestedBindings.countSuggestedBindings = (uint32_t)bindings.size(); CHECK_XRCMD(xrSuggestInteractionProfileBindings(m_instance.Get(), &suggestedBindings)); }
4.2 Cubeの宣言
OpenXR-SDK-VisualStudio-master/samples/BasicXrApp/OpenXrProgram.cpp
//L. 231付近 void CreateSpaces() { CHECK(m_session.Get() != XR_NULL_HANDLE); // Create a space to place a cube in the world. { //途中省略 //L252 // ここでcubeを宣言 spaceCreateInfo.poseInReferenceSpace = Pose::Translation({0, 0, -1}); CHECK_XRCMD(xrCreateReferenceSpace(m_session.Get(), &spaceCreateInfo, m_placedCubeSpace.Put())); m_placedCube.Space = m_placedCubeSpace.Get(); m_placedCube.Scale = {0.1f, 0.1f, 0.1f}; //途中省略 //L. 622 XrSpaceHandle m_placedCubeSpace; Cube m_placedCube; // Placed in local or anchor space.
4.3 コントローラとcubeの対応づけ
OpenXR-SDK-VisualStudio-master/samples/BasicXrApp/OpenXrProgram.cpp
//L511付近 bool RenderLayer(XrTime predictedDisplayTime, XrCompositionLayerProjection& layer, std::vector<XrCompositionLayerProjectionView>& projectionLayerViews) { //途中省略 //L534付近 // Update cubes location with latest space relation for (auto cube : {m_placedCube, m_cubesInHand[LeftSide], m_cubesInHand[RightSide]}) { if (cube.Space != XR_NULL_HANDLE) { XrSpaceLocation spaceLocation{XR_TYPE_SPACE_LOCATION}; CHECK_XRCMD(xrLocateSpace(cube.Space, m_sceneSpace.Get(), predictedDisplayTime, &spaceLocation)); if (xr::math::Pose::IsPoseValid(spaceLocation)) { cube.Pose = spaceLocation.pose; visibleCubes.push_back(cube); } } }
5. 参考:OpenXR APIリファレンスガイド
OpenXRのAPI(アプリ開発側)の名称や役割、関係性を知りたかったので調べたら下記を見つけました。
引用元:https://www.khronos.org/files/openxr-10-reference-guide.pdf
このpdfファイルには、HMDやコントローラの動作定義、イベント処理方法、グラフィック処理などのAPI名称、引数や簡単な使い方が書いてあります。後半にはアプリケーションのライフライクルも載っており、サンプルコードと合わせれば基本的な動きは理解できます。
たとえば、4.1-4.3で紹介したソースコードのXrActionSuggestedBinding、xrCreateReferenceSpace、XrSpaceLocationはpdfの中で解説されています。
6. おわりに
アプリ開発側のAPIの使い方がわかったことで、OpenXRの理解が少し進みました。
ざっと探しましたが、OpenXRには、Particleなどのエフェクトや、GUI開発環境への言及がありませんでした。そのため、OpenXRの普及が進んでも、アプリケーション開発はUnityやUnreal Engineなどが引き続き使われると思います。
そうすると、アプリ開発者としては、デバイスのRuntime対応、およびUnityやUnreal Engineなどの開発環境の対応が進んでから試すのが良さそうですね。