首页 > Hololens2-OpenXR开发(二)-实现通讯

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开发相关函数(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. 初始化远程通讯环境 (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. 创建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)

还没进入实时通讯状态前

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)

监视连接状态

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是用来接收信号的,如果没有收到信号就连接并创建任务,则运行到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
                

更多相关:

  •   测试用prototxt   name: "CIFAR10_quick"layer {name: "data" type: "MemoryData" top: "data" top: "label" memory_data_param {batch_size: 1     #样本个数 channels: 3 height: 32 w...

  •    话说每到吃完的时间就发愁,真的不知道该吃什么,然后就想到做一个生成吃什么的小软件,既然这个软件如此的简单,就打算用wpf开发吧,也不用数据库了,直接保存在xml中就可以了  程序整体结构如下图  首先我写了一个xml的帮助类,主要是写了个常用的增加方法 主程序界面也很简单,一共就两个页面 对应的两处代码也粘上 pr...