Hololens2-OpenXR开发(二)-实现通讯
Writing a Holographic Remoting Remote app using the OpenXR API
本文是根據官方示例的學習筆記
https://docs.microsoft.com/en-us/windows/mixed-reality/develop/native/holographic-remoting-create-remote-openxr
解釋名詞:
runtime: 不同廠商根據OpenXR標準實現的設備,如Hololens,Oculus
1. 導入XR開發(fā)相關函數(EnableRemotingXR)
bool EnableRemotingXR() {wchar_t executablePath[MAX_PATH];if (GetModuleFileNameW(NULL, executablePath, ARRAYSIZE(executablePath)) == 0) {return false;}std::filesystem::path filename(executablePath);filename = filename.replace_filename("RemotingXR.json");if (std::filesystem::exists(filename)) {SetEnvironmentVariableW(L"XR_RUNTIME_JSON", filename.c_str());return true;}return false;
}
2. 初始化遠程通訊環(huán)境 (PrepareRemotingEnvironment)
void PrepareRemotingEnvironment() {if (!m_options.secureConnection) {return;}if (m_options.authenticationToken.empty()) {throw std::logic_error("Authentication token must be specified for secure connections.");}if (m_options.listen) {if (m_options.certificateStore.empty() || m_options.subjectName.empty()) {throw std::logic_error("Certificate store and subject name must be specified for secure listening.");}constexpr size_t maxCertStoreSize = 1 << 20;std::ifstream certStoreStream(m_options.certificateStore, std::ios::binary);certStoreStream.seekg(0, std::ios_base::end);const size_t certStoreSize = certStoreStream.tellg();if (!certStoreStream.good() || certStoreSize == 0 || certStoreSize > maxCertStoreSize) {throw std::logic_error("Error reading certificate store.");}certStoreStream.seekg(0, std::ios_base::beg);m_certificateStore.resize(certStoreSize);certStoreStream.read(reinterpret_cast<char*>(m_certificateStore.data()), certStoreSize);if (certStoreStream.fail()) {throw std::logic_error("Error reading certificate store.");}}
}
3. 創(chuàng)建XR實例(CreateInstance)
OpenXR里3個常用的擴展包:XR_MSFT_holographic_remoting
XR_MSFT_holographic_remoting_speech XR_MSFT_remoting_frame_mirroring
void CreateInstance() {CHECK(m_instance.Get() == XR_NULL_HANDLE);// Build out the extensions to enable. Some extensions are required and some are optional.const std::vector<const char*> enabledExtensions = SelectExtensions();//選擇所需擴展包// Create the instance with enabled extensions.XrInstanceCreateInfo createInfo{XR_TYPE_INSTANCE_CREATE_INFO};createInfo.enabledExtensionCount = (uint32_t)enabledExtensions.size();createInfo.enabledExtensionNames = enabledExtensions.data();createInfo.applicationInfo = {"SampleRemoteOpenXr", 1, "", 1, XR_CURRENT_API_VERSION};strcpy_s(createInfo.applicationInfo.applicationName, m_applicationName.c_str());CHECK_XRCMD(xrCreateInstance(&createInfo, m_instance.Put()));m_extensions.PopulateDispatchTable(m_instance.Get());
}
4. 交互動作初始化(CreateActions)
還沒進入實時通訊狀態(tài)前
void CreateActions() {CHECK(m_instance.Get() != XR_NULL_HANDLE);// Create an action set.{XrActionSetCreateInfo actionSetInfo{XR_TYPE_ACTION_SET_CREATE_INFO};strcpy_s(actionSetInfo.actionSetName, "place_hologram_action_set");strcpy_s(actionSetInfo.localizedActionSetName, "Placement");CHECK_XRCMD(xrCreateActionSet(m_instance.Get(), &actionSetInfo, m_actionSet.Put()));}// Create actions.{// Enable subaction path filtering for left or right hand.m_subactionPaths[LeftSide] = GetXrPath("/user/hand/left");m_subactionPaths[RightSide] = GetXrPath("/user/hand/right");// Create an input action to place a hologram.{XrActionCreateInfo actionInfo{XR_TYPE_ACTION_CREATE_INFO};actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;strcpy_s(actionInfo.actionName, "place_hologram");strcpy_s(actionInfo.localizedActionName, "Place Hologram");actionInfo.countSubactionPaths = (uint32_t)m_subactionPaths.size();actionInfo.subactionPaths = m_subactionPaths.data();CHECK_XRCMD(xrCreateAction(m_actionSet.Get(), &actionInfo, m_placeAction.Put()));}// Create an input action getting the left and right hand poses.{XrActionCreateInfo actionInfo{XR_TYPE_ACTION_CREATE_INFO};actionInfo.actionType = XR_ACTION_TYPE_POSE_INPUT;strcpy_s(actionInfo.actionName, "hand_pose");strcpy_s(actionInfo.localizedActionName, "Hand Pose");actionInfo.countSubactionPaths = (uint32_t)m_subactionPaths.size();actionInfo.subactionPaths = m_subactionPaths.data();CHECK_XRCMD(xrCreateAction(m_actionSet.Get(), &actionInfo, m_poseAction.Put()));}// Create an output action for vibrating the left and right controller.{XrActionCreateInfo actionInfo{XR_TYPE_ACTION_CREATE_INFO};actionInfo.actionType = XR_ACTION_TYPE_VIBRATION_OUTPUT;strcpy_s(actionInfo.actionName, "vibrate");strcpy_s(actionInfo.localizedActionName, "Vibrate");actionInfo.countSubactionPaths = (uint32_t)m_subactionPaths.size();actionInfo.subactionPaths = m_subactionPaths.data();CHECK_XRCMD(xrCreateAction(m_actionSet.Get(), &actionInfo, m_vibrateAction.Put()));}// Create an input action to exit the session.}// Set up suggested bindings for the simple_controller profile.{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/aim/pose")});bindings.push_back({m_poseAction.Get(), GetXrPath("/user/hand/left/input/aim/pose")});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));}
}
5. 驗證通訊是否正常(ProcessEvents)
監(jiān)視連接狀態(tài)
XR_TYPE_REMOTING_EVENT_DATA_CONNECTED_MSFT 已成功建立
XR_TYPE_REMOTING_EVENT_DATA_DISCONNECTED_MSFT 已建立的連接已關閉或無法建立連接
XR_TYPE_REMOTING_EVENT_DATA_LISTENING_MSFT 偵聽啟動
auto pollEvent = [&](XrEventDataBuffer& eventData) -> bool {eventData.type = XR_TYPE_EVENT_DATA_BUFFER;eventData.next = nullptr;return CHECK_XRCMD(xrPollEvent(m_instance.Get(), &eventData)) == XR_SUCCESS;
};
XrEventDataBuffer eventData{};
while (pollEvent(eventData)) {switch (eventData.type) {... case XR_TYPE_REMOTING_EVENT_DATA_LISTENING_MSFT: {DEBUG_PRINT("Holographic Remoting: Listening on port %d",reinterpret_cast<const XrRemotingEventDataListeningMSFT*>(&eventData)->listeningPort);break;}case XR_TYPE_REMOTING_EVENT_DATA_CONNECTED_MSFT: {DEBUG_PRINT("Holographic Remoting: Connected.");break;}case XR_TYPE_REMOTING_EVENT_DATA_DISCONNECTED_MSFT: {DEBUG_PRINT("Holographic Remoting: Disconnected - Reason: %d",reinterpret_cast<const XrRemotingEventDataDisconnectedMSFT*>(&eventData)->disconnectReason);break;}
}
6. XR初始化(ProcessWindowEventsWin32)
連接XR設備 (ConnectOrListen)
a. 使用Hololens的話,端口是8265,remoteHostName 就是眼鏡中顯示的ip地址。如果固定使用一臺電腦的話,可以初始化地址。
XrRemotingConnectInfoMSFT connectInfo{static_cast<XrStructureType>(XR_TYPE_REMOTING_CONNECT_INFO_MSFT)};
connectInfo.remoteHostName = "192.168.x.x";
connectInfo.remotePort = 8265;
connectInfo.secureConnection = false;
xrRemotingConnectMSFT(m_instance.Get(), m_systemId, &connectInfo);
b. 可以通過調用 xrRemotingListenMSFT 方法來偵聽遠程應用上的傳入連接
XrRemotingListenInfoMSFT listenInfo{static_cast<XrStructureType>(XR_TYPE_REMOTING_LISTEN_INFO_MSFT)};
listenInfo.listenInterface = "0.0.0.0";
listenInfo.handshakeListenPort = 8265;
listenInfo.transportListenPort = 8266;
listenInfo.secureConnection = false;
xrRemotingListenMSFT(m_instance.Get(), m_systemId, &listenInfo);
注意:代碼b必須在a前面,b是用來接收信號的,如果沒有收到信號就連接并創(chuàng)建任務,則運行到b時,就會報錯說是接收不到信息。
The timeout is fixed to 10 seconds.
If a connection can be established within this time, the XrSession creation will succeed and the session state will transition to XR_SESSION_STATE_READY.
In case no connection can be established the session creation also succeeds but immediately transitions to XR_SESSION_STATE_LOSS_PENDING.
初始化配置 (InitializeSession)
包括 CreateSpaces(包括獲取用戶空間坐標,詳見(四))和CreateSwapchains兩個重要函數
7. 與交互相關的函數初始化(PollActions)
在while函數中實時識別雙手,定位手的位置等
// 手握住
if (placeActionValue.isActive && placeActionValue.changedSinceLastSync && placeActionValue.currentState) {//如果握住if (side == 0)//side=0左手,=1右手DEBUG_PRINT("BeginAction[LeftSide]");elseDEBUG_PRINT("BeginAction[RightSide]");//添加一些自定義函數...
}
// 手松開了
else if (placeActionValue.isActive && placeActionValue.changedSinceLastSync && !placeActionValue.currentState) {if (side == 0)DEBUG_PRINT("EndAction[LeftSide]");elseDEBUG_PRINT("EndAction[RightSide]");//添加一些自定義函數...
}
8. 將本地內容傳輸到眼鏡中(RenderFrame)
利用XrRemotingFrameMirrorImageInfoMSFT鏡像本地信息。
XrFrameEndInfo frameEndInfo{XR_TYPE_FRAME_END_INFO};
...
XrRemotingFrameMirrorImageD3D11MSFT mirrorImageD3D11{static_cast<XrStructureType>(XR_TYPE_REMOTING_FRAME_MIRROR_IMAGE_D3D11_MSFT)};
mirrorImageD3D11.texture = m_window->GetNextSwapchainTexture();
XrRemotingFrameMirrorImageInfoMSFT mirrorImageEndInfo{static_cast<XrStructureType>(XR_TYPE_REMOTING_FRAME_MIRROR_IMAGE_INFO_MSFT)};
mirrorImageEndInfo.image = reinterpret_cast<const XrRemotingFrameMirrorImageBaseHeaderMSFT*>(&mirrorImageD3D11);
frameEndInfo.next = &mirrorImageEndInfo;
xrEndFrame(m_session.Get(), &frameEndInfo);
m_window->PresentSwapchain();
總結
以上是生活随笔為你收集整理的Hololens2-OpenXR开发(二)-实现通讯的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Hololens2-OpenXR开发(一
- 下一篇: 了解Hololens2的硬件信息