Omprojektion av sena steg
Late Stage Reprojection (LSR) är en maskinvarufunktion som hjälper till att stabilisera hologram när användaren rör sig.
Statiska modeller förväntas visuellt behålla sin position när du flyttar runt dem. Om de verkar vara instabila kan det här beteendet antyda LSR-problem. Tänk på att extra dynamiska transformeringar, till exempel animeringar eller explosionsvyer, kan maskera det här beteendet.
Du kan välja mellan två olika LSR-lägen, nämligen Planar LSR eller Depth LSR. Båda LSR-lägena förbättrar hologramstabiliteten, även om de har sina distinkta begränsningar. Börja med att prova Depth LSR, eftersom det förmodligen ger bättre resultat i de flesta fall.
Så här ställer du in LSR-läget
Vilket av LSR-lägena som används bestäms av om klientprogrammet skickar en djupbuffert. Om djupbufferten skickas använder den annars Djup LSR och Planar LSR .
Följande stycken förklarar hur du skickar in djupbufferten i Unity respektive interna program.
Unity
I Unity-redigeraren går du till File > Build Settings. Välj Player Settings längst ned till vänster och kontrollera Player > XR Settings > Virtual Reality SDKs > Windows Mixed Reality sedan om Enable Depth Buffer Sharing är markerat:
I så fall använder appen Djup-LSR, annars använder den Planar LSR.
När du använder OpenXR ska djupbufferten alltid skickas. Inställningen finns i XR Plug-in Management > OpenXR. Reprojection-läget kan sedan ändras via ett tillägg i OpenXR-plugin-programmet:
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);
}
}
}
}
Interna C++-program
Att skicka djupbufferten är helt under kontroll av den interna C++-bindningskoden, oberoende av WMR- eller OpenXR-versionen. Det enda villkor som måste uppfyllas är att en djupbuffert måste bindas till grafik-API:et vid den tidpunkt som GraphicsBinding::BlitRemoteFrame
anropas.
Djup LSR
För att djup-LSR ska fungera måste klientprogrammet tillhandahålla en giltig djupbuffert som innehåller all relevant geometri som ska beaktas under LSR.
Djup-LSR försöker stabilisera videoramen baserat på innehållet i den angivna djupbufferten. Därför kan innehåll som inte har renderats till det, till exempel transparenta objekt, inte justeras av LSR och kan visa instabilitet och reprojectionartefakter.
För att minska instabiliteten i reprojection för transparenta objekt kan du framtvinga djupbuffertskrivning. Se materialflaggan TransparencyWritesDepth för färg- och PBR-materialen. Observera dock att den visuella kvaliteten på transparent/ogenomskinlig objektinteraktion kan bli lidande när den här flaggan aktiveras.
Planar LSR
Planar LSR har inte djupinformation per pixel, som djup-LSR gör. I stället återskapas allt innehåll baserat på ett plan som du måste ange varje bildruta.
Planar LSR omprojects de objekt bäst som ligger nära det angivna planet. Ju längre bort ett objekt är, desto mer instabilt ser det ut. Även om Djup LSR är bättre på att återskapa objekt på olika djup, kan Planar LSR fungera bättre för innehåll som överensstämmer väl med ett plan.
Konfigurera Planar LSR i Unity
Planparametrarna härleds från en så kallad fokuspunkt. När du använder WMR måste fokuspunkten ställas in varje bildruta genom UnityEngine.XR.WSA.HolographicSettings.SetFocusPointForFrame
. Mer information finns i Api:et för Unity Focus Point. För OpenXR måste fokuspunkten anges via det ReprojectionSettings
som visas i föregående avsnitt.
Om du inte anger en fokuspunkt väljs en reserv för dig. Den automatiska återställningen leder dock ofta till suboptimala resultat.
Du kan beräkna fokuspunkten själv, även om det kan vara meningsfullt att basera den på den som beräknas av fjärrrenderingsvärden. Ring RemoteManagerUnity.CurrentSession.GraphicsBinding.GetRemoteFocusPoint
för att hämta det.
Vanligtvis renderar både klienten och värden innehåll som den andra sidan inte känner till, till exempel gränssnittselement på klienten. Därför kan det vara klokt att kombinera fjärrfokuspunkten med en lokalt beräknad.
Fokuspunkterna som beräknas i två efterföljande bildrutor kan variera mycket. Att bara använda dem som det är kan leda till att hologram verkar hoppa runt. För att förhindra det här beteendet rekommenderar vi att du interpolerar mellan de tidigare och aktuella fokuspunkterna.
Lägen för reprojection-pose
Det allmänna problemomfånget med hybridrendering kan anges så här: Fjärrinnehåll och lokalt innehåll ligger inom distinkta poser (dvs. koordinatutrymmen) eftersom fjärrpositionen förutsägs av servern medan den lokala posen är den faktiska aktuella. I slutet av en återgivningsram måste dock både fjärr- och lokalt innehåll justeras och föras till visningen. Följande bild visar ett exempel där lokala och fjärranslutna poser översätts jämfört med visningsvyporten:
Beroende på vilken GraphicsBinding
användning som används ger ARR upp till tre reprojectionlägen som fungerar ortogonalt till det LSR-läge som beskrivs ovan. Dessa lägen kallas Remote pose mode, Local pose modeoch Passthrough pose mode. Till skillnad från LSR-läget definierar poselägena hur fjärranslutet och lokalt innehåll kombineras. Valet av läget handlar med den visuella kvaliteten på lokalt innehåll för körningsprestanda, så program bör noggrant överväga vilket alternativ som är lämpligt. Se överväganden nedan.
Remote pose mode
Remote pose mode är standardläget i ARR. I det här läget återges det lokala innehållet ovanpå den inkommande fjärrbildströmmen med hjälp av fjärrställningen från fjärrramen. Sedan vidarebefordras det kombinerade resultatet till operativsystemet för den slutliga omprojektionen. Även om den här metoden endast använder en reprojection baseras den slutliga korrigeringen på tur- och returintervallet så att även det fullständiga omprojektionsfelet tillämpas på det lokala innehållet. Till följd av detta kan det stora korrigeringsdeltat leda till betydande snedvridningar av lokal geometri, inklusive gränssnittselement.
Med hjälp av bilden ovan tillämpas följande transformering i Remote pose mode:
Local pose mode
I det här läget delas omprojektionen upp i två distinkta steg: I det första steget återskapas fjärrinnehållet till det lokala poseutrymmet, dvs. det utrymme som det lokala innehållet återges med på VR/AR-enheter som standard. Därefter renderas det lokala innehållet ovanpå den här förkonfigurerade bilden med hjälp av den vanliga lokala posen. I det andra steget vidarebefordras det kombinerade resultatet till operativsystemet för den slutliga omprojektionen. Eftersom denna andra reprojection endast medför ett litet delta - i själva verket samma delta som skulle användas om ARR inte fanns - minimeras förvrängningsartefakterna på lokalt innehåll avsevärt.
Bilden ser därför ut så här:
Passthrough pose mode
Det här poseläget fungerar i stort sett på samma sätt som Remote pose mode, vilket innebär att det lokala och fjärranslutna innehållet kombineras i fjärranslutet utrymme. Innehållet kommer dock inte att återskapas efter kombination utan förbli i fjärranslutet poseutrymme. Den största fördelen med det här läget är att den resulterande bilden inte påverkas av reprojectionartefakter.
Konceptuellt kan det här läget jämföras med konventionella molnströmningsprogram. På grund av den höga svarstiden är den inte lämplig för huvudmonterade scenarier, men är ett genomförbart alternativ för Desktop och andra plattskärmsprogram där högre bildkvalitet önskas. Det är därför endast tillgängligt GraphicsBindingSimD3D11
för tillfället.
Prestanda- och kvalitetsöverväganden
Valet av poseläge har visuella kvalitets- och prestandakonsekvenser. Den extra körningskostnaden på klientsidan för att utföra den extra omprojektionen på Local pose mode en HoloLens 2-enhet uppgår till cirka 1 millisekunder per GPU-tid. Den här extra kostnaden måste beaktas om klientprogrammet redan ligger nära rambudgeten på 16 millisekunder. Å andra sidan finns det typer av program utan lokalt innehåll eller lokalt innehåll som inte är benägna att förvränga artefakter. I dessa fall Local pose mode får inte någon visuell fördel eftersom kvaliteten på fjärrinnehållet inte påverkas.
Det allmänna rådet skulle därför vara att testa lägena per användningsfall och se om vinsten i visuell kvalitet motiverar de extra prestandakostnaderna. Det är också möjligt att växla läget dynamiskt, till exempel aktivera lokalt läge endast när viktiga UIs visas.
Så här ändrar Pose mode du vid körning
Följande klient-API kan användas för att ändra läget vid körning:
RenderingSession session = ...;
session.GraphicsBinding.SetPoseMode(PoseMode.Local); // set local pose mode
ApiHandle<RenderingSession> session = ...;
session->GetGraphicsBinding()->SetPoseMode(PoseMode::Local); // set local pose mode
I allmänhet kan läget ändras när grafikbindningsobjektet är tillgängligt. Det finns en viktig skillnad för GraphicsBindingSimD3D11
: poseläget kan bara ändras till PoseMode.Remote
, om det har initierats med proxystrukturer. Om så inte är fallet kan attitydläget bara växlas mellan PoseMode.Local
och PoseMode.Passthrough
tills grafikbindningen initieras igen. Se de två överlagringarna av GraphicsBindingSimD3d11.InitSimulation
, som antingen tar inbyggda pekare till ID3D11Texture2D-objekt (proxysökväg) eller width
och height
för önskat användarvyport (icke-proxysökväg).
Överväganden för Desktop Unity-körning
På grund av GraphicsBindingSimD3D11
den tekniska bakgrunden och det faktum att rendering utanför skärmen fungerar i Unity kräver ARR Unity-körningen att användaren anger önskat poseläge vid start av RemoteManagerUnity
enligt följande:
public static void InitRemoteManager(Camera camera)
{
RemoteUnityClientInit clientInit = new RemoteUnityClientInit(camera, PoseMode.Remote);
RemoteManagerUnity.InitializeManager(clientInit);
}
Om PoseMode.Remote
anges initieras grafikbindningen med proxystrukturer utanför skärmen och all rendering omdirigeras från Unity-scenens huvudkamera till en proxykamera. Den här kodsökvägen rekommenderas endast för användning om körningspositionsläget ändras till PoseMode.Remote
krävs. Om inget poseläge anges väljer ARR Unity-körningen en lämplig standard beroende på den aktuella plattformen.
Varning
Omdirigeringen av proxykameran kan vara inkompatibel med andra Unity-tillägg, som förväntar sig att scenåtergivning ska ske med huvudkameran. Proxykameran kan hämtas via egenskapen om den RemoteManagerUnity.ProxyCamera
behöver frågas eller registreras någon annanstans. Mer specifikt för Cinemachine
plugin-programmet finns i den här felsökningsposten: Unity-plugin-programmet Cinemachine
fungerar inte i läget Fjärrposition.
Om PoseMode.Local
eller PoseMode.Passthrough
används i stället initieras inte grafikbindningen med proxystrukturer utanför skärmen, och en snabb sökväg som använder Unity-scenens huvudkamera för återgivning används. Om respektive användningsfall kräver fjärrpositionsläge vid körning PoseMode.Remote
, bör anges vid RemoteManagerUnity
initiering. Direktrendering med Unitys huvudkamera är effektivare och kan förhindra problem med andra Unity-tillägg. Därför rekommenderar vi att du använder sökvägen för icke-proxyrendering.