Delen via


Grafische binding

Als u Azure Remote Rendering in een aangepaste toepassing wilt kunnen gebruiken, moet deze worden geïntegreerd in de renderingpijplijn van de toepassing. Deze integratie is de verantwoordelijkheid van de grafische binding.

Zodra de grafische binding is ingesteld, krijgt u toegang tot verschillende functies die van invloed zijn op de weergegeven afbeelding. Deze functies kunnen worden onderverdeeld in twee categorieën: algemene functies die altijd beschikbaar zijn en specifieke functies die alleen relevant zijn voor de geselecteerde Microsoft.Azure.RemoteRendering.GraphicsApiTypefuncties.

Grafische binding in Unity

In Unity wordt de volledige binding verwerkt door de RemoteUnityClientInit struct die wordt doorgegeven aan RemoteManagerUnity.InitializeManager. Als u de grafische modus wilt instellen, moet het GraphicsApiType veld worden ingesteld op de gekozen binding. Het veld wordt automatisch ingevuld, afhankelijk van of er een XRDevice aanwezig is. Het gedrag kan handmatig worden overschreven met het volgende gedrag:

  • HoloLens 2: de OpenXR - of windows Mixed Reality-grafische binding wordt gebruikt, afhankelijk van de actieve Unity XR-invoegtoepassing.
  • Platte UWP-desktop-app: Simulatie wordt altijd gebruikt.
  • Unity-editor: Simulatie wordt altijd gebruikt, tenzij een WMR VR-headset is aangesloten. In dat geval wordt ARR uitgeschakeld om fouten op te sporen in de niet-ARR-gerelateerde onderdelen van de toepassing. Zie ook holografische externe communicatie.

Het enige andere relevante onderdeel voor Unity is toegang tot de basisbinding. Alle andere secties hieronder kunnen worden overgeslagen.

Grafische binding instellen in aangepaste toepassingen

Voer de volgende twee stappen uit om een grafische binding te selecteren: Eerst moet de grafische binding statisch worden geïnitialiseerd wanneer het programma wordt geïnitialiseerd:

RemoteRenderingInitialization managerInit = new RemoteRenderingInitialization();
managerInit.GraphicsApi = GraphicsApiType.OpenXrD3D11;
managerInit.ConnectionType = ConnectionType.General;
managerInit.Right = ///...
RemoteManagerStatic.StartupRemoteRendering(managerInit);
RemoteRenderingInitialization managerInit;
managerInit.GraphicsApi = GraphicsApiType::OpenXrD3D11;
managerInit.ConnectionType = ConnectionType::General;
managerInit.Right = ///...
StartupRemoteRendering(managerInit); // static function in namespace Microsoft::Azure::RemoteRendering

De bovenstaande aanroep moet worden aangeroepen voordat andere Remote Rendering-API's worden geopend. Op dezelfde manier moet de bijbehorende de-init-functie RemoteManagerStatic.ShutdownRemoteRendering(); worden aangeroepen nadat alle andere Remote Rendering-objecten al zijn vernietigd. Voor WMR StartupRemoteRendering moet ook worden aangeroepen voordat een holografische API wordt aangeroepen. Voor OpenXR geldt hetzelfde voor alle OpenXR-gerelateerde API's.

Toegang tot grafische binding

Zodra een client is ingesteld, kan de eenvoudige grafische binding worden geopend met de RenderingSession.GraphicsBinding getter. Als voorbeeld kunnen de laatste framestatistieken als volgt worden opgehaald:

RenderingSession currentSession = ...;
if (currentSession.GraphicsBinding != null)
{
    FrameStatistics frameStatistics;
    if (currentSession.GraphicsBinding.GetLastFrameStatistics(out frameStatistics) == Result.Success)
    {
        ...
    }
}
ApiHandle<RenderingSession> currentSession = ...;
if (ApiHandle<GraphicsBinding> binding = currentSession->GetGraphicsBinding())
{
    FrameStatistics frameStatistics;
    if (binding->GetLastFrameStatistics(&frameStatistics) == Result::Success)
    {
        ...
    }
}

Grafische API's

Er zijn momenteel drie grafische API's die kunnen worden geselecteerd, OpenXrD3D11WmrD3D11 en SimD3D11. Er bestaat nog een vierde Headless , maar wordt nog niet ondersteund aan de clientzijde.

OpenXR

GraphicsApiType.OpenXrD3D11 is de standaardbinding die moet worden uitgevoerd op HoloLens 2. Hiermee wordt de GraphicsBindingOpenXrD3d11 binding gemaakt. In deze modus maakt Azure Remote Rendering een OpenXR API-laag om zichzelf te integreren in de OpenXR-runtime.

Voor toegang tot de afgeleide grafische bindingen moet de basis GraphicsBinding worden gecast. Er zijn drie dingen die moeten worden gedaan om de OpenXR-binding te gebruiken:

Aangepaste JSON-laag van OpenXR-pakket

Als u Remote Rendering wilt gebruiken met OpenXR, moet de aangepaste OpenXR API-laag worden geactiveerd. Dit wordt gedaan door het aanroepen StartupRemoteRendering in de vorige sectie. Als vereiste moet de XrApiLayer_msft_holographic_remoting.json toepassing echter worden verpakt, zodat deze kan worden geladen. Dit wordt automatisch gedaan als het NuGet-pakket Microsoft.Azure.RemoteRendering.Cpp wordt toegevoegd aan een project.

Remote Rendering informeren over de gebruikte XR-ruimte

Dit is nodig om externe en lokaal gerenderde inhoud uit te lijnen.

RenderingSession currentSession = ...;
ulong space = ...; // XrSpace cast to ulong
GraphicsBindingOpenXrD3d11 openXrBinding = (currentSession.GraphicsBinding as GraphicsBindingOpenXrD3d11);
if (openXrBinding.UpdateAppSpace(space) == Result.Success)
{
    ...
}
ApiHandle<RenderingSession> currentSession = ...;
XrSpace space = ...;
ApiHandle<GraphicsBindingOpenXrD3d11> openXrBinding = currentSession->GetGraphicsBinding().as<GraphicsBindingOpenXrD3d11>();
#ifdef _M_ARM64
    if (openXrBinding->UpdateAppSpace(reinterpret_cast<uint64_t>(space)) == Result::Success)
#else
    if (openXrBinding->UpdateAppSpace(space) == Result::Success)
#endif
{
    ...
}

Wanneer het bovenstaande XrSpace wordt gebruikt door de toepassing die het wereldcoördinaatsysteem voor ruimte definieert waarin coördinaten in de API worden uitgedrukt.

Externe afbeelding weergeven (OpenXR)

Aan het begin van elk frame moet het externe frame in de achterbuffer worden weergegeven. Dit wordt gedaan door het aanroepen BlitRemoteFramevan zowel kleur- als dieptegegevens voor beide ogen in het huidige afhankelijke renderdoel. Het is dus belangrijk dat u dit doet nadat u de volledige backbuffer als renderdoel hebt gekoppeld.

Waarschuwing

Nadat de externe afbeelding in de backbuffer is belicht, moet de lokale inhoud worden weergegeven met behulp van een stereorenderingstechniek met één pass, bijvoorbeeld met behulp van SV_RenderTargetArrayIndex. Het gebruik van andere stereorenderingstechnieken, zoals het weergeven van elk oog in een afzonderlijke pas, kan leiden tot grote prestatievermindering of grafische artefacten en moet worden vermeden.

RenderingSession currentSession = ...;
GraphicsBindingOpenXrD3d11 openXrBinding = (currentSession.GraphicsBinding as GraphicsBindingOpenXrD3d11);
openXrBinding.BlitRemoteFrame();
ApiHandle<RenderingSession> currentSession = ...;
ApiHandle<GraphicsBindingOpenXrD3d11> openXrBinding = currentSession->GetGraphicsBinding().as<GraphicsBindingOpenXrD3d11>();
openXrBinding->BlitRemoteFrame();

Windows Mixed Reality

GraphicsApiType.WmrD3D11 is de eerder gebruikte grafische binding die moet worden uitgevoerd op HoloLens 2. Hiermee wordt de GraphicsBindingWmrD3d11 binding gemaakt. In deze modus wordt Azure Remote Rendering rechtstreeks aan de holografische API's gekoppeld.

Voor toegang tot de afgeleide grafische bindingen moet de basis GraphicsBinding worden gecast. Er zijn twee dingen die moeten worden gedaan om de WMR-binding te gebruiken:

Remote Rendering informeren over het gebruikte coördinaatsysteem

Dit is nodig om externe en lokaal gerenderde inhoud uit te lijnen.

RenderingSession currentSession = ...;
IntPtr ptr = ...; // native pointer to ISpatialCoordinateSystem
GraphicsBindingWmrD3d11 wmrBinding = (currentSession.GraphicsBinding as GraphicsBindingWmrD3d11);
if (wmrBinding.UpdateUserCoordinateSystem(ptr) == Result.Success)
{
    ...
}
ApiHandle<RenderingSession> currentSession = ...;
void* ptr = ...; // native pointer to ISpatialCoordinateSystem
ApiHandle<GraphicsBindingWmrD3d11> wmrBinding = currentSession->GetGraphicsBinding().as<GraphicsBindingWmrD3d11>();
if (wmrBinding->UpdateUserCoordinateSystem(ptr) == Result::Success)
{
    ...
}

Waar het bovenstaande ptr een aanwijzer moet zijn naar een systeemeigen ABI::Windows::Perception::Spatial::ISpatialCoordinateSystem object dat het wereldcoördinaatsysteem voor ruimtecoördinaten definieert waarin coördinaten in de API worden uitgedrukt.

Externe afbeelding weergeven (WMR)

Dezelfde overwegingen als in de bovenstaande OpenXR-case zijn hier van toepassing. De API-aanroepen zien er als volgt uit:

RenderingSession currentSession = ...;
GraphicsBindingWmrD3d11 wmrBinding = (currentSession.GraphicsBinding as GraphicsBindingWmrD3d11);
wmrBinding.BlitRemoteFrame();
ApiHandle<RenderingSession> currentSession = ...;
ApiHandle<GraphicsBindingWmrD3d11> wmrBinding = currentSession->GetGraphicsBinding().as<GraphicsBindingWmrD3d11>();
wmrBinding->BlitRemoteFrame();

Simulatie

GraphicsApiType.SimD3D11 is de simulatiebinding en als deze is geselecteerd, wordt de GraphicsBindingSimD3d11 grafische binding gemaakt. Deze interface wordt gebruikt om hoofdbewegingen te simuleren, bijvoorbeeld in een bureaubladtoepassing en geeft een monoscopische afbeelding weer.

Als u de simulatiebinding wilt implementeren, is het belangrijk om het verschil tussen de lokale camera en het externe frame te begrijpen, zoals beschreven op de camerapagina .

Er zijn twee camera's nodig:

  • Lokale camera: Deze camera vertegenwoordigt de huidige camerapositie die wordt aangestuurd door de toepassingslogica.
  • Proxycamera: deze camera komt overeen met het huidige externe frame dat is verzonden door de server. Omdat er een tijdsvertraging is tussen de klant die een frame aanvraagt en de aankomst ervan, bevindt het Remote Frame zich altijd een beetje achter de beweging van de lokale camera.

De basisbenadering hier is dat zowel de externe afbeelding als de lokale inhoud worden weergegeven in een doel buiten het scherm met behulp van de proxycamera. De proxy-afbeelding wordt vervolgens opnieuw geprojecteerd naar de lokale cameraruimte, wat verder wordt uitgelegd in nieuwe projecten in de late fase.

GraphicsApiType.SimD3D11 ondersteunt ook stereoscopische rendering, die moet worden ingeschakeld tijdens de InitSimulation onderstaande installatieoproep. De installatie is wat meer betrokken en werkt als volgt:

Proxy-renderdoel maken

Externe en lokale inhoud moet worden weergegeven op een offscreenkleur/diepteweergavedoel met de naam Proxy met behulp van de proxycameragegevens die door de GraphicsBindingSimD3d11.Update functie worden geleverd.

De proxy moet overeenkomen met de resolutie van de backbuffer en moet de DXGI_FORMAT_R8G8B8A8_UNORM - of DXGI_FORMAT_B8G8R8A8_UNORM-indeling hebben. In het geval van stereoscopische rendering moeten zowel het patroon van de kleurproxy als, als de diepte van de proxy wordt gebruikt, twee matrixlagen hebben in plaats van één. Zodra een sessie gereed is, GraphicsBindingSimD3d11.InitSimulation moet u worden aangeroepen voordat u er verbinding mee maakt:

RenderingSession currentSession = ...;
IntPtr d3dDevice = ...; // native pointer to ID3D11Device
IntPtr color = ...; // native pointer to ID3D11Texture2D
IntPtr depth = ...; // native pointer to ID3D11Texture2D
float refreshRate = 60.0f; // Monitor refresh rate up to 60hz.
bool flipBlitRemoteFrameTextureVertically = false;
bool flipReprojectTextureVertically = false;
bool stereoscopicRendering = false;
GraphicsBindingSimD3d11 simBinding = (currentSession.GraphicsBinding as GraphicsBindingSimD3d11);
simBinding.InitSimulation(d3dDevice, depth, color, refreshRate, flipBlitRemoteFrameTextureVertically, flipReprojectTextureVertically, stereoscopicRendering);
ApiHandle<RenderingSession> currentSession = ...;
void* d3dDevice = ...; // native pointer to ID3D11Device
void* color = ...; // native pointer to ID3D11Texture2D
void* depth = ...; // native pointer to ID3D11Texture2D
float refreshRate = 60.0f; // Monitor refresh rate up to 60hz.
bool flipBlitRemoteFrameTextureVertically = false;
bool flipReprojectTextureVertically = false;
bool stereoscopicRendering = false;
ApiHandle<GraphicsBindingSimD3d11> simBinding = currentSession->GetGraphicsBinding().as<GraphicsBindingSimD3d11>();
simBinding->InitSimulation(d3dDevice, depth, color, refreshRate, flipBlitRemoteFrameTextureVertically, flipReprojectTextureVertically, stereoscopicRendering);

De init-functie moet worden voorzien van aanwijzers naar het systeemeigen d3d-apparaat, evenals de kleur en dieptepatroon van het proxy-renderdoel. Eenmaal geïnitialiseerd RenderingSession.ConnectAsync en Disconnect meerdere keren kan worden aangeroepen, maar wanneer u overschakelt naar een andere sessie, GraphicsBindingSimD3d11.DeinitSimulation moet u eerst op de oude sessie worden aangeroepen voordat GraphicsBindingSimD3d11.InitSimulation u een andere sessie kunt aangeroepen.

Render-lusupdate

De render-lusupdate bestaat uit meerdere stappen:

  1. Elk frame, voordat een rendering plaatsvindt, GraphicsBindingSimD3d11.Update wordt aangeroepen met de huidige cameratransformatie die naar de server wordt verzonden om te worden weergegeven. Tegelijkertijd moet de geretourneerde proxytransformatie worden toegepast op de proxycamera om deze weer te geven in het proxy-renderdoel. Als de geretourneerde proxy-update SimulationUpdate.frameId null is, zijn er nog geen externe gegevens. In dit geval moet in plaats van in het proxy-renderdoel alle lokale inhoud rechtstreeks met behulp van de huidige cameragegevens naar de achterbuffer worden weergegeven en worden de volgende twee stappen overgeslagen.
  2. De toepassing moet nu het proxy-renderdoel binden en aanroepen GraphicsBindingSimD3d11.BlitRemoteFrameToProxy. Hiermee vult u de externe kleur en dieptegegevens in het proxy-renderdoel. Elke lokale inhoud kan nu worden weergegeven op de proxy met behulp van de proxycameratransformatie.
  3. Vervolgens moet de backbuffer worden gebonden als een renderdoel en GraphicsBindingSimD3d11.ReprojectProxy aangeroepen waarop de backbuffer kan worden weergegeven.
RenderingSession currentSession = ...;
GraphicsBindingSimD3d11 simBinding = (currentSession.GraphicsBinding as GraphicsBindingSimD3d11);
SimulationUpdateParameters updateParameters = new SimulationUpdateParameters();
// Fill out camera data with current camera data
// (see "Simulation Update structures" section below)
...
SimulationUpdateResult updateResult = new SimulationUpdateResult();
simBinding.Update(updateParameters, out updateResult);
// Is the frame data valid?
if (updateResult.FrameId != 0)
{
    // Bind proxy render target
    simBinding.BlitRemoteFrameToProxy();
    // Use proxy camera data to render local content
    ...
    // Bind back buffer
    simBinding.ReprojectProxy();
}
else
{
    // Bind back buffer
    // Use current camera data to render local content
    ...
}
ApiHandle<RenderingSession> currentSession;
ApiHandle<GraphicsBindingSimD3d11> simBinding = currentSession->GetGraphicsBinding().as<GraphicsBindingSimD3d11>();

SimulationUpdateParameters updateParameters;
// Fill out camera data with current camera data
// (see "Simulation Update structures" section below)
...
SimulationUpdateResult updateResult;
simBinding->Update(updateParameters, &updateResult);
// Is the frame data valid?
if (updateResult.FrameId != 0)
{
    // Bind proxy render target
    simBinding->BlitRemoteFrameToProxy();
    // Use proxy camera data to render local content
    ...
    // Bind back buffer
    simBinding->ReprojectProxy();
}
else
{
    // Bind back buffer
    // Use current camera data to render local content
    ...
}

Simulatie-updatestructuren

Elk frame, de Render-lus van de vorige sectie vereist dat u een reeks cameraparameters invoert die overeenkomen met de lokale camera en retourneert een set cameraparameters die overeenkomen met de volgende beschikbare camera van het frame. Deze twee sets worden vastgelegd in respectievelijk de SimulationUpdateParameters SimulationUpdateResult structuren:

public struct SimulationUpdateParameters
{
    public int FrameId;
    public StereoMatrix4x4 ViewTransform;
    public StereoCameraFov FieldOfView;
};

public struct SimulationUpdateResult
{
    public int FrameId;
    public float NearPlaneDistance;
    public float FarPlaneDistance;
    public StereoMatrix4x4 ViewTransform;
    public StereoCameraFov FieldOfView;
};

De structuurleden hebben de volgende betekenis:

Lid Beschrijving
FrameId Continue frame-id. Vereist voor input van SimulationUpdateParameters en moet continu worden verhoogd voor elk nieuw frame. Is 0 in SimulationUpdateResult als er nog geen framegegevens beschikbaar zijn.
ViewTransform Links-rechts-stereopaar van de cameraweergave transformatie matrices van het frame. Voor monoscopische weergave is alleen het Left lid geldig.
FieldOfView Links-rechts-stereopaar van de beeldvelden van de framecamera in het veld van de weergaveconventie van OpenXR. Voor monoscopische weergave is alleen het Left lid geldig.
NearPlaneDistance afstand in de buurt die wordt gebruikt voor de projectiematrix van het huidige externe frame.
FarPlaneDistance vervlakafstand die wordt gebruikt voor de projectiematrix van het huidige externe frame.

De stereoparen ViewTransform en FieldOfView toestaan beide waarden voor de ogen camera in te stellen voor het geval stereoscopische rendering is ingeschakeld. Anders worden de Right leden genegeerd. Zoals u ziet, wordt alleen de transformatie van de camera doorgegeven als gewone 4x4 transformatiematrices, terwijl er geen projectiematrices zijn opgegeven. De werkelijke matrices worden intern berekend door Azure Remote Rendering met behulp van de opgegeven weergavevelden en het huidige vlak vlak en vervlak dat is ingesteld op de Camera Instellingen-API.

Aangezien u het near-plane en far-plane op de Camera kunt wijzigen Instellingen tijdens runtime naar wens en de service deze instellingen asynchroon toepast, draagt elke SimulationUpdateResult ook het specifieke vlak en verre vlak dat wordt gebruikt tijdens het weergeven van het bijbehorende frame. U kunt deze vlakwaarden gebruiken om uw projectiematrices aan te passen voor het weergeven van lokale objecten zodat deze overeenkomen met de externe frameweergave.

Ten slotte kunt u, terwijl voor de aanroep Simulatie-update het veld-van-weergave in de OpenXR-conventie is vereist, om standaardisatie en algoritmen veiligheidsredenen worden gebruikt, kunt u gebruikmaken van de conversiefuncties die worden geïllustreerd in de volgende voorbeelden van de structuurpopulatie:

public SimulationUpdateParameters CreateSimulationUpdateParameters(int frameId, Matrix4x4 viewTransform, Matrix4x4 projectionMatrix)
{
    SimulationUpdateParameters parameters = default;
    parameters.FrameId = frameId;
    parameters.ViewTransform.Left = viewTransform;
    if (parameters.FieldOfView.Left.FromProjectionMatrix(projectionMatrix) != Result.Success)
    {
        // Invalid projection matrix
        throw new ArgumentException("Invalid projection settings");
    }
    return parameters;
}

public void GetCameraSettingsFromSimulationUpdateResult(SimulationUpdateResult result, out Matrix4x4 projectionMatrix, out Matrix4x4 viewTransform, out int frameId)
{
    projectionMatrix = default;
    viewTransform = default;
    frameId = 0;

    if (result.FrameId == 0)
    {
        // Invalid frame data
        return;
    }

    // Use the screenspace depth convention you expect for your projection matrix locally
    if (result.FieldOfView.Left.ToProjectionMatrix(result.NearPlaneDistance, result.FarPlaneDistance, DepthConvention.ZeroToOne, out projectionMatrix) != Result.Success)
    {
        // Invalid field-of-view
        return;
    }
    viewTransform = result.ViewTransform.Left;
    frameId = result.FrameId;
}
SimulationUpdateParameters CreateSimulationUpdateParameters(uint32_t frameId, Matrix4x4 viewTransform, Matrix4x4 projectionMatrix)
{
    SimulationUpdateParameters parameters;
    parameters.FrameId = frameId;
    parameters.ViewTransform.Left = viewTransform;
    if (FovFromProjectionMatrix(projectionMatrix, parameters.FieldOfView.Left) != Result::Success)
    {
        // Invalid projection matrix
        return {};
    }
    return parameters;
}

void GetCameraSettingsFromSimulationUpdateResult(const SimulationUpdateResult& result, Matrix4x4& projectionMatrix, Matrix4x4& viewTransform, uint32_t& frameId)
{
    if (result.FrameId == 0)
    {
        // Invalid frame data
        return;
    }

    // Use the screenspace depth convention you expect for your projection matrix locally
    if (FovToProjectionMatrix(result.FieldOfView.Left, result.NearPlaneDistance, result.FarPlaneDistance, DepthConvention::ZeroToOne, projectionMatrix) != Result::Success)
    {
        // Invalid field-of-view
        return;
    }
    viewTransform = result.ViewTransform.Left;
    frameId = result.FrameId;
}

Met deze conversiefuncties kunt u snel schakelen tussen de specificatie voor velden en een eenvoudige projectiematrix met 4x4 perspectieven, afhankelijk van uw behoeften voor lokale rendering. Deze conversiefuncties bevatten verificatielogica en retourneren fouten, zonder een geldig resultaat in te stellen, voor het geval de invoerprojectiematrices of invoervelden ongeldig zijn.

API-documentatie

Volgende stappen