Condividi tramite


Riproiezione con ritardo della fase

LSR (Late Stage Reprojection) è una funzionalità hardware che consente di stabilizzare gli ologrammi quando l'utente si sposta.

I modelli statici devono mantenere visivamente la loro posizione quando si spostano. Se sembrano essere instabili, questo comportamento può suggerire problemi LSR. Tenere presente che trasformazioni dinamiche aggiuntive, ad esempio animazioni o visualizzazioni di esplosione, potrebbero mascherare questo comportamento.

È possibile scegliere tra due diverse modalità LSR, ovvero LSR planare o Depth LSR. Entrambe le modalità LSR migliorano la stabilità dell'ologramma, anche se presentano limitazioni distinte. Per iniziare, provare Depth LSR, perché è probabilmente dare risultati migliori nella maggior parte dei casi.

Come impostare la modalità LSR

Quale delle modalità LSR viene usata è determinata dal fatto che l'applicazione client invii un buffer di profondità. Se il buffer di profondità viene inviato, usa Depth LSR e Planar LSR in caso contrario.

I paragrafi seguenti illustrano come inviare il buffer di profondità vengono eseguiti rispettivamente in Unity e nelle applicazioni native.

Unity

Nell'editor di Unity passare a File > Build Settings. Selezionare Player Settings in basso a sinistra, quindi controllare Player > XR Settings > Virtual Reality SDKs > Windows Mixed Reality se Enable Depth Buffer Sharing è selezionato:

Flag Depth Buffer Sharing Enabled

In caso affermativo, l'app userà Depth LSR, altrimenti userà planar LSR.

Quando si usa OpenXR, il buffer di profondità deve essere sempre inviato. L'impostazione è disponibile in XR Plug-in Management > OpenXR. La modalità di riprogettazione può quindi essere modificata tramite un'estensione nel plug-in OpenXR:

using Microsoft.MixedReality.OpenXR;

public class OverrideReprojection : MonoBehaviour
{
    void OnEnable()
    {
        RenderPipelineManager.endCameraRendering += RenderPipelineManager_endCameraRendering;
    }
    void OnDisable()
    {
        RenderPipelineManager.endCameraRendering -= RenderPipelineManager_endCameraRendering;
    }

    // When using the Universal Render Pipeline, OnPostRender has to be called manually.
    private void RenderPipelineManager_endCameraRendering(ScriptableRenderContext context, Camera camera)
    {
        OnPostRender();
    }

    // Called directly when using Unity's legacy renderer.
    private void OnPostRender()
    {
        ReprojectionSettings reprojectionSettings = default;
        reprojectionSettings.ReprojectionMode = ReprojectionMode.PlanarManual; // Or your favorite reprojection mode.
        
        // In case of PlanarManual you also need to provide a focus point here.
        reprojectionSettings.ReprojectionPlaneOverridePosition = ...;
        reprojectionSettings.ReprojectionPlaneOverrideNormal = ...;
        reprojectionSettings.ReprojectionPlaneOverrideVelocity = ...;

        foreach (ViewConfiguration viewConfiguration in ViewConfiguration.EnabledViewConfigurations)
        {
            if (viewConfiguration.IsActive && viewConfiguration.SupportedReprojectionModes.Contains(reprojectionSettings.ReprojectionMode))
            {
                viewConfiguration.SetReprojectionSettings(reprojectionSettings);
            }
        }
    }
}

Applicazioni C++ native

L'invio del buffer di profondità è completamente sotto controllo del codice di associazione C++ nativo, indipendentemente dalla versione WMR o OpenXR. L'unica condizione che deve essere soddisfatta è che nel momento in cui GraphicsBinding::BlitRemoteFrame viene chiamato un buffer di profondità deve essere associato all'API grafica.

Depth LSR

Per il funzionamento di Depth LSR, l'applicazione client deve fornire un buffer di profondità valido che contiene tutta la geometria pertinente da considerare durante LSR.

Depth LSR tenta di stabilizzare il fotogramma video in base al contenuto del buffer di profondità fornito. Di conseguenza, il contenuto di cui non è stato eseguito il rendering, ad esempio gli oggetti trasparenti, non può essere regolato da LSR e può mostrare instabilità e reprogettazione degli artefatti.

Per attenuare l'instabilità della riprogettazione per gli oggetti trasparenti, è possibile forzare la scrittura del buffer di profondità. Vedi il flag materiale TransparencyWritesDepth per i materiali Color e PBR . Si noti tuttavia che la qualità visiva dell'interazione tra oggetti trasparenti/opachi può risentire quando si abilita questo flag.

LSR planare

LSR planare non dispone di informazioni sulla profondità per pixel, come fa Depth LSR. Riprogetta invece tutto il contenuto in base a un piano che è necessario fornire ogni fotogramma.

Planar LSR riprogetta gli oggetti migliori che si trovano vicino al piano fornito. Più lontano è un oggetto, più instabile sarà. Anche se Depth LSR è preferibile riprogettare oggetti a profondità diverse, LSR planare può funzionare meglio per l'allineamento del contenuto con un piano.

Configurare LSR planare in Unity

I parametri del piano sono derivati da un cosiddetto punto di attivazione. Quando si usa WMR, il punto di attivazione deve essere impostato su ogni fotogramma tramite UnityEngine.XR.WSA.HolographicSettings.SetFocusPointForFrame. Per informazioni dettagliate, vedere l'API Del punto attivo di Unity. Per OpenXR, il punto di attivazione deve essere impostato tramite l'oggetto ReprojectionSettings illustrato nella sezione precedente. Se non imposti un punto attivo, verrà scelto automaticamente un fallback. Tuttavia, il fallback automatico spesso comporta risultati non ottimali.

È possibile calcolare manualmente il punto attivo, anche se può essere utile basarlo su quello calcolato dall'host Rendering remoto. Chiamare RemoteManagerUnity.CurrentSession.GraphicsBinding.GetRemoteFocusPoint per ottenerlo.

In genere sia il client che l'host eseguono il rendering del contenuto di cui l'altro lato non è a conoscenza, ad esempio gli elementi dell'interfaccia utente nel client. Pertanto, potrebbe essere opportuno combinare il punto di attivazione remoto con uno calcolato localmente.

I punti di messa a fuoco calcolati in due fotogrammi successivi possono variare molto. Semplicemente usandoli così com'è può portare a ologrammi che sembrano saltare in giro. Per evitare questo comportamento, è consigliabile eseguire l'interpolazione tra i punti di attivazione precedenti e correnti.

Modalità pose di riprogettazione

L'ambito generale del problema con il rendering ibrido può essere indicato in questo modo: il contenuto remoto e locale si trova all'interno di posizioni distinte (ovvero spazi di coordinate) perché la posizione remota viene stimata dal server, mentre la posizione locale è quella corrente effettiva. Tuttavia, alla fine di un frame di rendering sia il contenuto remoto che quello locale devono essere allineati e portati sullo schermo. La figura seguente mostra un esempio in cui le pose locali e remote vengono convertite rispetto al viewport di visualizzazione:

Diagramma che illustra la posizione remota e locale in relazione al viewport di destinazione.

A seconda dell'oggetto GraphicsBinding usato, ARR fornisce fino a tre modalità di riprogettazione che funzionano in modo ortogonale alla modalità LSR illustrata in precedenza. Queste modalità sono denominate Remote pose mode, Local pose modee Passthrough pose mode. A differenza della modalità LSR, le modalità pose definiscono la modalità di combinazione del contenuto remoto e locale. La scelta della modalità scambia la qualità visiva del contenuto locale per le prestazioni di runtime, quindi le applicazioni devono considerare attentamente quale opzione è appropriata. Vedere le considerazioni seguenti.

Remote pose mode

Remote pose mode è la modalità predefinita in ARR. In questa modalità, il rendering del contenuto locale viene eseguito sopra il flusso di immagini remote in ingresso usando la posizione remota dal frame remoto. Il risultato combinato viene quindi inoltrato al sistema operativo per la riprogettazione finale. Anche se questo approccio usa una sola riprogettazione, la correzione finale si basa sull'intervallo di round trip in modo che venga applicato anche l'errore di riprogettazione completo al contenuto locale. Di conseguenza, il delta di correzione di grandi dimensioni può comportare distorsioni significative della geometria locale, inclusi gli elementi dell'interfaccia utente.

Usando la figura precedente, la trasformazione seguente viene applicata in Remote pose mode:

Passaggi di riprogettazione in modalità pose remota.

Local pose mode

In questa modalità, la riprogettazione viene suddivisa in due passaggi distinti: nel primo passaggio, il contenuto remoto viene riprogetto nello spazio di posa locale, ovvero lo spazio di cui viene eseguito il rendering del contenuto locale nei dispositivi VR/AR per impostazione predefinita. Successivamente, il rendering del contenuto locale viene eseguito sopra questa immagine pre-trasformata usando la posizione locale consueta. Nel secondo passaggio, il risultato combinato viene inoltrato al sistema operativo per la riprogettazione finale. Poiché questa seconda riprogettazione comporta solo un piccolo delta, in realtà lo stesso delta che verrebbe usato se ARR non fosse presente, gli artefatti di distorsione sul contenuto locale vengono ridotti in modo significativo.

Di conseguenza, l'illustrazione è simile alla seguente:

Passaggi di riprogettazione in modalità pose locale.

Passthrough pose mode

Questa modalità pose si comporta essenzialmente come Remote pose mode, ovvero il contenuto locale e remoto viene combinato nello spazio remoto. Tuttavia, il contenuto non verrà riprogetto dopo la combinazione, ma rimarrà nello spazio di posa remoto. Il vantaggio principale di questa modalità è che l'immagine risultante non sarà influenzata da elementi di riprogettazione.

Concettualmente, questa modalità può essere confrontata con le applicazioni di streaming cloud convenzionali. A causa dell'elevata latenza che si verifica, non è adatto per scenari montati a testa, ma è un'alternativa praticabile per Desktop e altre applicazioni a schermo piatto in cui è desiderata una qualità dell'immagine più elevata. È quindi disponibile solo per GraphicsBindingSimD3D11 il momento.

Considerazioni sulle prestazioni e sulla qualità

La scelta della modalità pose ha implicazioni visive sulla qualità e sulle prestazioni. Il costo di runtime aggiuntivo sul lato client per eseguire la riprogettazione aggiuntiva in in Local pose mode un dispositivo HoloLens 2 ammonta a circa 1 millisecondo per fotogramma di tempo GPU. Questo costo aggiuntivo deve essere messo in considerazione se l'applicazione client è già vicina al budget frame di 16 millisecondi. D'altra parte, esistono tipi di applicazioni senza contenuto locale o contenuto locale che non è soggetto a distorsioni degli artefatti. In questi casi Local pose mode non ottiene alcun vantaggio visivo perché la qualità della riprogettazione del contenuto remoto non è influenzata.

Il consiglio generale sarebbe quindi quello di testare le modalità in base al caso d'uso e verificare se il guadagno nella qualità visiva giustifica il sovraccarico aggiuntivo delle prestazioni. È anche possibile attivare o disattivare la modalità in modo dinamico, ad esempio abilitare la modalità locale solo quando vengono visualizzate interfacce utente importanti.

Come modificare l'oggetto Pose mode in fase di esecuzione

L'API client seguente può essere usata per modificare la modalità in fase di esecuzione:

RenderingSession session = ...;
session.GraphicsBinding.SetPoseMode(PoseMode.Local); // set local pose mode
ApiHandle<RenderingSession> session = ...;
session->GetGraphicsBinding()->SetPoseMode(PoseMode::Local); // set local pose mode

In generale, la modalità può essere modificata ogni volta che è disponibile l'oggetto di associazione grafica. Esiste una distinzione importante per GraphicsBindingSimD3D11: la modalità pose può essere modificata solo in PoseMode.Remote, se è stata inizializzata con trame proxy. In caso contrario, la modalità pose può essere attivata PoseMode.Local PoseMode.Passthrough o disattivata solo fino a quando l'associazione grafica non viene reinizializzata. Vedere i due overload di GraphicsBindingSimD3d11.InitSimulation, che accettano puntatori nativi a oggetti ID3D11Texture2D (percorso proxy) o e width height del viewport utente desiderato (percorso non proxy).

Considerazioni sul runtime di Unity desktop

A causa del background tecnico di GraphicsBindingSimD3D11 e del funzionamento del rendering offscreen in Unity, il runtime di Unity ARR richiede all'utente di specificare la modalità di posa desiderata all'avvio di RemoteManagerUnity come indicato di seguito:

public static void InitRemoteManager(Camera camera)
{
    RemoteUnityClientInit clientInit = new RemoteUnityClientInit(camera, PoseMode.Remote);
    RemoteManagerUnity.InitializeManager(clientInit);
}

Se PoseMode.Remote viene specificato, l'associazione grafica verrà inizializzata con trame proxy offscreen e tutto il rendering verrà reindirizzato dalla fotocamera principale della scena Unity a una fotocamera proxy. Questo percorso di codice è consigliato solo per l'utilizzo se sono necessarie modifiche alla PoseMode.Remote modalità di posa di runtime. Se non viene specificata alcuna modalità di posa, il runtime di Unity ARR selezionerà un valore predefinito appropriato a seconda della piattaforma corrente.

Avviso

Il reindirizzamento della fotocamera proxy potrebbe non essere compatibile con altre estensioni unity, che prevedono che il rendering della scena venga eseguito con la fotocamera principale. La fotocamera proxy può essere recuperata tramite la RemoteManagerUnity.ProxyCamera proprietà se deve essere eseguita una query o registrata altrove. In particolare per il Cinemachine plug-in, fare riferimento a questa voce di risoluzione dei problemi: il plug-in Unity Cinemachine non funziona in modalità pose remota.

Se PoseMode.Local invece viene usato o PoseMode.Passthrough , l'associazione grafica non verrà inizializzata con trame proxy offscreen e verrà usato un percorso rapido che usa la fotocamera principale della scena Unity per il rendering. Se il rispettivo caso d'uso richiede la modalità pose remota in fase di esecuzione, PoseMode.Remote deve essere specificato all'inizializzazione RemoteManagerUnity . Il rendering diretto con la fotocamera principale di Unity è più efficiente e può evitare problemi con altre estensioni unity. È quindi consigliabile usare il percorso di rendering non proxy.

Passaggi successivi