Reprojekcja na późnym etapie

Reprojection late stage (LSR) to funkcja sprzętowa, która pomaga ustabilizować hologramy podczas przemieszczania się użytkownika.

Modele statyczne powinny wizualnie utrzymywać swoją pozycję podczas poruszania się po nich. Jeśli wydają się być niestabilne, to zachowanie może wskazywać na problemy Z LSR. Należy pamiętać, że dodatkowe przekształcenia dynamiczne, takie jak animacje lub widoki eksplozji, mogą maskuje to zachowanie.

Można wybrać między dwoma różnymi trybami LSR, a mianowicie Planar LSR lub Depth LSR. Oba tryby LSR zwiększają stabilność hologramu, chociaż mają odrębne ograniczenia. Zacznij od próby głębokości LSR, ponieważ prawdopodobnie daje lepsze wyniki w większości przypadków.

Jak ustawić tryb LSR

Który z trybów LSR jest używany, określa, czy aplikacja kliencka przesyła bufor głębokości. Jeśli bufor głębokości jest przesyłany, w przeciwnym razie używa warstwy LSR głębokości i planuar LSR .

W poniższych akapitach wyjaśniono, jak przesyłanie buforu głębokości odbywa się odpowiednio w środowisku Unity i aplikacjach natywnych.

Unity

W edytorze aparatu Unity przejdź do strony File > Build Settings. Wybierz Player Settings w lewym dolnym rogu, a następnie sprawdź Player > XR Settings > Virtual Reality SDKs > Windows Mixed Reality , czy Enable Depth Buffer Sharing jest zaznaczone:

Depth Buffer Sharing Enabled flag

Jeśli tak jest, aplikacja będzie używać głębokości LSR, w przeciwnym razie użyje planar LSR.

W przypadku korzystania z biblioteki OpenXR bufor głębokości powinien być zawsze przesyłany. Ustawienie można znaleźć w pliku XR Plug-in Management > OpenXR. Tryb ponownego projektowania można następnie zmienić za pomocą rozszerzenia w wtyczki 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);
            }
        }
    }
}

Natywne aplikacje języka C++

Przesyłanie buforu głębokości jest w pełni pod kontrolą natywnego kodu powiązania języka C++, niezależnie od wersji WMR lub OpenXR. Jedynym warunkiem, który należy spełnić, jest to, że w momencie wywoływania GraphicsBinding::BlitRemoteFrame bufor głębokości musi być powiązany z interfejsem API grafiki.

Głębokość LSR

Aby funkcja LSR głębokości działała, aplikacja kliencka musi podać prawidłowy bufor głębokości zawierający całą odpowiednią geometrię do rozważenia podczas LSR.

Głębokość LSR próbuje ustabilizować ramkę wideo na podstawie zawartości dostarczonego buforu głębokości. W związku z tym zawartość, która nie została do niej renderowana, na przykład przezroczyste obiekty, nie może być dostosowana przez LSR i może pokazywać niestabilność i artefakty ponownego projektu.

Aby wyeliminować niestabilność projektu dla obiektów przezroczystych, możesz wymusić zapisywanie buforu głębokości. Zobacz flagę materiału TransparencyWritesDepth dla materiałów Color i PBR . Należy jednak pamiętać, że jakość wizualizacji przezroczystej/nieprzezroczystej interakcji z obiektem może wystąpić podczas włączania tej flagi.

Planar LSR

Planar LSR nie ma informacji o głębokości na piksel, ponieważ głębokość LSR nie jest. Zamiast tego ponownie projektuje całą zawartość na podstawie płaszczyzny, którą należy podać dla każdej ramki.

Planar LSR reprojektuje te obiekty najlepiej, które leżą blisko dostarczonej płaszczyzny. Dalej obiekt jest, tym bardziej niestabilny będzie wyglądać. Podczas gdy funkcja LSR głębokości jest lepsza w reprojektowaniu obiektów o różnych głębokościach, planar LSR może działać lepiej w przypadku zawartości dobrze dopasowanej do płaszczyzny.

Konfigurowanie planar LSR w a środowisku Unity

Parametry płaszczyzny pochodzą z tak zwanego punktu koncentracji uwagi. W przypadku korzystania z usługi WMR punkt koncentracji uwagi musi być ustawiany przez UnityEngine.XR.WSA.HolographicSettings.SetFocusPointForFrameelement . Aby uzyskać szczegółowe informacje, zobacz interfejs API punktu koncentracji uwagi aparatu Unity. W przypadku biblioteki OpenXR punkt koncentracji uwagi należy ustawić za pośrednictwem elementu pokazanego ReprojectionSettings w poprzedniej sekcji. Jeśli nie ustawisz punktu koncentracji uwagi, zostanie wybrana rezerwa. Jednak automatyczne rezerwowe często prowadzi do nieoptymalnych wyników.

Możesz samodzielnie obliczyć punkt koncentracji uwagi, choć warto go obliczyć na podstawie tego, który jest obliczany przez hosta usługi Remote Rendering. Zadzwoń RemoteManagerUnity.CurrentSession.GraphicsBinding.GetRemoteFocusPoint , aby to uzyskać.

Zazwyczaj zarówno klient, jak i host renderuje zawartość, o których druga strona nie jest świadoma, takich jak elementy interfejsu użytkownika na kliencie. W związku z tym warto połączyć zdalny punkt koncentracji uwagi z lokalnie obliczonym punktem.

Punkty fokusu obliczane w dwóch kolejnych ramkach mogą się znacznie różnić. Po prostu używanie ich w stanie as-is może prowadzić do hologramów wydaje się skakać. Aby zapobiec temu zachowaniu, interpolacja między poprzednimi i bieżącymi punktami koncentracji uwagi jest zalecana.

Tryby ponownego projektu

Ogólny zakres problemu z renderowaniem hybrydowym można określić w następujący sposób: Zawartość zdalna i lokalna znajdują się w odrębnych pozycjach (czyli współrzędnych), ponieważ zdalne położenie jest przewidywane przez serwer, podczas gdy pozycja lokalna jest rzeczywistą bieżącą. Jednak na końcu ramki renderowania zarówno zawartość zdalna, jak i lokalna musi być wyrównana i przeniesiona do wyświetlacza. Na poniższej ilustracji przedstawiono przykład, w którym lokalne i zdalne pozy są tłumaczone w porównaniu z widokiem wyświetlania:

Diagram that illustrates remote and local pose in relation to target viewport.

W zależności od używanego GraphicsBinding trybu ARR zapewnia maksymalnie trzy tryby ponownego projektowania, które działają ortogonalnie do trybu LSR omówionego powyżej. Te tryby są określane jako Remote pose mode, Local pose modei Passthrough pose mode. W przeciwieństwie do trybu LSR tryby pozy definiują sposób łączenia zawartości zdalnej i lokalnej. Wybór trybu wymienia wizualną jakość lokalnej zawartości pod kątem wydajności środowiska uruchomieniowego, dlatego aplikacje powinny dokładnie rozważyć, która opcja jest odpowiednia. Zapoznaj się z poniższymi zagadnieniami.

Remote pose mode

Remote pose mode jest trybem domyślnym w usłudze ARR. W tym trybie zawartość lokalna jest renderowana na podstawie przychodzącego strumienia obrazu zdalnego przy użyciu zdalnego pozy z ramki zdalnej. Następnie połączony wynik jest przekazywany do systemu operacyjnego na potrzeby ostatniego ponownego projektu. Chociaż to podejście używa tylko jednego ponownego projektu, ostateczna korekta jest oparta na interwale rundy, więc pełny błąd ponownego projektu jest również stosowany do zawartości lokalnej. W konsekwencji duża delta korekty może spowodować znaczne zakłócenia geometrii lokalnej, w tym elementów interfejsu użytkownika.

Na powyższej ilustracji zastosowano następującą transformację w pliku Remote pose mode:

Reprojection steps in remote pose mode.

Local pose mode

W tym trybie reprojektacja jest podzielona na dwa odrębne kroki: w pierwszym kroku zawartość zdalna jest ponownie projektowana na lokalną przestrzeń pozy, czyli przestrzeń, z którą jest renderowana lokalna zawartość na urządzeniach VR/AR. Następnie zawartość lokalna jest renderowana na podstawie tego wstępnie przekształconego obrazu przy użyciu zwykłego lokalnego pozy. W drugim kroku połączony wynik jest przekazywany do systemu operacyjnego na potrzeby ostatniego ponownego projektu. Ponieważ ten drugi ponowny projekt wiąże się tylko z małą różnicą — w rzeczywistości ta sama delta, która byłaby używana, jeśli ARR nie była obecna — artefakty zniekształcenia zawartości lokalnej są znacznie ograniczane.

W związku z tym ilustracja wygląda następująco:

Reprojection steps in local pose mode.

Passthrough pose mode

Ten tryb pozy zachowuje się zasadniczo tak samo jak Remote pose mode, co oznacza, że zawartość lokalna i zdalna są łączone w przestrzeni zdalnej. Jednak zawartość nie zostanie ponownie utworzona po połączeniu, ale pozostanie w zdalnej przestrzeni. Główną zaletą tego trybu jest to, że wynikowy obraz nie będzie miał wpływu na artefakty ponownego projektowania.

Koncepcyjnie ten tryb można porównać z konwencjonalnymi aplikacjami do przesyłania strumieniowego w chmurze. Ze względu na duże opóźnienia, jakie powoduje, nie jest odpowiednia dla scenariuszy zamontowanych na głowie, ale jest to realna alternatywa dla aplikacji klasycznych i innych aplikacji z płaskim ekranem, w których wymagana jest wyższa jakość obrazu. W związku z tym jest on dostępny GraphicsBindingSimD3D11 tylko na razie.

Zagadnienia dotyczące wydajności i jakości

Wybór trybu pozy ma wpływ na jakość wizualizacji i wydajność. Dodatkowy koszt środowiska uruchomieniowego po stronie klienta do wykonania dodatkowego ponownego projektu w Local pose mode urządzeniu HoloLens 2 wynosi około 1 milisekund na ramę czasu procesora GPU. Ten dodatkowy koszt należy wziąć pod uwagę, jeśli aplikacja kliencka jest już blisko budżetu ramowego 16 milisekund. Z drugiej strony istnieją typy aplikacji bez lokalnej zawartości lub zawartości lokalnej, które nie są podatne na zniekształcenia artefaktów. W takich przypadkach Local pose mode nie zyskuje żadnej korzyści wizualnej, ponieważ nie ma to wpływu na jakość ponownego projektu zawartości zdalnej.

Ogólnie rzecz biorąc, należy zatem przetestować tryby na podstawie przypadku użycia i sprawdzić, czy wzrost jakości wizualizacji uzasadnia dodatkowe obciążenie związane z wydajnością. Można również dynamicznie przełączać tryb, na przykład włączyć tryb lokalny tylko wtedy, gdy są wyświetlane ważne interfejsy użytkownika.

Jak zmienić środowisko Pose mode uruchomieniowe

Do zmiany trybu w czasie wykonywania można użyć następującego interfejsu API klienta:

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

Ogólnie rzecz biorąc, tryb można zmienić za każdym razem, gdy obiekt powiązania grafiki jest dostępny. Istnieje ważne rozróżnienie: GraphicsBindingSimD3D11tryb pozy można zmienić tylko na PoseMode.Remote, jeśli został zainicjowany za pomocą tekstur serwera proxy. Jeśli tak nie jest, tryb pozy może być przełączany tylko między PoseMode.Local i PoseMode.Passthrough do momentu ponownego zainicjowania powiązania grafiki. Zobacz dwa przeciążenia GraphicsBindingSimD3d11.InitSimulationelementu , które przyjmują wskaźniki natywne do obiektów ID3D11Texture2D (ścieżka serwera proxy) lub width i height żądanego widoku użytkownika (ścieżka innego niż proxy).

Zagadnienia dotyczące środowiska uruchomieniowego aparatu Unity w programie Desktop

Ze względu na techniczne tło GraphicsBindingSimD3D11 i fakt działania renderowania offscreen w środowisku Unity środowisko uruchomieniowe ARR Unity wymaga od użytkownika określenia żądanego trybu pozowania podczas uruchamiania w RemoteManagerUnity następujący sposób:

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

Jeśli PoseMode.Remote zostanie określona, powiązanie grafiki zostanie zainicjowane z teksturami serwera proxy poza ekranem, a wszystkie renderowanie zostanie przekierowane z głównego aparatu sceny aparatu Unity do aparatu proxy. Ta ścieżka kodu jest zalecana tylko w przypadku użycia, jeśli wymagane są zmiany PoseMode.Remote trybu wykonywania. Jeśli nie określono trybu pozowania, środowisko uruchomieniowe ARR Unity wybierze odpowiednią wartość domyślną w zależności od bieżącej platformy.

Ostrzeżenie

Przekierowanie aparatu proxy może być niezgodne z innymi rozszerzeniami aparatu Unity, które oczekują, że renderowanie sceny odbędzie się z aparatem głównym. Aparat proxy można pobrać za pośrednictwem RemoteManagerUnity.ProxyCamera właściwości, jeśli musi być odpytywane lub zarejestrowane w innym miejscu. W szczególności w przypadku Cinemachine wtyczki zapoznaj się z tym wpisem rozwiązywania problemów: Wtyczka aparatu Unity Cinemachine nie działa w trybie zdalnego pozowania.

Jeśli PoseMode.Local zamiast tego jest używane lub PoseMode.Passthrough jest używane, powiązanie grafiki nie zostanie zainicjowane z teksturami serwera proxy poza ekranem, a zostanie użyta szybka ścieżka przy użyciu głównego aparatu sceny aparatu Unity do renderowania. Jeśli odpowiedni przypadek użycia wymaga zdalnego trybu pozowania w czasie wykonywania, PoseMode.Remote należy określić podczas RemoteManagerUnity inicjowania. Bezpośrednie renderowanie za pomocą głównego aparatu Unity jest bardziej wydajne i może zapobiegać problemom z innymi rozszerzeniami aparatu Unity. W związku z tym zaleca się użycie ścieżki renderowania innej niż serwer proxy.

Następne kroki