Vykreslování v Rozhraní DirectX

Poznámka

Tento článek se týká starších nativních rozhraní API WinRT. Pro nové projekty nativních aplikací doporučujeme použít rozhraní OpenXR API.

Windows Mixed Reality je postavená na rozhraní DirectX a umožňuje uživatelům vytvářet bohaté 3D grafické prostředí. Abstrakce vykreslování se nachází těsně nad rozhraním DirectX, což umožňuje aplikacím uvažovat o poloze a orientaci pozorovatelů holografických scén předpověděných systémem. Vývojář pak může své hologramy najít na základě každé kamery a nechat aplikaci vykreslit tyto hologramy v různých prostorových souřadnicových systémech, jak se uživatel pohybuje.

Poznámka: Tento návod popisuje holografické vykreslování v Direct3D 11. Šablona aplikace Direct3D 12 Windows Mixed Reality se dodává také s rozšířením Mixed Reality šablon aplikací.

Aktualizace aktuálního rámce

Pokud chcete aktualizovat stav aplikace pro hologramy, aplikace jednou za rámeček:

  • Získejte HolographicFrame ze systému pro správu zobrazení.
  • Aktualizujte scénu aktuální predikcí, kde se bude po vykreslení zobrazovat kamera. Poznámka: Pro holografickou scénu může existovat více než jedna kamera.

Pokud chcete vykreslit zobrazení holografických fotoaparátů, aplikace jednou za snímek:

  • Pro každou kameru vykreslujte scénu pro aktuální snímek pomocí matic zobrazení kamery a projekce ze systému.

Vytvoření nového holografického rámce a získání jeho předpovědi

HolographicFrame obsahuje informace, které aplikace potřebuje k aktualizaci a vykreslení aktuálního rámce. Aplikace začne každý nový rámec voláním metody CreateNextFrame . Při zavolání této metody jsou předpovědi provedeny pomocí nejnovějších dostupných dat senzoru a zapouzdřeny v objektu CurrentPrediction .

Nový objekt rámce musí být použit pro každý vykreslený snímek, protože je platný pouze pro okamžik v čase. Vlastnost CurrentPrediction obsahuje informace, jako je umístění kamery. Informace jsou extrapolovány na přesný okamžik v čase, kdy se očekává, že bude snímek viditelný pro uživatele.

Následující kód je vyjmut z 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();

Zpracování aktualizací fotoaparátu

Zadní vyrovnávací paměti se můžou měnit mezi snímky. Vaše aplikace musí ověřit zadní vyrovnávací paměť pro každou kameru a podle potřeby uvolnit a znovu vytvořit zobrazení prostředků a hloubkové vyrovnávací paměti. Všimněte si, že sada pozic v predikci je autoritativní seznam fotoaparátů používaných v aktuálním snímku. Tento seznam se obvykle používá k iteraci sady fotoaparátů.

Z AppMain::Update:

m_deviceResources->EnsureCameraResources(holographicFrame, prediction);

From DeviceResources::EnsureCameraResources:

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

Získání souřadnicového systému, který se má použít jako základ pro vykreslování

Windows Mixed Reality umožňuje aplikaci vytvářet různé souřadnicové systémy, jako jsou připojené a statické referenční rámce pro sledování míst ve fyzickém světě. Aplikace pak může tyto souřadnicové systémy použít k odůvodnění, kde vykreslit jednotlivé snímky hologramů. Při žádosti o souřadnice z rozhraní API budete vždy předávat systém SpatialCoordinateSystem , ve kterém chcete tyto souřadnice vyjádřit.

Z AppMain::Update:

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

Tyto souřadnicové systémy se pak dají použít ke generování stereo matic zobrazení při vykreslování obsahu ve scéně.

From 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);

Zpracování pohledu a zadávání gest

Pohled a zadávání rukou nejsou založené na čase a nemusí se aktualizovat ve funkci StepTimer . Tento vstup je však něco, co aplikace potřebuje podívat na každý snímek.

Zpracování aktualizací na základě času

Každá aplikace pro vykreslování v reálném čase bude potřebovat nějaký způsob zpracování aktualizací založených na čase – šablona aplikace Pro Windows Holographic používá implementaci StepTimer , podobně jako stepTimer poskytovaný v šabloně aplikace DirectX 11 pro UPW. Tato ukázková pomocná třída StepTimer může poskytovat aktualizace s pevnými časovými kroky, aktualizace proměnných časových kroků a výchozím režimem jsou kroky s proměnným časem.

U holografického vykreslování jsme se rozhodli do funkce časovače nevkládat příliš mnoho, protože ji můžete nakonfigurovat jako krok s pevným časem. U některých snímků může být volána více než jednou – nebo vůbec – a aktualizace holografických dat by měla proběhnout jednou pro každý snímek.

Z AppMain::Update:

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

Umístění a otočení hologramů v souřadnicové soustavě

Pokud pracujete v jednom souřadnicovém systému, stejně jako to dělá šablona s SpatialStationaryReferenceFrame, tento proces se neliší od toho, na co jste zvyklí v 3D grafikách. Zde otočíme datovou krychli a nastavíme matici modelu na základě pozice ve statickém souřadnicovém systému.

Z 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));

Poznámka k pokročilým scénářům: Rotující datová krychle je jednoduchým příkladem umístění hologramu v rámci jednoho referenčního rámce. Ve stejném vykresleném rámci je také možné současně použít více systémů SpatialCoordinateSystems .

Aktualizace dat konstantní vyrovnávací paměti

Transformace modelu pro obsah se aktualizují jako obvykle. Teď budete mít vypočítané platné transformace pro souřadnicový systém, ve který budete vykreslovat.

Z SpinningCubeRenderer::Update:

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

A co transformace zobrazení a projekce? Abychom získali co nejlepší výsledky, chceme počkat, až budeme téměř připraveni na naše volání do losování, než je získáme.

Vykreslení aktuálního snímku

Vykreslování na Windows Mixed Reality se příliš neliší od vykreslování na 2D mono monitoru, ale existuje několik rozdílů:

  • Predikce holografického rámce jsou důležité. Čím blíže bude předpověď při prezentování rámce, tím lépe budou hologramy vypadat.
  • Windows Mixed Reality řídí zobrazení kamery. Vykreslujte je pro každou z nich, protože holografický rámec vám je bude prezentovat později.
  • Doporučujeme provést stereokreslení pomocí instančovaného kreslení do cílového pole vykreslení. Šablona holografické aplikace používá doporučený přístup instančněného kreslení k cílovému poli vykreslení, které používá zobrazení cíle vykreslení na Texture2DArray.
  • Pokud chcete vykreslit bez použití stereo instancengu, budete muset vytvořit dva objekty RenderTargetView bez pole, jeden pro každé oko. Každý RenderTargetViews odkazuje na jeden ze dvou řezů v Texture2DArray poskytnuté aplikaci ze systému. To se nedoporučuje, protože je obvykle pomalejší než použití instance.

Získání aktualizované předpovědi HolographicFrame

Aktualizace predikce rámce zvyšuje efektivitu stabilizace obrazu. Přesnější umístění hologramů získáte z důvodu kratší doby mezi predikcí a zobrazením rámce pro uživatele. V ideálním případě těsně před vykreslením aktualizujte predikci rámce.

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

Vykreslit na každou kameru

Smyčka na sadě pozic kamery v predikci a vykreslení pro každou kameru v této sadě.

Nastavení vykreslovacího průchodu

Windows Mixed Reality používá stereoskopické vykreslování ke zvýšení iluze hloubky a k stereoskopickému vykreslení, takže levý i pravý displej jsou aktivní. Při stereoskopickém vykreslování je mezi dvěma displeji posun, který mozek dokáže sladit jako skutečnou hloubku. Tato část popisuje stereoskopické vykreslování pomocí instanceng s využitím kódu ze šablony aplikace Windows Holographic.

Každá kamera má vlastní cíl vykreslování (zadní vyrovnávací paměť) a matice zobrazení a projekce do holografického prostoru. Vaše aplikace bude muset vytvořit všechny další prostředky založené na fotoaparátech – například hloubkovou vyrovnávací paměť – pro jednotlivé kamery. V šabloně aplikace Windows Holographic poskytujeme pomocnou třídu, která tyto prostředky spojí dohromady v DX::CameraResources. Začněte nastavením cílových zobrazení vykreslování:

Z 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);

Použití předpovědi k získání matic zobrazení a projekce pro kameru

Matice zobrazení a projekce pro každou holografickou kameru se budou měnit s každým snímkem. Aktualizujte data v konstantní vyrovnávací paměti pro každou holografickou kameru. Udělejte to po aktualizaci předpovědi a před tím, než provedete volání pro tuto kameru.

Z 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);

Tady si ukážeme, jak jsou matice získány z pozice fotoaparátu. Během tohoto procesu získáme také aktuální zobrazení kamery. Všimněte si, jak poskytujeme souřadnicový systém: jedná se o stejný souřadnicový systém, který jsme použili k pochopení pohledu, a stejný systém, který jsme použili k umístění otáčející se datové krychle.

From 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))
    );
}

Zobrazení by mělo být nastaveno pro každý snímek. Shader vrcholů (alespoň) bude obecně potřebovat přístup k datům zobrazení nebo projekce.

From 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()
);

Vykreslujte do zpětné vyrovnávací paměti kamery a potvrďte vyrovnávací paměť hloubky:

Než se pokusíte použít data zobrazení nebo projekce, je vhodné zkontrolovat, jestli byl příkaz TryGetViewTransform úspěšný, protože pokud souřadnicový systém není vyhledatelný (například sledování bylo přerušeno), aplikace ho nemůže pro daný rámec vykreslit. Šablona volá vykreslení pouze na rotující datové krychli, pokud třída CameraResources označuje úspěšnou aktualizaci.

Windows Mixed Reality obsahuje funkce pro stabilizaci obrazu, které udržují hologramy umístěné tam, kde je vývojář nebo uživatel umístí na světě. Stabilizace obrázku pomáhá skrýt latenci, která je součástí vykreslovacího kanálu, aby se zajistilo nejlepší holografické prostředí pro uživatele. Je možné zadat zaostřovací bod, který ještě více zlepší stabilizaci obrazu, nebo může být k dispozici hloubková vyrovnávací paměť pro výpočet optimalizované stabilizace obrazu v reálném čase.

Nejlepších výsledků dosáhnete, když vaše aplikace poskytne hloubkovou vyrovnávací paměť pomocí rozhraní API CommitDirect3D11DepthBuffer . Windows Mixed Reality pak mohou pomocí informací o geometrii z hloubkové vyrovnávací paměti optimalizovat stabilizaci obrazu v reálném čase. Šablona aplikace Windows Holographic ve výchozím nastavení potvrdí hloubkovou vyrovnávací paměť aplikace, což pomáhá optimalizovat stabilitu hologramu.

Z 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);
    }
}

Poznámka

Systém Windows zpracuje hloubkovou texturu na GPU, takže musí být možné použít hloubkovou vyrovnávací paměť jako prostředek shaderu. ID3D11Texture2D, který vytvoříte, by měl být v beztypovém formátu a měl by být svázán jako zobrazení prostředků shaderu. Tady je příklad, jak vytvořit texturu hloubky, kterou je možné potvrdit pro stabilizaci obrazu.

Kód pro vytvoření prostředku hloubkové vyrovnávací paměti pro 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
    ));

Kreslení holografického obsahu

Šablona aplikace Windows Holographic vykresluje obsah stereo pomocí doporučené techniky kreslení instance geometrie texture2DArray velikosti 2. Podívejme se na část s vytvářením instancí a na to, jak funguje na Windows Mixed Reality.

Z 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.
);

Každá instance přistupuje k jiné matici zobrazení/projekce z konstantní vyrovnávací paměti. Tady je struktura konstantní vyrovnávací paměti, která je pouze polem dvou matic.

Z vertexShaderShared.hlsl, který obsahuje 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];
};

Index cílového pole vykreslení musí být nastaven pro každý pixel. V následujícím fragmentu kódu se output.viewId mapuje na sémantickou SV_RenderTargetArrayIndex . To vyžaduje podporu volitelné funkce Direct3D 11.3, která umožňuje nastavit sémantiku indexu cílového pole vykreslování z jakékoli fáze shaderu.

Z 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;
};

Z vertexShaderShared.hlsl, který obsahuje 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;
}

Pokud chcete použít existující techniky kreslení instance s touto metodou kreslení do cílového pole stereo vykreslování, nakreslete dvakrát více instancí, než obvykle máte. V shaderu vydělte input.instId 2, abyste získali ID původní instance, které je možné indexovat (například) do vyrovnávací paměti dat jednotlivých objektů: int actualIdx = input.instId / 2;

Důležitá poznámka k vykreslování stereo obsahu na HoloLensu

Windows Mixed Reality podporuje možnost nastavit index cílového pole vykreslení z jakékoli fáze shaderu. Za normálních okolností jde o úlohu, kterou je možné provést pouze ve fázi shaderu geometrie, protože je definována sémantika pro Direct3D 11. Tady si ukážeme úplný příklad, jak nastavit vykreslovací kanál pouze s nastavenými fázemi shaderu vrcholu a pixelu. Kód shaderu je, jak je popsáno výše.

Z 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.
);

Důležitá poznámka k vykreslování na jiných zařízeních než HoloLens

Nastavení indexu cílového pole vykreslení v shaderu vrcholů vyžaduje, aby ovladač grafického adaptéru podporoval volitelnou funkci Direct3D 11.3, kterou HoloLens podporuje. Vaše aplikace může bezpečně implementovat právě tuto techniku vykreslování a budou splněny všechny požadavky pro spuštění na Microsoft HoloLens.

Může se stát, že budete chtít použít i emulátor HoloLensu, který může být výkonným vývojovým nástrojem pro holografickou aplikaci – a podporovat Windows Mixed Reality imerzivní náhlavní soupravy připojené k počítačům Windows 10. Do šablony aplikace Holographic pro Windows je také integrovaná podpora cesty vykreslování jiných než HoloLens – pro všechny Windows Mixed Reality. V kódu šablony najdete kód, který umožní spuštění holografické aplikace na GPU ve vývojovém počítači. Tady je postup, jak třída DeviceResources kontroluje podporu této volitelné funkce.

From 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;
}

Aby vaše aplikace podporovala vykreslování bez této volitelné funkce, musí k nastavení indexu cílového pole vykreslení použít shader geometrie. Tento fragment kódu by se přidal zaVSSetConstantBuffers a předPSSetShader v příkladu kódu uvedeném v předchozí části, který vysvětluje, jak vykreslit stereo na HoloLensu.

Z 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
    );
}

POZNÁMKA HLSL: V tomto případě musíte také načíst mírně upravený shader vrcholu, který předá index cílového pole vykreslení do shaderu geometrie pomocí vždy povolené sémantické shaderu, například TEXCOORD0. Shader geometrie nemusí provádět žádnou práci; shader geometrie šablony prochází všemi daty s výjimkou indexu cílového pole vykreslení, který se používá k nastavení SV_RenderTargetArrayIndex sémantické.

Kód šablony aplikace pro 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);
    }
}

Přítomen

Povolení holografického rámce pro prezentaci řetězce výměny

S Windows Mixed Reality řídí systém řetěz výměny. Systém pak spravuje prezentaci snímků pro každou holografickou kameru, aby se zajistilo vysoce kvalitní uživatelské prostředí. Poskytuje také aktualizaci oblasti zobrazení jednotlivých snímků pro každou kameru, aby se optimalizovaly aspekty systému, jako je stabilizace obrazu nebo Mixed Reality Capture. Holografická aplikace využívající DirectX tedy nevolá Funkci Present v řetězci výměn DXGI. Místo toho použijete třídu HolographicFrame k zobrazení všech swapchains pro rámec, jakmile ho dokončíte kreslení.

From DeviceResources::P resent:

HolographicFramePresentResult presentResult = frame.PresentUsingCurrentPrediction();

Ve výchozím nastavení toto rozhraní API čeká na dokončení rámce, než se vrátí. Holografické aplikace by měly před zahájením práce na novém snímku počkat na dokončení předchozího snímku, protože se tím snižuje latence a umožňují lepší výsledky predikcí holografických snímků. Toto není pevné pravidlo, a pokud máte snímky, u kterých trvá déle než jedna aktualizace obrazovky, můžete toto čekání zakázat předáním parametru HolographicFramePresentWaitBehavior do presentUsingCurrentPrediction. V takovém případě byste pravděpodobně použili asynchronní vykreslovací vlákno k udržování nepřetržitého zatížení GPU. Obnovovací frekvence zařízení HoloLens je 60 Hz, přičemž jeden snímek má dobu trvání přibližně 16 ms. Imerzivní sluchátka s mikrofonem mohou být v rozsahu od 60 Hz do 90 Hz; při aktualizaci displeje při frekvenci 90 Hz bude mít každý snímek dobu trvání přibližně 11 ms.

Zpracování scénářů DeviceLost ve spolupráci s HolographicFrame

Aplikace DirectX 11 obvykle chtějí zkontrolovat hresult vrácenou funkcí Present swap chain DXGI, aby zjistily, jestli nedošlo k chybě DeviceLost . HolographicFrame Třída to zpracuje za vás. Zkontrolujte vrácený HolographicFramePresentResult a zjistěte, jestli potřebujete uvolnit a znovu vytvořit zařízení Direct3D a prostředky založené na zařízeních.

// 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();
}

Pokud došlo ke ztrátě zařízení Direct3D a vytvořili jste ho znovu, musíte holographicSpace informovat, aby nové zařízení začala používat. Řetěz prohození se pro toto zařízení vytvoří znovu.

From DeviceResources::InitializeUsingHolographicSpace:

m_holographicSpace.SetDirect3D11Device(m_d3dInteropDevice);

Po zobrazení rámce se můžete vrátit zpět do smyčky hlavního programu a povolit, aby pokračoval k dalšímu snímku.

Hybridní grafické počítače a aplikace hybridní reality

Windows 10 Creators Update počítače je možné nakonfigurovat s diskrétními i integrovanými grafickými procesory. U těchto typů počítačů systém Windows zvolí adaptér, ke kterému je náhlavní souprava připojená. Aplikace musí zajistit, aby zařízení DirectX, které vytvoří, používalo stejný adaptér.

Většina obecného ukázkového kódu rozhraní Direct3D ukazuje vytvoření zařízení DirectX pomocí výchozího hardwarového adaptéru, který v hybridním systému nemusí být stejný jako ten, který se používá pro náhlavní soupravu.

Chcete-li vyřešit problémy, použijte HolographicAdapterID z holographicSpace. PrimaryAdapterId() nebo HolographicDisplay. AdapterId(). Toto adapterId se pak dá použít k výběru správného DXGIAdapter pomocí IDXGIFactory4.EnumAdapterByLuid.

From 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();
}

Kód pro aktualizaci DeviceResources::CreateDeviceResources tak, aby používal 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.
);

Hybridní grafika a Media Foundation

Použití služby Media Foundation v hybridních systémech může způsobit problémy, kdy se video nevykresluje nebo je poškozená textura videa, protože Služba Media Foundation používá výchozí systémové chování. V některých scénářích se pro podporu více vláken vyžaduje vytvoření samostatného zařízení ID3D11Device a nastavení správných příznaků vytváření.

Při inicializaci ID3D11Device musí být příznak D3D11_CREATE_DEVICE_VIDEO_SUPPORT definován jako součást D3D11_CREATE_DEVICE_FLAG. Po vytvoření zařízení a kontextu zavolejte SetMultithreadProtected a povolte multithreading. K přidružení zařízení k MMFDXGIDeviceManager použijte funkci IMFDXGIDeviceManager::ResetDevice .

Kód pro přidružení zařízení ID3D11Device k MMFDXGIDeviceManager:

// 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;

Viz také