HoloLens (第 1 世代) 用ホログラフィック リモート
Holographic Remoting を初めて使用する場合は、概要を参照してください。
重要
このドキュメントでは、HoloLens 1 のホスト アプリケーションの作成について説明します。 HoloLens (第 1 世代) のホスト アプリケーションでは、NuGet パッケージ バージョン 1.x.x を使用する必要があります。このことは、HoloLens 1 用に作成されたホスト アプリケーションは、HoloLens 2 と互換性がなく、その逆も同様であることを意味しています。
HoloLens 2
Holographic Remoting を使用している HoloLens 開発者は、HoloLens 2 との互換性を持たせるために、アプリを更新する必要があります。 これには、新しいバージョンの Holographic Remoting NuGet パッケージが必要です。 HoloLens 2 で Holographic Remoting Player に接続する場合は、バージョン 2.0.0.0 以上の Holographic Remoting NuGet パッケージを使用してください。 そうでない場合、接続に失敗します。
Note
HoloLens 2 に特有のガイダンスは、ここにあります。
Holographic Remoting をデスクトップまたは UWP アプリに追加する
このページでは、Holographic Remoting をデスクトップまたは UWP アプリに追加する方法を説明します。
Holographic Remoting を使用すると、アプリは、デスクトップ PC または Xbox One などの UWP デバイスでホストされているホログラフィック コンテンツを使用する HoloLens を対象とすることができます。 また、より多くのシステム リソースにアクセスできるため、リモートのイマーシブ ビューを既存のデスクトップ PC ソフトウェアに統合することができるようになります。 リモート処理ホスト アプリは HoloLens から入力データ ストリームを受信し、仮想のイマーシブ ビューでコンテンツをレンダリングし、コンテンツ フレームを HoloLens にストリーミングで戻します。 接続は標準の Wi-Fi を使用して行われます。 リモート処理を使用するには、NuGet パッケージを使用して Holographic Remoting をデスクトップまたは UWP アプリに追加し、接続を処理してイマーシブ ビューをレンダリングするコードを記述します。 コード サンプルには、デバイス接続の処理タスクを簡略化するヘルパー ライブラリが含まれています。
通常のリモート処理接続の待機時間は、最短で 50 ms です。 プレーヤー アプリは、リアルタイムで待機時間を報告します。
Note
この記事のコード スニペットは現在のところ、C++ ホログラフィック プロジェクト テンプレートで使用されている C++17 準拠の C++/WinRT ではなく、C++/CX を使用しています。 考え方は C++/WinRT プロジェクトの場合と同じですが、コードを変換する必要があります。
リモート処理の NuGet パッケージを取得する
Holographic Remoting のための NuGet パッケージを取得し、プロジェクトからの参照を追加するには、次の手順に従います。
- Visual Studio でプロジェクトに移動します。
- プロジェクト ノードを右クリックし、[Manage NuGet Packages...](NuGet パッケージの管理...) を選択します。
- 表示されるパネルで、[Browse](参照) を選択してから "Holographic Remoting" を検索します。
- Microsoft.Holographic.Remoting を選択してから、[Install](インストール) を選択します。
- [Preview](プレビュー) ダイアログが表示されたら、[OK] をクリックします。
- 使用許諾契約書ダイアログが表示されたら、[I Accept](同意する) を選択します。
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 アドレスに接続します。 Holographic Remoting ライブラリは、エンコーダーとデコーダーの解像度が正確に一致することを想定しているため、ビデオ フレーム サイズが 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 の更新やレンダリングの開始などを行うことができます。 デスクトップのコード サンプルでは、"connected" (接続済み) メッセージでウィンドウ タイトルを更新します。
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 Holographic 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() メソッドは、更新、描画、表示ループを 1 回実行します。
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 で実行されているときとまったく同じです。ただし、デスクトップ PC の大量のシステム リソースを利用できるという点だけは異なります。 ずっと多くの三角形のレンダリング、より多くの描画パスの使用、より多くの物理計算、2 GB を超える RAM が必要なコンテンツを読み込むための x64 プロセスの使用などが可能になります。
リモート セッションを切断して終了する
ユーザーが切断のための 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;
}
}
Remoting Player を取得する
Windows Holographic Remoting Player は、リモート処理ホスト アプリが接続するエンドポイントとして Windows アプリ ストアで提供されています。 Windows Holographic Remoting Player を取得するには、HoloLens から Windows アプリ ストアにアクセスして Remoting を検索し、アプリをダウンロードします。 Remoting Player には統計情報を画面に表示する機能が含まれており、リモート処理ホスト アプリのデバッグを行うときに役立ちます。
メモと参照情報
ホログラフィック アプリ ビューには、アプリに Direct3D デバイスを提供する方法が必要であり、この方法はホログラフィック空間を初期化するために使用する必要があります。 アプリはこの Direct3D デバイスを使用して、プレビュー フレームをコピーして表示する必要があります。
internal:
const std::shared_ptr<DX::DeviceResources>& GetDeviceResources()
{
return m_deviceResources;
}
コード サンプル:Holographic Remoting コード サンプルの全体を利用できます。これには、リモート処理と互換性があるホログラフィック アプリケーション ビューと、デスクトップ Win32、UWP DirectX、XAML を使用する UWP 向けのリモート処理ホスト プロジェクトが含まれています。
デバッグに関する注意: Holographic Remoting ライブラリは、初回例外をスローすることがあります。 Visual Studio の、その時点でアクティブな例外の設定によっては、これらの例外がデバッグ セッションに表示されることがあります。 これらの例外は、Holographic Remoting ライブラリによって内部で捕捉され、無視することができます。