Scrittura di un'app Holographic Remoting Player personalizzata

Se non si ha familiarità con Holographic Remoting, è possibile leggere la panoramica.

Importante

Questo documento descrive la creazione di un'applicazione lettore personalizzata per HoloLens 2. I lettori personalizzati scritti per HoloLens 2 non sono compatibili con le applicazioni remote scritte per HoloLens 1. Ciò implica che entrambe le applicazioni devono usare il pacchetto NuGet versione 2.x.x.

Creando un'app lettore Holographic Remoting personalizzata, è possibile creare un'applicazione personalizzata in grado di visualizzare visualizzazioni immersive da un computer remoto nel HoloLens 2. Tutto il codice in questa pagina e i progetti funzionanti sono disponibili nel repository GitHub degli esempi di Holographic Remoting.

Un lettore Holographic Remoting consente all'app di visualizzare il contenuto olografico di cui viene eseguito il rendering in un PC desktop o in un dispositivo UWP come Xbox One con accesso a più risorse di sistema. Un'app lettore Holographic Remoting trasmette i dati di input a un'applicazione remota Holographic Remoting e riceve una visualizzazione immersiva come flusso video e audio. La connessione viene effettuata tramite Wi-Fi standard. Per creare un'app lettore, usa un pacchetto NuGet per aggiungere Holographic Remoting alla tua app UWP. Scrivere quindi codice per gestire la connessione e visualizzare una visualizzazione immersiva.

Prerequisiti

Un buon punto di partenza è un'app UWP basata su DirectX che ha già come destinazione l'API Windows Mixed Reality. Per informazioni dettagliate, vedere Panoramica dello sviluppo DirectX. Se non si ha un'app esistente e si vuole iniziare da zero, il modello di progetto olografico C++ è un buon punto di partenza.

Importante

Qualsiasi app che usa Holographic Remoting deve essere creata per usare un apartment multithread. L'uso di un apartment a thread singolo è supportato , ma comporta prestazioni non ottimali e possibilmente stuttering durante la riproduzione. Quando si usa C++/ WinRT winrt::init_apartment un apartment multithread è l'impostazione predefinita.

Ottenere il pacchetto NuGet Holographic Remoting

Per aggiungere il pacchetto NuGet a un progetto in Visual Studio, sono necessari i passaggi seguenti.

  1. Aprire il progetto in Visual Studio.
  2. Fare clic con il pulsante destro del mouse sul nodo del progetto e scegliere Gestisci pacchetti NuGet...
  3. Nel pannello visualizzato selezionare Sfoglia e quindi cercare "Holographic Remoting".
  4. Selezionare Microsoft.Holographic.Remoting, assicurarsi di selezionare la versione 2.x.x più recente e selezionare Installa.
  5. Se viene visualizzata la finestra di dialogo Anteprima , selezionare OK.
  6. Selezionare Accetto quando viene visualizzata la finestra di dialogo del contratto di licenza.

Importante

L'oggetto build\native\include\HolographicAppRemoting\Microsoft.Holographic.AppRemoting.idl all'interno del pacchetto NuGet contiene documentazione dettagliata per l'API esposta da Holographic Remoting.

Modificare package.appxmanifest dell'applicazione

Per rendere l'applicazione consapevole del Microsoft.Holographic.AppRemoting.dll aggiunto dal pacchetto NuGet, è necessario eseguire i passaggi seguenti nel progetto:

  1. Nel Esplora soluzioni fare clic con il pulsante destro del mouse sul file Package.appxmanifest e scegliere Apri con...
  2. Selezionare Editor XML (testo) e selezionare OK
  3. Aggiungere le righe seguenti al file e salvare
  </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>

Creare il contesto del lettore

Come primo passaggio, l'applicazione deve creare un contesto del lettore.

// 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();

Avviso

Un lettore personalizzato inserisce un livello intermedio tra l'app lettore e il runtime Windows Mixed Reality fornito con Windows. Questa operazione viene eseguita durante la creazione del contesto del giocatore. Per questo motivo, qualsiasi chiamata a qualsiasi API Windows Mixed Reality prima di creare il contesto del giocatore può comportare un comportamento imprevisto. L'approccio consigliato consiste nel creare il contesto del giocatore il prima possibile prima dell'interazione con qualsiasi API Realtà mista. Non combinare mai oggetti creati o recuperati tramite qualsiasi API Windows Mixed Reality prima della chiamata a PlayerContext::Create con oggetti creati o recuperati in seguito.

Successivamente è possibile creare HolographicSpace chiamando HolographicSpace.CreateForCoreWindow.

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

Connettersi all'app remota

Quando l'app lettore è pronta per il rendering del contenuto, è possibile stabilire una connessione all'app remota.

La connessione può essere stabilita in uno dei modi seguenti:

  1. L'app lettore in esecuzione in HoloLens 2 si connette all'app remota.
  2. L'app remota si connette all'app lettore in esecuzione in HoloLens 2.

Per connettersi dall'app lettore all'app remota, chiamare il Connect metodo nel contesto del lettore specificando il nome host e la porta. La porta predefinita è 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()
}

Importante

Come per qualsiasi API C++/WinRT, potrebbe generare un'eccezione Connect winrt::hresult_error che deve essere gestita.

L'ascolto delle connessioni in ingresso nell'app lettore può essere eseguita chiamando il Listen metodo . Durante questa chiamata è possibile specificare sia la porta handshake che la porta di trasporto. La porta handshake viene usata per l'handshake iniziale. I dati vengono quindi inviati sulla porta di trasporto. Per impostazione predefinita vengono usati il numero di porta 8265 e 8266 .

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()
}

PlayerContext espone tre eventi per monitorare lo stato della connessione

  1. OnConnected: attivato quando è stata stabilita una connessione all'app remota.
m_onConnectedEventToken = m_playerContext.OnConnected([]() 
{
    // Handle connection successfully established
});
  1. OnDisconnected: attivato se una connessione stabilita viene terminata o non è stato possibile stabilire una connessione.
m_onDisconnectedEventToken = m_playerContext.OnDisconnected([](ConnectionFailureReason failureReason)
{
    switch (failureReason)
    {
        // Handle connection failed or terminated.
        // See ConnectionFailureReason for possible reasons.
    }
}

Nota

I valori possibili ConnectionFailureReason sono documentati nel Microsoft.Holographic.AppRemoting.idlfile.

  1. OnListening: quando si avvia l'ascolto delle connessioni in ingresso.
m_onListeningEventToken = m_playerContext.OnListening([]()
{
    // Handle start listening for incoming connections
});

È anche possibile eseguire query sullo stato della connessione usando la ConnectionState proprietà nel contesto del lettore.

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

Visualizzare il frame di cui è stato eseguito il rendering remoto

Per visualizzare il contenuto sottoposto a rendering remoto, chiamare PlayerContext::BlitRemoteFrame durante il rendering di un HolographicFrame.

BlitRemoteFrame richiede che il buffer nascosto per l'holographicFrame corrente sia associato come destinazione di rendering. Il buffer nascosto può essere ricevuto da HolographicCameraRenderingParameters tramite la proprietà Direct3D11BackBuffer .

Quando viene chiamato, BlitRemoteFrame copia il frame ricevuto più recente dall'applicazione remota nel BackBuffer di HolographicFrame. Viene inoltre impostato il set di punti di messa a fuoco, se l'applicazione remota ha specificato un punto attivo durante il rendering del frame remoto.

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

Nota

PlayerContext::BlitRemoteFrame sovrascrive potenzialmente il punto di messa a fuoco per il frame corrente.

In caso di esito positivo, BlitRemoteFrame restituisce BlitResult::Success_Color. In caso contrario, restituisce il motivo dell'errore:

  • BlitResult::Failed_NoRemoteFrameAvailable: operazione non riuscita perché non è disponibile alcun frame remoto.
  • BlitResult::Failed_NoCamera: non è stato possibile perché non è presente alcuna fotocamera.
  • BlitResult::Failed_RemoteFrameTooOld: non riuscito perché il frame remoto è troppo vecchio (vedere la proprietà PlayerContext::BlitRemoteFrameTimeout).

Importante

A partire dalla versione 2.1.0 è possibile con un lettore personalizzato usare la riprogettazione della profondità tramite Holographic Remoting.

BlitResult può anche restituire BlitResult::Success_Color_Depth in base alle condizioni seguenti:

Se queste condizioni vengono soddisfatte, BlitRemoteFrame influirà la profondità remota nel buffer di profondità locale attualmente associato. È quindi possibile eseguire il rendering di contenuto locale aggiuntivo, che avrà un'intersezione di profondità con il contenuto sottoposto a rendering remoto. È anche possibile eseguire il commit del buffer di profondità locale tramite HolographicCameraRenderingParameters.CommitDirect3D11DepthBuffer nel lettore personalizzato per avere una riprogettazione approfondita per il contenuto sottoposto a rendering remoto e locale.

Modalità trasformazione proiezione

Un problema che si verifica quando si usa la riprogettazione di profondità tramite Holographic Remoting è che il rendering del contenuto remoto può essere eseguito con una trasformazione di proiezione diversa rispetto al contenuto locale di cui è stato eseguito il rendering diretto dall'app lettore personalizzata. Un caso d'uso comune consiste nel specificare valori diversi per il piano vicino e lontano (tramite HolographicCamera::SetNearPlaneDistance e HolographicCamera::SetFarPlaneDistance) sul lato giocatore e sul lato remoto. In questo caso, non è chiaro se la trasformazione di proiezione sul lato giocatore deve riflettere le distanze remote del piano vicino/lontano o quelle locali.

A partire dalla versione 2.1.0 è possibile controllare la modalità di trasformazione della proiezione tramite PlayerContext::ProjectionTransformConfig. I valori supportati sono:

  • Local - HolographicCameraPose::P rojectionTransform restituisce una trasformazione di proiezione, che riflette le distanze del piano vicino/lontano impostate dall'app lettore personalizzata in HolographicCamera.
  • Remote - La trasformazione di proiezione riflette le distanze del piano vicino/lontano specificate dall'app remota.
  • Merged - Distanze del piano vicino/lontano dall'app remota e l'app lettore personalizzata vengono unite. Per impostazione predefinita, questa operazione viene eseguita prendendo il minimo delle distanze del piano vicino e il massimo delle distanze del piano lontano. Nel caso in cui il lato remoto o locale sia invertito, ad esempio molto vicino < , le distanze remote vicino/lontano vengono capovolte.

Facoltativo: impostare BlitRemoteFrameTimeout

Importante

PlayerContext::BlitRemoteFrameTimeout è supportato a partire dalla versione 2.0.9.

La PlayerContext::BlitRemoteFrameTimeout proprietà specifica il periodo di tempo in cui viene riutilizzato un frame remoto se non viene ricevuto alcun nuovo frame remoto.

Un caso d'uso comune consiste nell'abilitare il timeout BlitRemoteFrame per visualizzare una schermata vuota se non vengono ricevuti nuovi fotogrammi per un determinato periodo di tempo. Se abilitato, è anche possibile usare il tipo restituito del BlitRemoteFrame metodo per passare a un contenuto di fallback sottoposto a rendering locale.

Per abilitare il timeout, impostare il valore della proprietà su una durata uguale o maggiore di 100 ms. Per disabilitare il timeout, impostare la proprietà su zero duration. Se il timeout è abilitato e non viene ricevuto alcun frame remoto per la durata impostata, BlitRemoteFrame avrà esito negativo e restituirà Failed_RemoteFrameTooOld finché non viene ricevuto un nuovo frame remoto.

using namespace std::chrono_literals;

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

Facoltativo: ottenere statistiche sull'ultimo frame remoto

Per diagnosticare i problemi di prestazioni o di rete, è possibile recuperare le statistiche sull'ultimo frame remoto tramite la PlayerContext::LastFrameStatistics proprietà . Le statistiche vengono aggiornate durante la chiamata a HolographicFrame::P resentUsingCurrentPrediction.

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

Per altre informazioni, vedere la PlayerFrameStatistics documentazione nel Microsoft.Holographic.AppRemoting.idlfile .

Facoltativo: canali dati personalizzati

I canali dati personalizzati possono essere usati per inviare dati utente tramite la connessione remota già stabilita. Per altre informazioni, vedere Canali dati personalizzati.

Facoltativo: Over-Rendering

Holographic Remoting prevede la posizione in cui l'intestazione dell'utente sarà al momento della visualizzazione delle immagini di cui è stato eseguito il rendering. Tuttavia, questa stima è un'approssimazione. Di conseguenza, il viewport stimato nell'app remota e il viewport effettivo successivo nell'app lettore possono differire. Deviazioni più forti (ad esempio, a causa di un movimento imprevedibile) potrebbero causare aree nere ai bordi del frustum di visualizzazione. A partire dalla versione 2.6.0 è possibile usare Over-Rendering per ridurre le aree nere e migliorare la qualità visiva aumentando artificialmente il riquadro di visualizzazione oltre il frustum di visualizzazione.

Over-Rendering può essere abilitato tramite PlayerContext::ConfigureOverRendering.

OverRenderingConfig Specifica un aumento delle dimensioni frazionarie al riquadro di visualizzazione effettivo, in modo che il riquadro di visualizzazione stimato diventi più grande e minore si verifichi un taglio. Con una maggiore dimensione del riquadro di visualizzazione, la densità dei pixel diminuisce, quindi OverRenderingConfig consente di aumentare anche la risoluzione. Se l'aumento del riquadro di visualizzazione è uguale alla risoluzione, aumentare la densità dei pixel rimane invariata. L'oggetto OverRenderingConfig viene definito come:

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).
};

Facoltativo: sincronizzazione del sistema di coordinate

A partire dalla versione 2.7.0 è possibile usare la sincronizzazione del sistema di coordinate per allineare i dati spaziali tra il lettore e l'app remota. Per altre informazioni, vedere Coordinate System Synchronization with Holographic Remoting Overview .For more information, see Coordinate System Synchronization with Holographic Remoting Overview.

Vedere anche