HoloLens(第 1 代)的全息远程处理
如果你是全息远程处理新手,建议阅读概述。
重要
本文档介绍如何创建适用于 HoloLens 1 的主机应用程序。 适用于 “HoloLens(第一代)”的主机应用程序必须使用 NuGet 包版本 “1.xx”。这意味着,为 HoloLens 1 编写的主机应用程序与 HoloLens 2 不兼容,反之亦然。
HoloLens 2
使用全息远程处理的 HoloLens 开发人员需要更新其应用,使其与 HoloLens 2 兼容。 这需要新版全息远程处理 NuGet 包。 在连接到 HoloLens 2 上的全息远程处理播放器时,请确保使用 2.0.0.0 或更高版本的全息远程处理 NuGet 包,否则连接会失败。 否则,连接将失败。
注意
可在此处找到特定于 HoloLens 2 的指南。
将全息远程处理添加到桌面或 UWP 应用
本页介绍如何向桌面或 UWP 应用添加全息远程处理。
使用全息远程处理,你的应用可以将其全息内容托管在台式电脑或 UWP 设备(例如 Xbox One)上的 HoloLens 作为目标。 你还可以访问更多系统资源,因此可以将远程沉浸式视图集成到现有的台式电脑软件中。 远程处理主机应用从 HoloLens 接收输入数据流,在虚拟沉浸式视图中渲染内容,然后将内容帧流式传输回 HoloLens。 使用标准 Wi-Fi 建立连接。 若要使用远程处理,请使用 NuGet 包将全息远程处理添加到桌面或 UWP 应用,然后编写代码来处理连接并渲染沉浸式视图。 帮助程序库包括在代码示例中,用于简化处理设备连接的任务。
典型的远程连接会有低至 50 毫秒的延迟。 播放器应用可以实时报告延迟。
注意
本文中的代码片段当前演示了如何使用 C++/CX,而不是 C++17 兼容的 C++/WinRT,后者在 C++ 全息项目模板中使用。 C++/WinRT 项目的这些概念是等效的,但你需要进行代码转换。
获取远程处理 NuGet 包
请按以下步骤获取用于全息远程处理的 NuGet 包,并从项目中添加引用:
- 转到 Visual Studio 中的项目。
- 右键单击项目节点,然后选择“管理 NuGet 包...”
- 在出现的面板中选择“浏览”,然后搜索“全息远程处理”。
- 选择“Microsoft.Holographic.Remoting”,然后选择“安装”。
- 如果出现了“预览”对话框,请选择“确定”。
- 出现许可协议对话框时,请选择“我接受”。
创建 HolographicStreamerHelpers
首先,需要将 HolographicStreamerHelpers 的实例添加到负责远程处理的类。
#include <HolographicStreamerHelpers.h>
private:
Microsoft::Holographic::HolographicStreamerHelpers^ m_streamerHelpers;
还需要跟踪连接状态。 如果要渲染此预览,则需要有一个可将它复制到其中的纹理。 还需要一些功能(如连接状态锁)、存储 HoloLens IP 地址的某种方法,等等。
private:
Microsoft::Holographic::HolographicStreamerHelpers^ m_streamerHelpers;
Microsoft::WRL::Wrappers::SRWLock m_connectionStateLock;
RemotingHostSample::AppView^ m_appView;
Platform::String^ m_ipAddress;
Microsoft::Holographic::HolographicStreamerHelpers^ m_streamerHelpers;
Microsoft::WRL::Wrappers::CriticalSection m_deviceLock;
Microsoft::WRL::ComPtr<IDXGISwapChain1> m_swapChain;
Microsoft::WRL::ComPtr<ID3D11Texture2D> m_spTexture;
初始化 HolographicStreamerHelpers 并连接到 HoloLens
若要连接到 HoloLens 设备,请创建 HolographicStreamerHelpers 的实例并连接到目标 IP 地址。 需要将视频帧大小设置为与 HoloLens 显示器宽度和高度匹配,因为全息远程处理库要求编码器和解码器的分辨率完全匹配。
m_streamerHelpers = ref new HolographicStreamerHelpers();
m_streamerHelpers->CreateStreamer(m_d3dDevice);
// We currently need to stream at 720p because that's the resolution of our remote display.
// There is a check in the holographic streamer that makes sure the remote and local
// resolutions match. The default streamer resolution is 1080p.
m_streamerHelpers->SetVideoFrameSize(1280, 720);
try
{
m_streamerHelpers->Connect(m_ipAddress->Data(), 8001);
}
catch (Platform::Exception^ ex)
{
DebugLog(L"Connect failed with hr = 0x%08X", ex->HResult);
}
设备连接是异步的。 应用需要提供针对连接事件、断开连接事件和帧发送事件的事件处理程序。
OnConnected 事件可以更新 UI,启动渲染,等等。 在我们的桌面代码示例中,我们使用“已连接”消息来更新窗口标题。
m_streamerHelpers->OnConnected += ref new ConnectedEvent(
[this]()
{
UpdateWindowTitle();
});
OnDisconnected 事件可以负责重新连接、UI 更新等。 在此示例中,如果发生暂时性故障,我们会重新连接。
Platform::WeakReference streamerHelpersWeakRef = Platform::WeakReference(m_streamerHelpers);
m_streamerHelpers->OnDisconnected += ref new DisconnectedEvent(
[this, streamerHelpersWeakRef](_In_ HolographicStreamerConnectionFailureReason failureReason)
{
DebugLog(L"Disconnected with reason %d", failureReason);
UpdateWindowTitle();
// Reconnect if this is a transient failure.
if (failureReason == HolographicStreamerConnectionFailureReason::Unreachable ||
failureReason == HolographicStreamerConnectionFailureReason::ConnectionLost)
{
DebugLog(L"Reconnecting...");
try
{
auto helpersResolved = streamerHelpersWeakRef.Resolve<HolographicStreamerHelpers>();
if (helpersResolved)
{
helpersResolved->Connect(m_ipAddress->Data(), 8001);
}
else
{
DebugLog(L"Failed to reconnect because a disconnect has already occurred.\n");
}
}
catch (Platform::Exception^ ex)
{
DebugLog(L"Connect failed with hr = 0x%08X", ex->HResult);
}
}
else
{
DebugLog(L"Disconnected with unrecoverable error, not attempting to reconnect.");
}
});
当远程处理组件准备好发送某个帧时,应用将有机会在 SendFrameEvent 中创建该帧的副本。 在这里,我们将帧复制到一个交换链,这样就可以在预览窗口中显示它。
m_streamerHelpers->OnSendFrame += ref new SendFrameEvent(
[this](_In_ const ComPtr<ID3D11Texture2D>& spTexture, _In_ FrameMetadata metadata)
{
if (m_showPreview)
{
ComPtr<ID3D11Device1> spDevice = m_appView->GetDeviceResources()->GetD3DDevice();
ComPtr<ID3D11DeviceContext> spContext = m_appView->GetDeviceResources()->GetD3DDeviceContext();
ComPtr<ID3D11Texture2D> spBackBuffer;
ThrowIfFailed(m_swapChain->GetBuffer(0, IID_PPV_ARGS(&spBackBuffer)));
spContext->CopySubresourceRegion(
spBackBuffer.Get(), // dest
0, // dest subresource
0, 0, 0, // dest x, y, z
spTexture.Get(), // source
0, // source subresource
nullptr); // source box, null means the entire resource
DXGI_PRESENT_PARAMETERS parameters = { 0 };
ThrowIfFailed(m_swapChain->Present1(1, 0, ¶meters));
}
});
渲染全息内容
若要使用远程处理来渲染内容,请在桌面或 UWP 应用中设置一个虚拟 IFrameworkView,并处理远程处理中的全息帧。 此视图通过相同的方式来使用所有 Windows 全息 API,但其设置方式略有不同。
全息空间和语音组件来自 HolographicRemotingHelpers 类,而不是你自行创建的:
m_appView->Initialize(m_streamerHelpers->HolographicSpace, m_streamerHelpers->RemoteSpeech);
你不在 Run 方法中使用更新循环,而是通过桌面或 UWP 应用的主循环来提供时钟周期更新。 这样一来,桌面或 UWP 应用就可以保持对消息处理的控制。
void DesktopWindow::Tick()
{
auto lock = m_deviceLock.Lock();
m_appView->Tick();
// display preview, etc.
}
全息应用视图的 Tick () 方法可完成对更新、绘图、呈现循环的一次迭代。
void AppView::Tick()
{
if (m_main)
{
// When running on Windows Holographic, we can use the holographic rendering system.
HolographicFrame^ holographicFrame = m_main->Update();
if (holographicFrame && m_main->Render(holographicFrame))
{
// The holographic frame has an API that presents the swap chain for each
// holographic camera.
m_deviceResources->Present(holographicFrame);
}
}
}
全息应用视图的更新、渲染和呈现循环与在 HoloLens 上运行时的效果完全相同,唯一区别是你有权访问台式电脑上数量多得多的系统资源。 你可以渲染更多的三角形,可以有更多的绘图轮次,可以实现更多的物理效果,并且可以使用 x64 进程加载那些需要 2 GB 以上 RAM 的内容。
断开并结束远程会话
若要断开连接(例如,用户单击某个 UI 按钮来断开连接),请在 HolographicStreamerHelpers 上调用 Disconnect(),然后释放该对象。
void DesktopWindow::DisconnectFromRemoteDevice()
{
// Disconnecting from the remote device can change the connection state.
auto exclusiveLock = m_connectionStateLock.LockExclusive();
if (m_streamerHelpers != nullptr)
{
m_streamerHelpers->Disconnect();
// Reset state
m_streamerHelpers = nullptr;
}
}
获取远程处理播放器
Windows 全息远程处理播放器在 Windows 应用商店中提供,作为一个供远程处理主机应用进行连接的终结点。 若要获取 Windows 全息远程处理播放器,请从 HoloLens 访问 Windows 应用商店,搜索“远程处理”,然后下载相应的应用。 远程处理播放器包含一项在屏幕上显示统计信息的功能,该功能在调试远程处理主机应用时可能很有用。
注释和资源
全息应用视图需要一种方法来为应用提供 Direct3D 设备,必须使用此设备来初始化全息空间。 应用应使用此 Direct3D 设备来复制和显示预览帧。
internal:
const std::shared_ptr<DX::DeviceResources>& GetDeviceResources()
{
return m_deviceResources;
}
“代码示例:”提供完整的全息远程处理代码示例,其中包含一个全息应用程序视图,该视图与用于桌面 Win32、UWP DirectX 和具有 XAML 的 UWP 的远程处理和远程处理主机项目兼容。
“调试说明:”全息远程处理库可能会引发第一次出现的异常。 这些异常可能会在调试会话中显示,具体取决于目前生效的 Visual Studio 异常设置。 这些异常由全息远程处理库在内部捕获,可以忽略。