Schreiben einer benutzerdefinierten Holographic Remoting Player-App

Wenn Sie noch nicht mit Holographic Remoting sind, sollten 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 die NuGet-Paketversion 2.x.x verwenden müssen.

Durch Erstellen einer benutzerdefinierten Holographic Remoting-Player-App können Sie eine benutzerdefinierte Anwendung erstellen, die immersive Ansichten auf einem Remotecomputer auf Ihrem HoloLens 2 anzeigen kann. Der gesamte Code auf dieser Seite und funktionierende Projekte finden Sie im Github-Repository für Holographic Remoting-Beispiele.

Mit einem Holographic Remoting-Player kann Ihre App holografische Inhalte anzeigen, die auf einem Desktop-PC oder einem UWP-Gerät wie der Xbox One gerendert werden , 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 über das standardmäßige WLAN hergestellt. Um eine Player-App zu erstellen, verwenden Sie ein NuGet-Paket, um Holographic Remoting zu 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. Ausführliche Informationen finden Sie unter Übersicht über die DirectX-Entwicklung. Wenn Sie noch keine App haben und von Grund auf neu beginnen möchten, ist die holografische C++-Projektvorlage ein guter Ausgangspunkt.

Wichtig

Jede App, die Holographic Remoting verwendet, sollte für die Verwendung eines Multithread-Apartments erstellt werden. Die Verwendung eines Singlethread-Apartments wird unterstützt, führt aber zu einer suboptimalen Leistung und möglicherweise zu Stottern während der Wiedergabe. Bei Verwendung von C++/WinRT ist winrt::init_apartment 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, stellen Sie sicher, dass Sie die neueste Version 2.x.x auswählen, 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 , wenn das Dialogfeld "Lizenzvereinbarung" angezeigt wird.

Wichtig

Das build\native\include\HolographicAppRemoting\Microsoft.Holographic.AppRemoting.idl im NuGet-Paket enthaltene ausführliche Dokumentation für die API, die von Holographic Remoting verfügbar gemacht wird.

Ändern des Package.appxmanifest der Anwendung

Um die Anwendung auf die vom NuGet-Paket hinzugefügten Microsoft.Holographic.AppRemoting.dll aufmerksam zu machen, 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...
  2. Wählen Sie XML (Text)-Editor aus, und wählen Sie 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

Ein benutzerdefinierter Player fügt eine zwischengeschaltete Ebene zwischen der Player-App und der mit Windows ausgelieferten Windows Mixed Reality Runtime ein. Dies geschieht während der Erstellung des Playerkontexts. Aus diesem Grund kann jeder Aufruf einer 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 Mixed Reality-API zu erstellen. Mischen Sie niemals Objekte, die vor dem Aufruf PlayerContext::Create von über eine Windows Mixed Reality-API erstellt oder abgerufen wurden, mit Objekten, die anschließend erstellt oder abgerufen werden.

Als Nächstes kann holographicSpace erstellt werden, indem Sie HolographicSpace.CreateForCoreWindow aufrufen.

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

Herstellen einer Verbindung mit der 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, indem Sie hostnamen und port angeben. 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 verarbeitet werden muss.

Das Lauschen auf eingehende Verbindungen in der Player-App kann durch Aufrufen der Listen -Methode erfolgen. Während dieses Aufrufs können sowohl der Handshakeport als auch der Transportport 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()
}

Macht PlayerContext 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 verbindung beendet 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 werden 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 Verbindungsstatus mithilfe der ConnectionState -Eigenschaft im Playerkontext abgefragt werden.

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

Anzeigen des remote gerenderten Frames

Um den remote gerenderten Inhalt anzuzeigen, rufen Sie PlayerContext::BlitRemoteFrame beim Rendern eines HolographicFrame auf.

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

Kopiert beim Aufruf BlitRemoteFrame den neuesten empfangenen Frame aus der Remoteanwendung in den BackBuffer des HolographicFrame. Zusätzlich wird der Fokuspunkt festgelegt, wenn die Remoteanwendung während des Renderings 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.

Gibt bei Erfolg BlitRemoteFrame zurück BlitResult::Success_Color. Andernfalls wird der Fehlergrund zurückgegeben:

  • BlitResult::Failed_NoRemoteFrameAvailable: Fehler, da kein Remoteframe verfügbar ist.
  • BlitResult::Failed_NoCamera: Fehler, da 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ückgegeben BlitResult::Success_Color_Depth werden:

Wenn diese Bedingungen erfüllt sind, BlitRemoteFrame wird die Remotetiefe in den derzeit gebundenen lokalen Tiefenpuffer eingespalten. Anschließend können Sie zusätzliche lokale Inhalte rendern, die eine Tiefenschnittmenge mit dem remote gerenderten Inhalt aufweisen. Darüber hinaus können Sie den lokalen Tiefenpuffer über HolographicCameraRenderingParameters.CommitDirect3D11DepthBuffer in Ihrem benutzerdefinierten Player committen, um eine Tiefenreprojektion für remote und lokal gerenderte Inhalte durchzuführen.

Projektionstransformationsmodus

Ein Problem, das bei verwendung der Tiefenreprojektion über Holographic Remoting auftritt, besteht darin, dass der Remoteinhalt mit einer anderen Projektionstransformation gerendert werden kann als lokale Inhalte, die direkt von Ihrer benutzerdefinierten Player-App gerendert werden. Ein gängiger Anwendungsfall ist das Angeben unterschiedlicher Werte für die Nah- und Fernebene (über HolographicCamera::SetNearPlaneDistance und HolographicCamera::SetFarPlaneDistance) auf der Spielerseite und auf der Remoteseite. In diesem Fall ist es nicht klar, ob die Projektionstransformation auf der Seite des Spielers die entfernten entfernungsnahen/fernen Ebenen oder die lokalen Abbilder 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 von Ihrer benutzerdefinierten Player-App auf der HolographicCamera festgelegten Entfernungen der nah-/fernen Ebene widerspiegelt.
  • Remote – Die Projektionstransformation spiegelt die von der Remote-App angegebenen Entfernungen auf der Nah-/Fernebene wider.
  • Merged – Die Entfernungen der Nah-/Fernebene von Ihrer Remote-App und Ihrer benutzerdefinierten Player-App werden zusammengeführt. Standardmäßig erfolgt dies, indem das Minimum der Entfernungen in der Nähe der Ebene und das Maximum der Entfernungen der fernen Ebene berücksichtigt wird. Wenn entweder die Remote- oder die lokale Seite invertiert ist, z. B. weit < in der Nähe, werden die entfernungsnahen/fernen Ebenen umgedreht.

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 gängiger Anwendungsfall besteht darin, das BlitRemoteFrame-Timeout so zu aktivieren, dass ein leerer Bildschirm angezeigt wird, wenn für eine bestimmte Zeit keine neuen Frames empfangen werden. Bei Aktivierung 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 null Dauer fest. Wenn das Timeout aktiviert ist und kein Remoteframe für die festgelegte Dauer empfangen wird, schlägt BlitRemoteFrame fehl und kehrt 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 bestehende Remotingverbindung zu senden. Weitere Informationen finden Sie unter Benutzerdefinierte Datenkanäle.

Optional: Over-Rendering

Holographic Remoting sagt voraus, wo sich der Kopf des Benutzers befindet, wenn die gerenderten Bilder auf den Displays angezeigt werden. Diese Vorhersage ist jedoch eine Näherung. Daher können sich der vorhergesagte Viewport für die 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 Regionen an den Grenzen des Seh frustums verursachen. Ab Version 2.6.0 können Sie Over-Rendering verwenden, um die schwarzen Regionen zu reduzieren und die visuelle Qualität zu verbessern, indem Sie den Viewport über den Anzeige frustum hinaus künstlich erhöhen.

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

Gibt OverRenderingConfig eine Vergrößerung der Bruchgröße auf den tatsächlichen Viewport an, sodass der vorhergesagte Viewport größer wird und weniger Schnitte auftreten. Bei einer erhöhten Viewportgröße nimmt die Pixeldichte ab, 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 gleich. 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 Koordinatensystemsynchronisierung mit holographic Remoting – Übersicht.

Weitere Informationen