Schreiben einer benutzerdefinierten Holographic Remoting Player-App

Wenn Sie noch nicht mit Holographic Remoting sind, können Sie unsere Übersicht lesen.

Wichtig

In diesem Dokument wird die Erstellung einer benutzerdefinierten Playeranwendung für HoloLens 2 beschrieben. Benutzerdefinierte Player, die für HoloLens 2 geschrieben wurden, sind nicht mit Remoteanwendungen kompatibel, die für HoloLens 1 geschrieben wurden. Dies bedeutet, dass beide Anwendungen NuGet Paketversion 2.x.x verwenden müssen.

Indem Sie eine benutzerdefinierte Holographic Remoting-Player-App erstellen, können Sie eine benutzerdefinierte Anwendung erstellen, die immersive Ansichten von einem Remotecomputer auf Ihrem HoloLens 2 anzeigen kann. Den gesamten Code auf dieser Seite und funktionierende Projekte finden Sie im GitHub-Repository mit Holographic Remoting-Beispielen.

Mit einem Holographic Remoting-Player kann Ihre App holografische Inhalte anzeigen, die auf einem Desktop-PC oder UWP-Gerät gerendert werden, z. B. die Xbox One mit Zugriff auf weitere Systemressourcen. Eine Holographic Remoting-Player-App streamt Eingabedaten an eine Holographic Remoting-Remoteanwendung und empfängt eine immersive Ansicht als Video- und Audiostream. Die Verbindung wird mithilfe von Standard-WLAN hergestellt. Verwenden Sie zum Erstellen einer Player-App ein NuGet Paket, um Holographic Remoting ihrer UWP-App hinzuzufügen. Schreiben Sie dann Code, um die Verbindung zu behandeln und eine immersive Ansicht anzuzeigen.

Voraussetzungen

Ein guter Ausgangspunkt ist eine funktionierende DirectX-basierte UWP-App, die bereits auf die Windows Mixed Reality-API ausgerichtet ist. Weitere Informationen finden Sie unter Übersicht über die DirectX-Entwicklung. Wenn Sie nicht über eine vorhandene App verfügen und von Grund auf neu beginnen möchten, ist die Holografische C++-Projektvorlage ein guter Ausgangspunkt.

Wichtig

Jede App, die Holographic Remoting verwendet, sollte so erstellt werden, dass sie ein Multithread-Apartment verwendet. Die Verwendung eines Singlethread-Apartments wird unterstützt, führt aber zu einer suboptimalen Leistung und möglicherweise zu einem Stubing während der Wiedergabe. Bei Verwendung von C++/WinRT winrt::init_apartment ist ein Multithread-Apartment die Standardeinstellung.

Abrufen des Holographic Remoting NuGet-Pakets

Die folgenden Schritte sind erforderlich, um das NuGet-Paket einem Projekt in Visual Studio hinzuzufügen.

  1. Öffnen Sie das Projekt in Visual Studio.
  2. Klicken Sie mit der rechten Maustaste auf den Projektknoten, und wählen Sie NuGet Pakete verwalten... aus.
  3. Wählen Sie im daraufhin angezeigten Bereich Durchsuchen aus, und suchen Sie dann nach "Holographic Remoting".
  4. Wählen Sie Microsoft.Holographic.Remoting aus, wählen Sie die neueste Version von 2.x.x aus, und wählen Sie Installieren aus.
  5. Wenn das Dialogfeld Vorschau angezeigt wird, wählen Sie OK aus.
  6. Wählen Sie Ich stimme zu aus, wenn das Dialogfeld "Lizenzvertrag" angezeigt wird.

Wichtig

Die build\native\include\HolographicAppRemoting\Microsoft.Holographic.AppRemoting.idl im NuGet Paket enthält eine ausführliche Dokumentation für die API, die von Holographic Remoting verfügbar gemacht wird.

Ändern des Package.appxmanifest der Anwendung

Damit die Anwendung die vom NuGet-Paket hinzugefügten Microsoft.Holographic.AppRemoting.dll erkennt, müssen die folgenden Schritte für das Projekt ausgeführt werden:

  1. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf die Datei Package.appxmanifest, und wählen Sie Öffnen mit... aus.
  2. Wählen Sie XML-Editor (Text) und dann OK aus.
  3. Fügen Sie der Datei die folgenden Zeilen hinzu, und speichern Sie sie.
  </Capabilities>

  <!--Add lines below -->
  <Extensions>
    <Extension Category="windows.activatableClass.inProcessServer">
      <InProcessServer>
        <Path>Microsoft.Holographic.AppRemoting.dll</Path>
        <ActivatableClass ActivatableClassId="Microsoft.Holographic.AppRemoting.PlayerContext" ThreadingModel="both" />
      </InProcessServer>
    </Extension>
  </Extensions>
  <!--Add lines above -->

</Package>

Erstellen des Playerkontexts

Im ersten Schritt sollte die Anwendung einen Playerkontext erstellen.

// class declaration:

#include <winrt/Microsoft.Holographic.AppRemoting.h>

...

private:
// PlayerContext used to connect with a Holographic Remoting remote app and display remotely rendered frames
winrt::Microsoft::Holographic::AppRemoting::PlayerContext m_playerContext = nullptr;
// class implementation:

// Create the player context
// IMPORTANT: This must be done before creating the HolographicSpace (or any other call to the Holographic API).
m_playerContext = winrt::Microsoft::Holographic::AppRemoting::PlayerContext::Create();

Warnung

Holographic Remoting ersetzt die Windows Mixed Reality Runtime, die Teil Windows ist, durch eine Remoting-spezifische Runtime. Dies erfolgt während der Erstellung des Playerkontexts. Aus diesem Grund kann jeder Aufruf einer beliebigen Windows Mixed Reality-API vor dem Erstellen des Playerkontexts zu unerwartetem Verhalten führen. Der empfohlene Ansatz besteht darin, den Playerkontext so früh wie möglich vor der Interaktion mit einer beliebigen Mixed Reality-API zu erstellen. Mischen Sie niemals Objekte, die über eine Windows Mixed Reality-API erstellt oder abgerufen wurden, vor dem Aufruf von PlayerContext::Create mit Objekten, die anschließend erstellt oder abgerufen wurden.

Als Nächstes kann holographicSpace erstellt werden, indem HolographicSpace.CreateForCoreWindow aufgerufen wird.

m_holographicSpace = winrt::Windows::Graphics::Holographic::HolographicSpace::CreateForCoreWindow(window);

Verbinden zur Remote-App

Sobald die Player-App zum Rendern von Inhalten bereit ist, kann eine Verbindung mit der Remote-App hergestellt werden.

Die Verbindung kann auf eine der folgenden Arten hergestellt werden:

  1. Die Player-App, die auf HoloLens 2 ausgeführt wird, stellt eine Verbindung mit der Remote-App her.
  2. Die Remote-App stellt eine Verbindung mit der Player-App her, die auf HoloLens 2 ausgeführt wird.

Um eine Verbindung zwischen der Player-App und der Remote-App herzustellen, rufen Sie die Connect -Methode im Playerkontext auf, die den Hostnamen und port angibt. Der Standardport ist 8265.

try
{
    m_playerContext.Connect(m_hostname, m_port);
}
catch(winrt::hresult_error& e)
{
    // Failed to connect. Get an error details via e.code() and e.message()
}

Wichtig

Wie bei jeder C++/WinRT-API Connect kann eine winrt::hresult_error ausgelöst werden, die behandelt werden muss.

Das Lauschen auf eingehende Verbindungen in der Player-App kann durch Aufrufen der Listen -Methode erfolgen. Sowohl der Handshakeport als auch der Transportport können während dieses Aufrufs angegeben werden. Der Handshakeport wird für den ersten Handshake verwendet. Die Daten werden dann über den Transportport gesendet. Standardmäßig werden die Portnummern 8265 und 8266 verwendet.

try
{
    m_playerContext.Listen(L"0.0.0.0", m_port, m_port + 1);
}
catch(winrt::hresult_error& e)
{
    // Failed to listen. Get an error details via e.code() and e.message()
}

Der PlayerContext macht drei Ereignisse verfügbar, um den Status der Verbindung zu überwachen.

  1. OnConnected: Wird ausgelöst, wenn eine Verbindung mit der Remote-App erfolgreich hergestellt wurde.
m_onConnectedEventToken = m_playerContext.OnConnected([]() 
{
    // Handle connection successfully established
});
  1. OnDisconnected: Wird ausgelöst, wenn eine hergestellte Verbindung beendet wird oder keine Verbindung hergestellt werden konnte.
m_onDisconnectedEventToken = m_playerContext.OnDisconnected([](ConnectionFailureReason failureReason)
{
    switch (failureReason)
    {
        // Handle connection failed or terminated.
        // See ConnectionFailureReason for possible reasons.
    }
}

Hinweis

Mögliche ConnectionFailureReason Werte sind in der Microsoft.Holographic.AppRemoting.idlDatei dokumentiert.

  1. OnListening: Beim Lauschen auf eingehende Verbindungen wird gestartet.
m_onListeningEventToken = m_playerContext.OnListening([]()
{
    // Handle start listening for incoming connections
});

Darüber hinaus kann der Verbindungszustand mithilfe der ConnectionState -Eigenschaft im Playerkontext abgefragt werden.

winrt::Microsoft::Holographic::AppRemoting::ConnectionState state = m_playerContext.ConnectionState();

Anzeigen des remote gerenderten Frames

Rufen Sie auf, während Sie einen HolographicFrame rendern, PlayerContext::BlitRemoteFrame um den per Remotezugriff gerenderten Inhalt anzuzeigen.

BlitRemoteFrame erfordert, dass der Hintergrundpuffer für den aktuellen HolographicFrame als Renderziel gebunden ist. Der Hintergrundpuffer kann von HolographicCameraRenderingParameters über die Direct3D11BackBuffer-Eigenschaft empfangen werden.

Kopiert beim Aufruf BlitRemoteFrame den zuletzt empfangenen Frame aus der Remoteanwendung in den BackBuffer des HolographicFrame. Darüber hinaus wird der Fokuspunktsatz festgelegt, wenn die Remoteanwendung während des Renderns des Remoteframes einen Fokuspunkt angegeben hat.

// Blit the remote frame into the backbuffer for the HolographicFrame.
winrt::Microsoft::Holographic::AppRemoting::BlitResult result = m_playerContext.BlitRemoteFrame();

Hinweis

PlayerContext::BlitRemoteFrame überschreibt möglicherweise den Fokuspunkt für den aktuellen Frame.

Bei Erfolg BlitRemoteFrame gibt zurück BlitResult::Success_Color. Andernfalls wird die Fehlerursache zurückgegeben:

  • BlitResult::Failed_NoRemoteFrameAvailable: Fehler, weil kein Remoteframe verfügbar ist.
  • BlitResult::Failed_NoCamera: Fehler, weil keine Kamera vorhanden ist.
  • BlitResult::Failed_RemoteFrameTooOld: Fehler, weil der Remoteframe zu alt ist (siehe PlayerContext::BlitRemoteFrameTimeout-Eigenschaft).

Wichtig

Ab Version 2.1.0 ist es mit einem benutzerdefinierten Player möglich, die Tiefenreprojektion über Holographic Remoting zu verwenden.

BlitResult kann auch unter den folgenden Bedingungen zurückgeben BlitResult::Success_Color_Depth :

Wenn diese Bedingungen erfüllt sind, BlitRemoteFrame blitt die Remotetiefe in den derzeit gebundenen lokalen Tiefenpuffer ein. Anschließend können Sie zusätzlichen lokalen Inhalt rendern, der eine tiefen Schnittmenge mit dem remote gerenderten Inhalt hat. Darüber hinaus können Sie den lokalen Tiefenpuffer über HolographicCameraRenderingParameters.CommitDirect3D11DepthBuffer in Ihrem benutzerdefinierten Player committen, um eine ausführliche Neuprojektion für remote und lokal gerenderte Inhalte zu erhalten.

Projektionstransformationsmodus

Ein Problem, das bei der Verwendung der Tiefenreprojektion über Holographic Remoting auftritt, besteht darin, dass der Remoteinhalt mit einer anderen Projektionstransformation als lokaler Inhalt gerendert werden kann, der direkt von Ihrer benutzerdefinierten Player-App gerendert wird. Ein häufiger Anwendungsfall ist die Angabe verschiedener Werte für die Nah- und Fernebene (über HolographicCamera::SetNearPlaneDistance und HolographicCamera::SetFarPlaneDistance) auf player- und remote-Seite. In diesem Fall ist nicht klar, ob die Projektionstransformation auf spielerseitiger Seite die Entfernungen der remoten Nah-/Fernebene oder der lokalen Ebene widerspiegeln soll.

Ab Version 2.1.0 können Sie den Projektionstransformationsmodus über PlayerContext::ProjectionTransformConfigsteuern. Diese Werte werden unterstützt:

  • Local - HolographicCameraPose::P rojectionTransform gibt eine Projektionstransformation zurück, die die Entfernungen der nah/fernen Ebene widerspiegelt, die von Ihrer benutzerdefinierten Player-App auf der HolographicCamera festgelegt wurden.
  • Remote – Die Projektionstransformation spiegelt die Entfernungen der nah/fernen Ebene wider, die von der Remote-App angegeben werden.
  • Merged – Entfernungen der Nah-/Fernebene von Ihrer Remote-App und Ihrer benutzerdefinierten Player-App werden zusammengeführt. Dies geschieht standardmäßig, indem der Mindestwert der Entfernungen in der Nähesebene und die maximale Entfernung der fernen Ebene verwendet wird. Für den Fall, dass entweder die Remoteseite oder die lokale Seite invertiert wird, z. B. weit < in der Nähe, werden die Entfernungen der Remote-Nah-/Fernebene gekippt.

Optional: Festlegen von BlitRemoteFrameTimeout

Wichtig

PlayerContext::BlitRemoteFrameTimeout wird ab Version 2.0.9 unterstützt.

Die PlayerContext::BlitRemoteFrameTimeout -Eigenschaft gibt an, wie lange ein Remoteframe wiederverwendet wird, wenn kein neuer Remoteframe empfangen wird.

Ein häufiger Anwendungsfall besteht darin, das BlitRemoteFrame-Timeout so zu aktivieren, dass ein leerer Bildschirm angezeigt wird, wenn für einen bestimmten Zeitraum keine neuen Frames empfangen werden. Wenn diese Option aktiviert ist, kann der Rückgabetyp der BlitRemoteFrame Methode auch verwendet werden, um zu einem lokal gerenderten Fallbackinhalt zu wechseln.

Um das Timeout zu aktivieren, legen Sie den Eigenschaftswert auf eine Dauer von mindestens 100 ms fest. Um das Timeout zu deaktivieren, legen Sie die -Eigenschaft auf 0 (null) fest. Wenn das Timeout aktiviert ist und für die festgelegte Dauer kein Remoteframe empfangen wird, schlägt BlitRemoteFrame fehl und gibt zurück Failed_RemoteFrameTooOld , bis ein neuer Remoteframe empfangen wird.

using namespace std::chrono_literals;

// Set the BlitRemoteFrame timeout to 0.5s
m_playerContext.BlitRemoteFrameTimeout(500ms);

Optional: Abrufen von Statistiken zum letzten Remoteframe

Um Leistungs- oder Netzwerkprobleme zu diagnostizieren, können Statistiken zum letzten Remoteframe über die PlayerContext::LastFrameStatistics -Eigenschaft abgerufen werden. Statistiken werden während des Aufrufs von HolographicFrame::P resentUsingCurrentPrediction aktualisiert.

// Get statistics for the last presented frame.
winrt::Microsoft::Holographic::AppRemoting::PlayerFrameStatistics statistics = m_playerContext.LastFrameStatistics();

Weitere Informationen finden Sie in der PlayerFrameStatistics Dokumentation in der Microsoft.Holographic.AppRemoting.idlDatei.

Optional: Benutzerdefinierte Datenkanäle

Benutzerdefinierte Datenkanäle können verwendet werden, um Benutzerdaten über die bereits eingerichtete Remotingverbindung zu senden. Weitere Informationen finden Sie unter Benutzerdefinierte Datenkanäle.

Optional: Over-Rendering

Holographic Remoting sagt vorher, wo sich der Kopf des Benutzers zu dem Zeitpunkt bewegt, zu dem die gerenderten Bilder auf den Bildschirmen angezeigt werden. Diese Vorhersage ist jedoch eine Näherung. Daher kann sich der vorhergesagte Viewport in der Remote-App und der spätere tatsächliche Viewport in der Player-App unterscheiden. Stärkere Abweichungen (z. B. aufgrund unvorhersehbarer Bewegung) können schwarze Bereiche an den Rändern des Sicht-Frustums verursachen. Ab Version 2.6.0 können Sie Over-Rendering verwenden, um die schwarzen Bereiche zu reduzieren und die visuelle Qualität zu verbessern, indem Sie den Viewport über das Anzeige-Frustum hinaus künstlicher erhöhen.

Over-Rendering können über PlayerContext::ConfigureOverRenderingaktiviert werden.

Gibt OverRenderingConfig eine Erhöhung der Bruchgröße auf den tatsächlichen Viewport an, sodass der vorhergesagte Viewport größer wird und weniger Schnittmengen auftreten. Bei einer erhöhten Viewportgröße verringert sich die Pixeldichte, sodass Sie mit OverRenderingConfig auch die Auflösung erhöhen können. Wenn die Viewporterhöhung gleich der Auflösungserhöhung ist, bleibt die Pixeldichte unverändert. OverRenderingConfig wird folgendermaßen definiert:

struct OverRenderingConfig
{
    float HorizontalViewportIncrease; // The fractional horizontal viewport increase. (e.g. 10% -> 0.1).
    float VerticalViewportIncrease; // The fractional vertical viewport increase. (e.g. 10% -> 0.1).
                
    float HorizontalResolutionIncrease; // The fractional horizontal resolution increase. (e.g. 10% -> 0.1).
    float VerticalResolutionIncrease; // The fractional vertical resolution increase. (e.g. 10% -> 0.1).
};

Optional: Koordinatensystemsynchronisierung

Ab Version 2.7.0 kann die Koordinatensystemsynchronisierung verwendet werden, um räumliche Daten zwischen dem Player und der Remote-App auszurichten. Weitere Informationen finden Sie unter Übersicht über die Koordinatensystemsynchronisierung mit Holographic Remoting.

Weitere Informationen