Rendering in DirectX

Notitie

Dit artikel heeft betrekking op de verouderde systeemeigen WinRT-API's. Voor nieuwe systeemeigen app-projecten raden we u aan de OpenXR-API te gebruiken.

Windows Mixed Reality is gebouwd op DirectX om rijke, 3D-grafische ervaringen voor gebruikers te produceren. De renderingabstractie bevindt zich net boven DirectX, waardoor apps kunnen redeneren over de positie en oriëntatie van holografische scène-waarnemers die door het systeem worden voorspeld. De ontwikkelaar kan vervolgens zijn hologrammen vinden op basis van elke camera, zodat de app deze hologrammen in verschillende ruimtelijke coördinatensystemen kan weergeven terwijl de gebruiker zich verplaatst.

Opmerking: in dit scenario wordt holografische rendering in Direct3D 11 beschreven. Een Direct3D 12 Windows Mixed Reality app-sjabloon wordt ook geleverd bij de extensie Mixed Reality app-sjablonen.

Update voor het huidige frame

Als u de toepassingsstatus voor hologrammen wilt bijwerken, doet de app het volgende:

  • Haal een HolographicFrame op uit het weergavebeheersysteem.
  • Werk de scène bij met de huidige voorspelling van waar de cameraweergave zich bevindt wanneer de weergave is voltooid. Let op: er kan meer dan één camera zijn voor de holografische scène.

Als u wilt weergeven in holografische cameraweergaven, moet u eenmaal per frame het volgende doen:

  • Voor elke camera geeft u de scène voor het huidige frame weer met behulp van de cameraweergave en projectiematrices van het systeem.

Een nieuw holografisch frame maken en de voorspelling ervan ophalen

Het HolographicFrame bevat informatie die de app nodig heeft om het huidige frame bij te werken en weer te geven. De app begint elk nieuw frame door de methode CreateNextFrame aan te roepen. Wanneer deze methode wordt aangeroepen, worden voorspellingen gedaan met behulp van de meest recente sensorgegevens die beschikbaar zijn en ingekapseld in het Object CurrentPrediction .

Er moet een nieuw frameobject worden gebruikt voor elk gerenderd frame, omdat het slechts een moment in de tijd geldig is. De eigenschap CurrentPrediction bevat informatie zoals de positie van de camera. De informatie wordt geëxtrapoleerd naar het exacte moment in de tijd waarop het frame naar verwachting zichtbaar is voor de gebruiker.

De volgende code is afkomstig uit AppMain::Update:

// The HolographicFrame has information that the app needs in order
// to update and render the current frame. The app begins each new
// frame by calling CreateNextFrame.
HolographicFrame holographicFrame = m_holographicSpace.CreateNextFrame();

// Get a prediction of where holographic cameras will be when this frame
// is presented.
HolographicFramePrediction prediction = holographicFrame.CurrentPrediction();

Camera-updates verwerken

Achterbuffers kunnen van frame naar frame worden gewijzigd. Uw app moet de back-buffer voor elke camera valideren en indien nodig resourceweergaven en dieptebuffers vrijgeven en opnieuw maken. U ziet dat de set poses in de voorspelling de gezaghebbende lijst is met camera's die in het huidige frame worden gebruikt. Meestal gebruikt u deze lijst om de set camera's te herhalen.

Van AppMain::Update:

m_deviceResources->EnsureCameraResources(holographicFrame, prediction);

Van DeviceResources::EnsureCameraResources:

for (HolographicCameraPose const& cameraPose : prediction.CameraPoses())
{
    HolographicCameraRenderingParameters renderingParameters = frame.GetRenderingParameters(cameraPose);
    CameraResources* pCameraResources = cameraResourceMap[cameraPose.HolographicCamera().Id()].get();
    pCameraResources->CreateResourcesForBackBuffer(this, renderingParameters);
}

Het coördinatensysteem ophalen dat moet worden gebruikt als basis voor rendering

met Windows Mixed Reality kunt u met uw app verschillende coördinatensystemen maken, zoals gekoppelde en stationaire referentieframes voor het bijhouden van locaties in de fysieke wereld. Uw app kan deze coördinaatsystemen vervolgens gebruiken om te bepalen waar hologrammen voor elk frame moeten worden weergegeven. Wanneer u coördinaten van een API aanvraagt, geeft u altijd het SpatialCoordinateSystem door waarin u deze coördinaten wilt uitdrukken.

Van AppMain::Update:

pose = SpatialPointerPose::TryGetAtTimestamp(
    m_stationaryReferenceFrame.CoordinateSystem(), prediction.Timestamp());

Deze coördinatensystemen kunnen vervolgens worden gebruikt om stereoweergavematrices te genereren bij het weergeven van de inhoud in uw scène.

Van CameraResources::UpdateViewProjectionBuffer:

// Get a container object with the view and projection matrices for the given
// pose in the given coordinate system.
auto viewTransformContainer = cameraPose.TryGetViewTransform(coordinateSystem);

Blik- en bewegingsinvoer verwerken

Blikken en handinvoer zijn niet op tijd gebaseerd en hoeven niet te worden bijgewerkt in de functie StepTimer . Deze invoer is echter iets dat de app moet bekijken in elk frame.

Op tijd gebaseerde updates verwerken

Elke realtime rendering-app heeft een manier nodig om tijdgebaseerde updates te verwerken: de Sjabloon voor de Windows Holographic-app maakt gebruik van een StepTimer-implementatie , vergelijkbaar met de StepTimer die wordt geleverd in de DirectX 11 UWP-app-sjabloon. Deze StepTimer-voorbeeldhelperklasse kan vaste tijdstapupdates, variabele tijdstapupdates bieden en de standaardmodus is variabele tijdstappen.

Voor holografische rendering hebben we ervoor gekozen om niet te veel in de timerfunctie te plaatsen, omdat u deze kunt configureren als een vaste tijdstap. Het kan meerdere keren per frame worden aangeroepen ( of helemaal niet, voor sommige frames ) en onze holografische gegevensupdates moeten eenmaal per frame plaatsvinden.

Van AppMain::Update:

m_timer.Tick([this]()
{
    m_spinningCubeRenderer->Update(m_timer);
});

Hologrammen in uw coördinatensysteem positioneren en draaien

Als u in één coördinatensysteem werkt, zoals de sjabloon doet met het SpatialStationaryReferenceFrame, verschilt dit proces niet van wat u anders gewend bent in 3D-afbeeldingen. Hier draaien we de kubus en stellen we de modelmatrix in op basis van de positie in het stationaire coördinatensysteem.

Van SpinningCubeRenderer::Update:

// Rotate the cube.
// Convert degrees to radians, then convert seconds to rotation angle.
const float    radiansPerSecond = XMConvertToRadians(m_degreesPerSecond);
const double   totalRotation = timer.GetTotalSeconds() * radiansPerSecond;
const float    radians = static_cast<float>(fmod(totalRotation, XM_2PI));
const XMMATRIX modelRotation = XMMatrixRotationY(-radians);

// Position the cube.
const XMMATRIX modelTranslation = XMMatrixTranslationFromVector(XMLoadFloat3(&m_position));

// Multiply to get the transform matrix.
// Note that this transform does not enforce a particular coordinate system. The calling
// class is responsible for rendering this content in a consistent manner.
const XMMATRIX modelTransform = XMMatrixMultiply(modelRotation, modelTranslation);

// The view and projection matrices are provided by the system; they are associated
// with holographic cameras, and updated on a per-camera basis.
// Here, we provide the model transform for the sample hologram. The model transform
// matrix is transposed to prepare it for the shader.
XMStoreFloat4x4(&m_modelConstantBufferData.model, XMMatrixTranspose(modelTransform));

Opmerking over geavanceerde scenario's: De draaiende kubus is een eenvoudig voorbeeld van het plaatsen van een hologram binnen één referentieframe. Het is ook mogelijk om meerdere SpatialCoordinateSystems tegelijkertijd in hetzelfde gerenderde frame te gebruiken.

Constante buffergegevens bijwerken

Modeltransformaties voor inhoud worden zoals gebruikelijk bijgewerkt. Inmiddels hebt u geldige transformaties berekend voor het coördinatensysteem waarin u gaat renderen.

Van SpinningCubeRenderer::Update:

// Update the model transform buffer for the hologram.
context->UpdateSubresource(
    m_modelConstantBuffer.Get(),
    0,
    nullptr,
    &m_modelConstantBufferData,
    0,
    0
);

Hoe zit het met weergave- en projectietransformaties? Voor de beste resultaten willen we wachten totdat we bijna klaar zijn voor onze trekkingsgesprekken voordat we deze krijgen.

Het huidige frame weergeven

Rendering op Windows Mixed Reality verschilt niet veel van rendering op een 2D-monobeeldscherm, maar er zijn een paar verschillen:

  • Holografische framevoorspellingen zijn belangrijk. Hoe dichter de voorspelling ligt bij het moment dat uw frame wordt gepresenteerd, hoe beter uw hologrammen eruitzien.
  • Windows Mixed Reality bepaalt de cameraweergaven. Render naar elk frame, omdat het holografische frame ze later voor u presenteert.
  • We raden u aan stereorendering uit te voeren met behulp van een instantietekening naar een renderdoelmatrix. De holografische app-sjabloon maakt gebruik van de aanbevolen benadering van het tekenen van een exemplaar om een doelmatrix weer te geven, die gebruikmaakt van een doelweergave weergeven op een Texture2DArray.
  • Als u wilt renderen zonder stereo-instancing te gebruiken, moet u twee niet-matrix RenderTargetViews maken, één voor elk oog. Elke RenderTargetViews verwijst naar een van de twee segmenten in de Texture2DArray die vanuit het systeem aan de app is verstrekt. Dit wordt niet aanbevolen, omdat het doorgaans langzamer is dan het gebruik van instancing.

Een bijgewerkte HolographicFrame-voorspelling ophalen

Het bijwerken van de framevoorspelling verbetert de effectiviteit van beeldstabilisatie. U krijgt nauwkeurigere plaatsing van hologrammen vanwege de kortere tijd tussen de voorspelling en het moment waarop het frame zichtbaar is voor de gebruiker. In het ideale plaats uw framevoorspelling bijwerken vlak voordat de weergave wordt weergegeven.

holographicFrame.UpdateCurrentPrediction();
HolographicFramePrediction prediction = holographicFrame.CurrentPrediction();

Weergeven naar elke camera

Maak een lus op de set camerahoudingen in de voorspelling en geef deze weer voor elke camera in deze set.

Uw rendering-pas instellen

Windows Mixed Reality maakt gebruik van stereoscopische weergave om de illusie van diepte te vergroten en stereoscopisch weer te geven, zodat zowel het linker- als het rechterbeeldscherm actief zijn. Bij stereoscopische rendering is er een verschuiving tussen de twee beeldschermen, die de hersenen als werkelijke diepte kunnen verzoenen. In deze sectie wordt stereoscopische rendering met instancing behandeld, met behulp van code uit de sjabloon voor de Windows Holographic-app.

Elke camera heeft een eigen renderdoel (achterbuffer) en weergave- en projectiematrices, in de holografische ruimte. Uw app moet andere op camera's gebaseerde resources, zoals de dieptebuffer, per camera maken. In de sjabloon voor de Windows Holographic-app bieden we een helperklasse om deze resources samen te bundelen in DX::CameraResources. Begin met het instellen van de weergavedoelweergaven:

Vanuit AppMain::Render:

// This represents the device-based resources for a HolographicCamera.
DX::CameraResources* pCameraResources = cameraResourceMap[cameraPose.HolographicCamera().Id()].get();

// Get the device context.
const auto context = m_deviceResources->GetD3DDeviceContext();
const auto depthStencilView = pCameraResources->GetDepthStencilView();

// Set render targets to the current holographic camera.
ID3D11RenderTargetView *const targets[1] =
    { pCameraResources->GetBackBufferRenderTargetView() };
context->OMSetRenderTargets(1, targets, depthStencilView);

// Clear the back buffer and depth stencil view.
if (m_canGetHolographicDisplayForCamera &&
    cameraPose.HolographicCamera().Display().IsOpaque())
{
    context->ClearRenderTargetView(targets[0], DirectX::Colors::CornflowerBlue);
}
else
{
    context->ClearRenderTargetView(targets[0], DirectX::Colors::Transparent);
}
context->ClearDepthStencilView(
    depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);

De voorspelling gebruiken om de weergave- en projectiematrices voor de camera op te halen

De weergave- en projectiematrices voor elke holografische camera veranderen met elk frame. Vernieuw de gegevens in de constante buffer voor elke holografische camera. Doe dit nadat u de voorspelling hebt bijgewerkt en voordat u trekoproepen voor die camera maakt.

Vanuit AppMain::Render:

// The view and projection matrices for each holographic camera will change
// every frame. This function refreshes the data in the constant buffer for
// the holographic camera indicated by cameraPose.
if (m_stationaryReferenceFrame)
{
    pCameraResources->UpdateViewProjectionBuffer(
        m_deviceResources, cameraPose, m_stationaryReferenceFrame.CoordinateSystem());
}

// Attach the view/projection constant buffer for this camera to the graphics pipeline.
bool cameraActive = pCameraResources->AttachViewProjectionBuffer(m_deviceResources);

Hier laten we zien hoe de matrices worden verkregen uit de camerahouding. Tijdens dit proces verkrijgen we ook de huidige viewport voor de camera. Let op hoe we een coördinatensysteem bieden: dit is hetzelfde coördinatensysteem dat we hebben gebruikt om staren te begrijpen, en het is hetzelfde systeem dat we hebben gebruikt om de draaiende kubus te positioneren.

Van CameraResources::UpdateViewProjectionBuffer:

// The system changes the viewport on a per-frame basis for system optimizations.
auto viewport = cameraPose.Viewport();
m_d3dViewport = CD3D11_VIEWPORT(
    viewport.X,
    viewport.Y,
    viewport.Width,
    viewport.Height
);

// The projection transform for each frame is provided by the HolographicCameraPose.
HolographicStereoTransform cameraProjectionTransform = cameraPose.ProjectionTransform();

// Get a container object with the view and projection matrices for the given
// pose in the given coordinate system.
auto viewTransformContainer = cameraPose.TryGetViewTransform(coordinateSystem);

// If TryGetViewTransform returns a null pointer, that means the pose and coordinate
// system cannot be understood relative to one another; content cannot be rendered
// in this coordinate system for the duration of the current frame.
// This usually means that positional tracking is not active for the current frame, in
// which case it is possible to use a SpatialLocatorAttachedFrameOfReference to render
// content that is not world-locked instead.
DX::ViewProjectionConstantBuffer viewProjectionConstantBufferData;
bool viewTransformAcquired = viewTransformContainer != nullptr;
if (viewTransformAcquired)
{
    // Otherwise, the set of view transforms can be retrieved.
    HolographicStereoTransform viewCoordinateSystemTransform = viewTransformContainer.Value();

    // Update the view matrices. Holographic cameras (such as Microsoft HoloLens) are
    // constantly moving relative to the world. The view matrices need to be updated
    // every frame.
    XMStoreFloat4x4(
        &viewProjectionConstantBufferData.viewProjection[0],
        XMMatrixTranspose(XMLoadFloat4x4(&viewCoordinateSystemTransform.Left) *
            XMLoadFloat4x4(&cameraProjectionTransform.Left))
    );
    XMStoreFloat4x4(
        &viewProjectionConstantBufferData.viewProjection[1],
        XMMatrixTranspose(XMLoadFloat4x4(&viewCoordinateSystemTransform.Right) *
            XMLoadFloat4x4(&cameraProjectionTransform.Right))
    );
}

De viewport moet voor elk frame worden ingesteld. Uw hoekpunt-shader (ten minste) heeft over het algemeen toegang nodig tot de weergave-/projectiegegevens.

Vanuit CameraResources::AttachViewProjectionBuffer:

// Set the viewport for this camera.
context->RSSetViewports(1, &m_d3dViewport);

// Send the constant buffer to the vertex shader.
context->VSSetConstantBuffers(
    1,
    1,
    m_viewProjectionConstantBuffer.GetAddressOf()
);

Render naar de backbuffer van de camera en voer de dieptebuffer door:

Het is een goed idee om te controleren of TryGetViewTransform is geslaagd voordat u probeert de weergave-/projectiegegevens te gebruiken, want als het coördinatensysteem niet kan worden geïmplementeerd (bijvoorbeeld omdat het bijhouden is onderbroken), kan uw app er niet mee renderen voor dat frame. De sjabloon roept Alleen Render aan op de draaiende kubus als de klasse CameraResources aangeeft dat de update is geslaagd.

Windows Mixed Reality bevat functies voor beeldstabilisatie om hologrammen op de positie te houden waar een ontwikkelaar of gebruiker ze in de wereld plaatst. Afbeeldingsstabilisatie helpt bij het verbergen van de latentie die inherent is aan een rendering-pijplijn om de beste holografische ervaringen voor gebruikers te garanderen. Er kan een focuspunt worden opgegeven om de beeldstabilisatie nog verder te verbeteren, of er kan een dieptebuffer worden geboden om geoptimaliseerde beeldstabilisatie in realtime te berekenen.

Voor de beste resultaten moet uw app een dieptebuffer bieden met behulp van de CommitDirect3D11DepthBuffer-API . Windows Mixed Reality kunt vervolgens geometriegegevens uit de dieptebuffer gebruiken om beeldstabilisatie in realtime te optimaliseren. Met de sjabloon voor de Windows Holographic-app wordt standaard de dieptebuffer van de app doorgevoerd, zodat de stabiliteit van hologrammen wordt geoptimaliseerd.

Vanuit AppMain::Render:

// Only render world-locked content when positional tracking is active.
if (cameraActive)
{
    // Draw the sample hologram.
    m_spinningCubeRenderer->Render();
    if (m_canCommitDirect3D11DepthBuffer)
    {
        // On versions of the platform that support the CommitDirect3D11DepthBuffer API, we can 
        // provide the depth buffer to the system, and it will use depth information to stabilize 
        // the image at a per-pixel level.
        HolographicCameraRenderingParameters renderingParameters =
            holographicFrame.GetRenderingParameters(cameraPose);
        
        IDirect3DSurface interopSurface =
            DX::CreateDepthTextureInteropObject(pCameraResources->GetDepthStencilTexture2D());

        // Calling CommitDirect3D11DepthBuffer causes the system to queue Direct3D commands to 
        // read the depth buffer. It will then use that information to stabilize the image as
        // the HolographicFrame is presented.
        renderingParameters.CommitDirect3D11DepthBuffer(interopSurface);
    }
}

Notitie

Windows verwerkt uw dieptepatroon op de GPU, dus het moet mogelijk zijn om uw dieptebuffer als arceringsresource te gebruiken. De ID3D11Texture2D die u maakt, moet een typeloze indeling hebben en moeten worden gebonden als een arceringsresourceweergave. Hier volgt een voorbeeld van het maken van een dieptepatroon dat kan worden doorgevoerd voor beeldstabilisatie.

Code voor het maken van dieptebufferresources voor CommitDirect3D11DepthBuffer:

// Create a depth stencil view for use with 3D rendering if needed.
CD3D11_TEXTURE2D_DESC depthStencilDesc(
    DXGI_FORMAT_R16_TYPELESS,
    static_cast<UINT>(m_d3dRenderTargetSize.Width),
    static_cast<UINT>(m_d3dRenderTargetSize.Height),
    m_isStereo ? 2 : 1, // Create two textures when rendering in stereo.
    1, // Use a single mipmap level.
    D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE
);

winrt::check_hresult(
    device->CreateTexture2D(
        &depthStencilDesc,
        nullptr,
        &m_d3dDepthStencil
    ));

CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc(
    m_isStereo ? D3D11_DSV_DIMENSION_TEXTURE2DARRAY : D3D11_DSV_DIMENSION_TEXTURE2D,
    DXGI_FORMAT_D16_UNORM
);
winrt::check_hresult(
    device->CreateDepthStencilView(
        m_d3dDepthStencil.Get(),
        &depthStencilViewDesc,
        &m_d3dDepthStencilView
    ));

Holografische inhoud tekenen

Met de sjabloon van de Windows Holographic-app wordt inhoud in stereo weergegeven met behulp van de aanbevolen techniek van het tekenen van een instantiegeometrie naar een Texture2DArray van grootte 2. Laten we eens kijken naar het instancing-gedeelte hiervan en hoe dit werkt op Windows Mixed Reality.

Van SpinningCubeRenderer::Render:

// Draw the objects.
context->DrawIndexedInstanced(
    m_indexCount,   // Index count per instance.
    2,              // Instance count.
    0,              // Start index location.
    0,              // Base vertex location.
    0               // Start instance location.
);

Elk exemplaar heeft toegang tot een andere weergave/projectiematrix vanuit de constante buffer. Hier ziet u de constante bufferstructuur, die slechts een matrix van twee matrices is.

Van VertexShaderShared.hlsl, opgenomen door VPRTVertexShader.hlsl:

// A constant buffer that stores each set of view and projection matrices in column-major format.
cbuffer ViewProjectionConstantBuffer : register(b1)
{
    float4x4 viewProjection[2];
};

De doelmatrixindex moet voor elke pixel worden ingesteld. In het volgende fragment is output.viewId toegewezen aan de SV_RenderTargetArrayIndex semantisch. Hiervoor is ondersteuning vereist voor een optionele Direct3D 11.3-functie, waarmee de doelmatrixindex semantisch kan worden ingesteld vanuit elke arceringsfase.

Vanuit VPRTVertexShader.hlsl:

// Per-vertex data passed to the geometry shader.
struct VertexShaderOutput
{
    min16float4 pos     : SV_POSITION;
    min16float3 color   : COLOR0;

    // The render target array index is set here in the vertex shader.
    uint        viewId  : SV_RenderTargetArrayIndex;
};

Van VertexShaderShared.hlsl, opgenomen door VPRTVertexShader.hlsl:

// Per-vertex data used as input to the vertex shader.
struct VertexShaderInput
{
    min16float3 pos     : POSITION;
    min16float3 color   : COLOR0;
    uint        instId  : SV_InstanceID;
};

// Simple shader to do vertex processing on the GPU.
VertexShaderOutput main(VertexShaderInput input)
{
    VertexShaderOutput output;
    float4 pos = float4(input.pos, 1.0f);

    // Note which view this vertex has been sent to. Used for matrix lookup.
    // Taking the modulo of the instance ID allows geometry instancing to be used
    // along with stereo instanced drawing; in that case, two copies of each 
    // instance would be drawn, one for left and one for right.
    int idx = input.instId % 2;

    // Transform the vertex position into world space.
    pos = mul(pos, model);

    // Correct for perspective and project the vertex position onto the screen.
    pos = mul(pos, viewProjection[idx]);
    output.pos = (min16float4)pos;

    // Pass the color through without modification.
    output.color = input.color;

    // Set the render target array index.
    output.viewId = idx;

    return output;
}

Als u uw bestaande instantietekentechnieken wilt gebruiken met deze methode voor tekenen naar een stereo render-doelmatrix, tekent u tweemaal het aantal exemplaren dat u normaal hebt. Deel input.instId in de shader door 2 om de oorspronkelijke exemplaar-id op te halen, die kan worden geïndexeerd in (bijvoorbeeld) een buffer met gegevens per object: int actualIdx = input.instId / 2;

Belangrijke opmerking over het weergeven van stereo-inhoud op HoloLens

Windows Mixed Reality ondersteunt de mogelijkheid om de doelmatrixindex in te stellen vanuit elke shaderfase. Normaal gesproken is dit een taak die alleen kan worden uitgevoerd in de fase van de geometrie-arcering vanwege de manier waarop de semantiek is gedefinieerd voor Direct3D 11. Hier laten we een volledig voorbeeld zien van het instellen van een rendering-pijplijn met alleen de fases hoekpunt en pixel-shader. De shader-code is zoals hierboven beschreven.

Van SpinningCubeRenderer::Render:

const auto context = m_deviceResources->GetD3DDeviceContext();

// Each vertex is one instance of the VertexPositionColor struct.
const UINT stride = sizeof(VertexPositionColor);
const UINT offset = 0;
context->IASetVertexBuffers(
    0,
    1,
    m_vertexBuffer.GetAddressOf(),
    &stride,
    &offset
);
context->IASetIndexBuffer(
    m_indexBuffer.Get(),
    DXGI_FORMAT_R16_UINT, // Each index is one 16-bit unsigned integer (short).
    0
);
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
context->IASetInputLayout(m_inputLayout.Get());

// Attach the vertex shader.
context->VSSetShader(
    m_vertexShader.Get(),
    nullptr,
    0
);
// Apply the model constant buffer to the vertex shader.
context->VSSetConstantBuffers(
    0,
    1,
    m_modelConstantBuffer.GetAddressOf()
);

// Attach the pixel shader.
context->PSSetShader(
    m_pixelShader.Get(),
    nullptr,
    0
);

// Draw the objects.
context->DrawIndexedInstanced(
    m_indexCount,   // Index count per instance.
    2,              // Instance count.
    0,              // Start index location.
    0,              // Base vertex location.
    0               // Start instance location.
);

Belangrijke opmerking over rendering op niet-HoloLens-apparaten

Als u de doelmatrixindex voor renderen instelt in de hoekpunt-shader, moet het grafische stuurprogramma een optionele Direct3D 11.3-functie ondersteunen, die HoloLens wel ondersteunt. Uw app kan mogelijk alleen die techniek voor rendering implementeren en aan alle vereisten voor het uitvoeren op de Microsoft HoloLens wordt voldaan.

Het kan zijn dat u ook de HoloLens-emulator wilt gebruiken. Dit kan een krachtig ontwikkelhulpprogramma zijn voor uw holografische app en ondersteuning bieden voor Windows Mixed Reality immersive headsetapparaten die zijn aangesloten op Windows 10 pc's. Ondersteuning voor het niet-HoloLens-renderingpad - voor alle Windows Mixed Reality - is ook ingebouwd in de sjabloon voor de Windows Holographic-app. In de sjablooncode vindt u code waarmee uw holografische app kan worden uitgevoerd op de GPU op uw ontwikkel-pc. Hier ziet u hoe de klasse DeviceResources controleert op deze optionele functieondersteuning.

Van DeviceResources::CreateDeviceResources:

// Check for device support for the optional feature that allows setting the render target array index from the vertex shader stage.
D3D11_FEATURE_DATA_D3D11_OPTIONS3 options;
m_d3dDevice->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS3, &options, sizeof(options));
if (options.VPAndRTArrayIndexFromAnyShaderFeedingRasterizer)
{
    m_supportsVprt = true;
}

Als u rendering wilt ondersteunen zonder deze optionele functie, moet uw app een geometrie-shader gebruiken om de doelmatrixindex voor de weergave in te stellen. Dit codefragment wordt toegevoegd naVSSetConstantBuffers en vóórPSSetShader in het codevoorbeeld in de vorige sectie waarin wordt uitgelegd hoe stereo op HoloLens wordt weergegeven.

Van SpinningCubeRenderer::Render:

if (!m_usingVprtShaders)
{
    // On devices that do not support the D3D11_FEATURE_D3D11_OPTIONS3::
    // VPAndRTArrayIndexFromAnyShaderFeedingRasterizer optional feature,
    // a pass-through geometry shader is used to set the render target 
    // array index.
    context->GSSetShader(
        m_geometryShader.Get(),
        nullptr,
        0
    );
}

HLSL-OPMERKING: In dit geval moet u ook een enigszins gewijzigde hoekpunt-shader laden die de doelmatrixindex voor renderen doorgeeft aan de geometrie-shader met behulp van een altijd toegestane shader-semantiek, zoals TEXCOORD0. De geometrie-shader hoeft geen werk te doen; de sjabloongeometrie-shader doorloopt alle gegevens, met uitzondering van de doelmatrixindex renderen, die wordt gebruikt om de SV_RenderTargetArrayIndex semantisch in te stellen.

App-sjablooncode voor GeometryShader.hlsl:

// Per-vertex data from the vertex shader.
struct GeometryShaderInput
{
    min16float4 pos     : SV_POSITION;
    min16float3 color   : COLOR0;
    uint instId         : TEXCOORD0;
};

// Per-vertex data passed to the rasterizer.
struct GeometryShaderOutput
{
    min16float4 pos     : SV_POSITION;
    min16float3 color   : COLOR0;
    uint rtvId          : SV_RenderTargetArrayIndex;
};

// This geometry shader is a pass-through that leaves the geometry unmodified 
// and sets the render target array index.
[maxvertexcount(3)]
void main(triangle GeometryShaderInput input[3], inout TriangleStream<GeometryShaderOutput> outStream)
{
    GeometryShaderOutput output;
    [unroll(3)]
    for (int i = 0; i < 3; ++i)
    {
        output.pos   = input[i].pos;
        output.color = input[i].color;
        output.rtvId = input[i].instId;
        outStream.Append(output);
    }
}

Aanwezig

Het holografische frame inschakelen om de wisselketen te presenteren

Met Windows Mixed Reality regelt het systeem de wisselketen. Het systeem beheert vervolgens het presenteren van frames aan elke holografische camera om een gebruikerservaring van hoge kwaliteit te garanderen. Het biedt ook een viewport update voor elk frame, voor elke camera, om aspecten van het systeem te optimaliseren, zoals beeldstabilisatie of Mixed Reality Capture. Dus een holografische app die DirectX gebruikt, roept Present niet aan op een DXGI-wisselketen. In plaats daarvan gebruikt u de klasse HolographicFrame om alle wisselketens voor een frame weer te geven wanneer u klaar bent met tekenen.

Van DeviceResources::P resent:

HolographicFramePresentResult presentResult = frame.PresentUsingCurrentPrediction();

Deze API wacht standaard tot het frame is voltooid voordat het wordt geretourneerd. Holografische apps moeten wachten tot het vorige frame is voltooid voordat ze aan een nieuw frame gaan werken, omdat dit de latentie vermindert en betere resultaten van holografische framevoorspellingen mogelijk maakt. Dit is geen harde regel en als u frames hebt die langer duren dan één schermvernieuwing, kunt u deze wachttijd uitschakelen door de parameter HolographicFramePresentWaitBehavior door te geven aan PresentUsingCurrentPrediction. In dit geval gebruikt u waarschijnlijk een asynchrone rendering-thread om de GPU continu te laden. De vernieuwingsfrequentie van het HoloLens-apparaat is 60 hz, waarbij één frame een duur van ongeveer 16 ms heeft. Insluitende headsetapparaten kunnen variëren van 60 hz tot 90 hz; bij het vernieuwen van het beeldscherm bij 90 hz heeft elk frame een duur van ongeveer 11 ms.

DeviceLost-scenario's verwerken in samenwerking met het HolographicFrame

DirectX 11-apps willen doorgaans de HRESULT controleren die wordt geretourneerd door de functie Present van de DXGI-wisselketen om erachter te komen of er een DeviceLost-fout is opgetreden. De klasse HolographicFrame verwerkt dit voor u. Inspecteer het geretourneerde HolographicFramePresentResult om erachter te komen of u de Direct3D-apparaat- en apparaatresources moet vrijgeven en opnieuw moet maken.

// The PresentUsingCurrentPrediction API will detect when the graphics device
// changes or becomes invalid. When this happens, it is considered a Direct3D
// device lost scenario.
if (presentResult == HolographicFramePresentResult::DeviceRemoved)
{
    // The Direct3D device, context, and resources should be recreated.
    HandleDeviceLost();
}

Als het Direct3D-apparaat verloren is gegaan en u het opnieuw hebt gemaakt, moet u de HolographicSpace laten weten dat het nieuwe apparaat moet worden gebruikt. De wisselketen wordt opnieuw gemaakt voor dit apparaat.

Van DeviceResources::InitializeUsingHolographicSpace:

m_holographicSpace.SetDirect3D11Device(m_d3dInteropDevice);

Zodra uw frame is gepresenteerd, kunt u terugkeren naar de hoofdprogrammalus en toestaan dat het doorgaat naar het volgende frame.

Hybride grafische pc's en mixed reality-toepassingen

Windows 10-makersupdate pc's kunnen worden geconfigureerd met zowel discrete als geïntegreerde GPU's. Bij dit soort computers kiest Windows de adapter waarmee de headset is verbonden. Toepassingen moeten ervoor zorgen dat het DirectX-apparaat dat wordt gemaakt, dezelfde adapter gebruikt.

De meeste algemene Direct3D-voorbeeldcode laat zien hoe u een DirectX-apparaat maakt met behulp van de standaardhardwareadapter, die op een hybride systeem mogelijk niet hetzelfde is als het apparaat dat voor de headset wordt gebruikt.

Als u problemen wilt omzeilen, gebruikt u de HolographicAdapterID van een van de HolographicSpaces. PrimaryAdapterId() of HolographicDisplay. AdapterId(). Deze adapterId kan vervolgens worden gebruikt om de juiste DXGIAdapter te selecteren met behulp van IDXGIFactory4.EnumAdapterByLuid.

Van DeviceResources::InitializeUsingHolographicSpace:

// The holographic space might need to determine which adapter supports
// holograms, in which case it will specify a non-zero PrimaryAdapterId.
LUID id =
{
    m_holographicSpace.PrimaryAdapterId().LowPart,
    m_holographicSpace.PrimaryAdapterId().HighPart
};

// When a primary adapter ID is given to the app, the app should find
// the corresponding DXGI adapter and use it to create Direct3D devices
// and device contexts. Otherwise, there is no restriction on the DXGI
// adapter the app can use.
if ((id.HighPart != 0) || (id.LowPart != 0))
{
    UINT createFlags = 0;

    // Create the DXGI factory.
    ComPtr<IDXGIFactory1> dxgiFactory;
    winrt::check_hresult(
        CreateDXGIFactory2(
            createFlags,
            IID_PPV_ARGS(&dxgiFactory)
        ));
    ComPtr<IDXGIFactory4> dxgiFactory4;
    winrt::check_hresult(dxgiFactory.As(&dxgiFactory4));

    // Retrieve the adapter specified by the holographic space.
    winrt::check_hresult(
        dxgiFactory4->EnumAdapterByLuid(
            id,
            IID_PPV_ARGS(&m_dxgiAdapter)
        ));
}
else
{
    m_dxgiAdapter.Reset();
}

Code voor het bijwerken van DeviceResources::CreateDeviceResources voor het gebruik van IDXGIAdapter

// Create the Direct3D 11 API device object and a corresponding context.
ComPtr<ID3D11Device> device;
ComPtr<ID3D11DeviceContext> context;

const D3D_DRIVER_TYPE driverType = m_dxgiAdapter == nullptr ? D3D_DRIVER_TYPE_HARDWARE : D3D_DRIVER_TYPE_UNKNOWN;
const HRESULT hr = D3D11CreateDevice(
    m_dxgiAdapter.Get(),        // Either nullptr, or the primary adapter determined by Windows Holographic.
    driverType,                 // Create a device using the hardware graphics driver.
    0,                          // Should be 0 unless the driver is D3D_DRIVER_TYPE_SOFTWARE.
    creationFlags,              // Set debug and Direct2D compatibility flags.
    featureLevels,              // List of feature levels this app can support.
    ARRAYSIZE(featureLevels),   // Size of the list above.
    D3D11_SDK_VERSION,          // Always set this to D3D11_SDK_VERSION for Windows Runtime apps.
    &device,                    // Returns the Direct3D device created.
    &m_d3dFeatureLevel,         // Returns feature level of device created.
    &context                    // Returns the device immediate context.
);

Hybride afbeeldingen en Media Foundation

Het gebruik van Media Foundation op hybride systemen kan problemen veroorzaken waarbij video niet wordt weergegeven of waarbij de videostructuur beschadigd is omdat Media Foundation standaard een systeemgedrag heeft. In sommige scenario's is het maken van een afzonderlijk ID3D11Device vereist voor de ondersteuning van multithreading en worden de juiste markeringen voor het maken ingesteld.

Bij het initialiseren van de ID3D11Device moet D3D11_CREATE_DEVICE_VIDEO_SUPPORT vlag worden gedefinieerd als onderdeel van de D3D11_CREATE_DEVICE_FLAG. Zodra het apparaat en de context zijn gemaakt, roept u SetMultithreadProtected aan om multithreading in te schakelen. Als u het apparaat wilt koppelen aan de IMFDXGIDeviceManager, gebruikt u de functie IMFDXGIDeviceManager::ResetDevice .

Code om een ID3D11Device te koppelen aan IMFDXGIDeviceManager:

// create dx device for media pipeline
winrt::com_ptr<ID3D11Device> spMediaDevice;

// See above. Also make sure to enable the following flags on the D3D11 device:
//   * D3D11_CREATE_DEVICE_VIDEO_SUPPORT
//   * D3D11_CREATE_DEVICE_BGRA_SUPPORT
if (FAILED(CreateMediaDevice(spAdapter.get(), &spMediaDevice)))
    return;                                                     

// Turn multithreading on 
winrt::com_ptr<ID3D10Multithread> spMultithread;
if (spContext.try_as(spMultithread))
{
    spMultithread->SetMultithreadProtected(TRUE);
}

// lock the shared dxgi device manager
// call MFUnlockDXGIDeviceManager when no longer needed
UINT uiResetToken;
winrt::com_ptr<IMFDXGIDeviceManager> spDeviceManager;
hr = MFLockDXGIDeviceManager(&uiResetToken, spDeviceManager.put());
if (FAILED(hr))
    return hr;
    
// associate the device with the manager
hr = spDeviceManager->ResetDevice(spMediaDevice.get(), uiResetToken);
if (FAILED(hr))
    return hr;

Zie ook