Renderelés a DirectX-ben

Megjegyzés

Ez a cikk az örökölt WinRT natív API-kkal kapcsolatos. Új natív alkalmazásprojektekhez az OpenXR API használatát javasoljuk.

Windows Mixed Reality a DirectX-en alapul, hogy gazdag, 3D grafikus élményt nyújtsunk a felhasználóknak. A renderelési absztrakció közvetlenül a DirectX felett helyezkedik el, ami lehetővé teszi az alkalmazások számára a rendszer által előrejelzett holografikus jelenetmegjelenítők pozíciójának és tájolásának okát. A fejlesztő ezután megkeresheti a hologramokat az egyes kamerák alapján, így az alkalmazás ezeket a hologramokat különböző térbeli koordináta-rendszerekben jeleníti meg a felhasználó mozgása során.

Megjegyzés: Ez az útmutató a Direct3D 11-ben történő holografikus renderelést ismerteti. A Direct3D 12 Windows Mixed Reality alkalmazássablont is tartalmazza a Mixed Reality alkalmazássablonok bővítmény.

Frissítés az aktuális kerethez

A hologramok alkalmazásállapotának frissítéséhez keretenként egyszer az alkalmazás a következőket fogja tenni:

  • HolographicFrame lekérése a kijelzőkezelő rendszerből.
  • Frissítse a jelenetet az aktuális előrejelzéssel, hogy hol lesz a kameranézet a renderelés befejezésekor. Ne feledje, hogy a holografikus jelenethez több kamera is lehet.

A holografikus kameranézetek megjelenítéséhez az alkalmazás keretenként egyszer a következőket fogja tenni:

  • Minden kamera esetében renderelje az aktuális keret jelenetét a kameranézet és a rendszer vetítési mátrixainak használatával.

Új holografikus keret létrehozása és előrejelzése

A HolographicFrame olyan információkkal rendelkezik, amelyeket az alkalmazásnak frissítenie és renderelnie kell az aktuális keretben. Az alkalmazás az új kereteket a CreateNextFrame metódus meghívásával kezdi. A metódus meghívásakor az előrejelzések a legújabb elérhető érzékelőadatokkal jönnek létre, és az CurrentPrediction objektumba vannak beágyazva.

Minden renderelt kerethez új keretobjektumot kell használni, mivel az csak egy pillanat alatt érvényes. A CurrentPrediction tulajdonság olyan információkat tartalmaz, mint a kamera helyzete. Az információk arra az időpontra lesznek extrapolálva, amikor a keret várhatóan látható lesz a felhasználó számára.

A következő kód az AppMain::Update fájlból származik:

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

Kamerafrissítések feldolgozása

A háttérpufferek keretről keretre válthatnak. Az alkalmazásnak ellenőriznie kell az egyes kamerák háttérpufferét, és szükség szerint fel kell szabadítenie és újra létre kell hoznia az erőforrásnézeteket és a mélységi puffereket. Figyelje meg, hogy az előrejelzésben szereplő pózok halmaza az aktuális keretben használt kamerák mérvadó listája. Általában ezzel a listával iterálhat a kamerák halmazán.

Az AppMain::Update fájlból:

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

A leképezés alapjául szolgáló koordinátarendszer lekérése

Windows Mixed Reality lehetővé teszi, hogy az alkalmazás különböző koordinátarendszereket hozzon létre, például csatolt és helyhez kötött referenciakereteket a fizikai világ helyeinek nyomon követéséhez. Az alkalmazás ezután ezeket a koordinátarendszereket használva meg tudja indokolni, hogy hol jelenjenek meg a hologramok az egyes kereteken. Amikor koordinátákat kér egy API-tól, mindig azt a SpatialCoordinateSystemet adja meg, amelyen belül meg szeretné fejezni ezeket a koordinátákat.

Az AppMain::Update fájlból:

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

Ezek a koordinátarendszerek ezután sztereó nézet mátrixok létrehozására használhatók a jelenetben lévő tartalom renderelésekor.

A CameraResources::UpdateViewProjectionBuffer fájlból:

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

Folyamat tekintete és kézmozdulat bemenete

A tekintet és a kézi bevitel nem időalapú, és nem kell frissítenie a StepTimer függvényben. Ezt a bemenetet azonban az alkalmazásnak meg kell néznie az egyes kereteket.

Időalapú frissítések feldolgozása

Minden valós idejű renderelő alkalmazásnak szüksége lesz valamilyen módon az időalapú frissítések feldolgozására – a Windows Holographic alkalmazássablon a DirectX 11 UWP-alkalmazássablonban megadott StepTimer-implementációhoz hasonló StepTimer-implementációt használ. Ez a StepTimer-minta segédosztály rögzített időlépés-frissítéseket, változó időlépés-frissítéseket, az alapértelmezett mód pedig a változó időlépések.

A holografikus megjelenítéshez úgy döntöttünk, hogy nem helyezünk túl sokat az időzítőfüggvénybe, mert konfigurálható rögzített időlépésként. Előfordulhat, hogy a rendszer keretenként többször is meghívja – vagy egyáltalán nem – bizonyos keretek esetében, és a holografikus adatok frissítésének keretenként egyszer kell történnie.

Az AppMain::Update fájlból:

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

Hologramok elhelyezése és elforgatása a koordinátarendszerben

Ha egyetlen koordinátarendszerben dolgozik, ahogyan a sablon a SpatialStationaryReferenceFrame-ben is, ez a folyamat nem tér el attól, amit egyébként a 3D ábrákban használt. Itt elforgatjuk a kockát, és beállítjuk a modellmátrixot a helyhez kötött koordinátarendszer pozíciója alapján.

Forrás: 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));

Vegye figyelembe a speciális forgatókönyveket: A forgó kocka egy egyszerű példa arra, hogyan helyezhet el egy hologramot egyetlen referenciakereten belül. Egyszerre több SpatialCoordinateSystems is használható ugyanabban a renderelt keretben.

Állandó pufferadatok frissítése

A tartalom modellátalakításai a szokásos módon frissülnek. Mostanra már érvényes átalakításokat fog kiszámolni ahhoz a koordinátarendszerhez, amelyben renderelni fog.

Forrás: SpinningCubeRenderer::Update:

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

Mi a helyzet a nézet- és leképezési átalakításokkal? A legjobb eredmény érdekében szeretnénk megvárni, amíg majdnem készen állunk a hívásra, mielőtt megkapjuk ezeket.

Az aktuális keret renderelése

A Windows Mixed Reality renderelése nem sokban különbözik a 2D mono kijelzőn való megjelenítéstől, de van néhány különbség:

  • A holografikus keret előrejelzései fontosak. Minél közelebb van az előrejelzés a keret megjelenéséhez, annál jobb lesz a hologramok megjelenése.
  • Windows Mixed Reality szabályozza a kameranézeteket. Renderelje mindegyikre, mert a holografikus keret később bemutatja őket.
  • Javasoljuk, hogy használjon sztereó renderelést példányos rajz használatával egy renderelési céltömbhöz. A holografikus alkalmazássablon a példányos rajz javasolt megközelítését használja egy renderelési céltömbhöz, amely renderelési célnézetet használ a Texture2DArray-ra.
  • Ha sztereó instancing használata nélkül szeretne renderelni, két nem tömbből álló RenderTargetView-t kell létrehoznia, egyet minden szemhez. Minden RenderTargetViews a rendszerből az alkalmazásnak biztosított Texture2DArray két szeletének egyikére hivatkozik. Ez nem ajánlott, mivel általában lassabb, mint az instancing használata.

Frissített HolographicFrame-előrejelzés lekérése

A keret előrejelzésének frissítése növeli a képstabilizálás hatékonyságát. A hologramok pontosabb elhelyezését az előrejelzés közötti rövidebb idő és a felhasználó számára látható keret miatt érheti el. Ideális esetben közvetlenül a renderelés előtt frissítse a keret előrejelzését.

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

Renderelés minden kamerára

Az előrejelzésben a kamera halmazának ismétlése, majd a halmaz minden kamerájának renderelése.

A renderelési passz beállítása

Windows Mixed Reality sztereoszkopikus renderelést használ a mélység illúziójának javítására és a sztereoszkopikus megjelenítésre, így a bal és a jobb oldali kijelző is aktív. A sztereoszkopikus renderelésnek van egy eltolódása a két kijelző között, amelyet az agy képes összeegyeztetni tényleges mélységként. Ez a szakasz a sztereoszkopikus renderelést mutatja be instancing használatával, a Windows Holographic alkalmazássablonból származó kód használatával.

Minden kamera saját renderelési célhelyet (visszapuffert) és nézet- és vetítési mátrixokat használ a holografikus térbe. Az alkalmazásnak minden más kameraalapú erőforrást – például a mélységi puffert – kameránként kell létrehoznia. A Windows Holographic alkalmazássablonban egy segédosztályt biztosítunk az erőforrások összecsomagolásához a DX::CameraResources fájlban. Először állítsa be a renderelési célnézeteket:

Az AppMain::Render fájlból:

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

Az előrejelzés használatával lekérheti a kamera nézet- és vetítési mátrixait

Az egyes holografikus fényképezőgépek nézet- és vetítési mátrixai minden képkockával változnak. Frissítse az adatokat az egyes holografikus fényképezőgépek állandó pufferében. Ezt az előrejelzés frissítése után és a kamera rajzolása előtt végezze el.

Az AppMain::Render fájlból:

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

Itt bemutatjuk, hogyan szerezték be a mátrixokat a kamera pózból. A folyamat során a kamera aktuális nézetét is beszerezzük. Figyelje meg, hogyan biztosítunk koordinátarendszert: ez ugyanaz a koordinátarendszer, amelyet a tekintet megértéséhez használtunk, és ugyanaz, mint amit a forgó kocka elhelyezéséhez használtunk.

A CameraResources::UpdateViewProjectionBuffer fájlból:

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

A nézetportot minden kerethez be kell állítani. A csúcspontárnyékolónak (legalábbis) általában hozzá kell férnie a nézet-/leképezési adatokhoz.

A CameraResources::AttachViewProjectionBuffer fájlból:

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

Renderelje a kamera hátpufferét, és véglegesítse a mélységi puffert:

Érdemes ellenőrizni, hogy a TryGetViewTransform sikeres volt-e a nézet-/leképezési adatok használata előtt, mert ha a koordinátarendszer nem található (például a nyomon követés megszakadt), akkor az alkalmazás nem tudja megjeleníteni az adott kerethez. A sablon csak akkor hívja meg a Renderet a forgó kockán, ha a CameraResources osztály sikeres frissítést jelez.

Windows Mixed Reality képstabilizálási funkciókat tartalmaz, hogy a hologramok a fejlesztő vagy a felhasználó által a világra helyezve legyenek elhelyezve. A képstabilizálás segít elrejteni a renderelési folyamat késését, hogy a lehető legjobb holografikus élményt biztosítsa a felhasználók számára. Megadható egy fókuszpont a képstabilizálás további javítására, vagy egy mélységi puffer is rendelkezésre állhat a számításra optimalizált képstabilizálás valós idejű kiszámításához.

A legjobb eredmény érdekében az alkalmazásnak mélységi puffert kell biztosítania a CommitDirect3D11DepthBuffer API használatával. Windows Mixed Reality ezután a mélységi puffer geometriai információi alapján valós időben optimalizálhatja a képstabilizálást. A Windows Holographic alkalmazássablon alapértelmezés szerint véglegesíti az alkalmazás mélységi pufferét, ezzel segítve a hologram stabilitásának optimalizálását.

Az AppMain::Render fájlból:

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

Megjegyzés

A Windows feldolgozni fogja a mélységi anyagmintát a GPU-n, ezért lehetővé kell tenni a mélységi puffer használatát árnyékoló erőforrásként. A létrehozott ID3D11Texture2D formátumnak típus nélkülinek kell lennie, és árnyékoló erőforrásnézetként kell kötnie. Íme egy példa a képstabilizáláshoz véglegesített mélységi textúra létrehozására.

A CommitDirect3D11DepthBuffer mélységi puffererőforrás-létrehozásának kódja:

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

Holografikus tartalom rajzolása

A Windows holografikus alkalmazássablonja sztereóban jeleníti meg a tartalmat a példányos geometria 2DArray 2-es méretű Texture2DArray-ra való rajzolásának ajánlott technikája használatával. Nézzük meg ennek instancing részét, és hogy hogyan működik a Windows Mixed Reality.

Forrás : 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.
);

Minden példány egy másik nézet-/leképezési mátrixhoz fér hozzá az állandó puffertől. Íme az állandó pufferstruktúra, amely csak két mátrixból álló tömb.

A VPRTVertexShader.hlsl által tartalmazott VertexShaderShared.hlsl fájlból:

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

A renderelési céltömb indexét minden képponthoz be kell állítani. Az alábbi kódrészletben az output.viewId a SV_RenderTargetArrayIndex szemantikai értékre van leképezve. Ehhez támogatnia kell egy választható Direct3D 11.3-funkciót, amely lehetővé teszi a renderelési céltömb indexének szemantikai beállítását bármely árnyékolószakaszból.

Forrás: 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;
};

A VPRTVertexShader.hlsl által tartalmazott VertexShaderShared.hlsl fájlból:

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

Ha a meglévő példányos rajzi technikákat ezzel a módszerrel szeretné egy sztereó renderelt céltömbre rajzolni, rajzoljon kétszer annyi példányt, mint általában. A shaderben ossza el az input.instId azonosítót 2-vel az eredeti példányazonosító lekéréséhez, amely (például) objektumonkénti adatok pufferébe indexelhető: int actualIdx = input.instId / 2;

Fontos megjegyzés a sztereó tartalmak HoloLensen való renderelésével kapcsolatban

Windows Mixed Reality támogatja a renderelési céltömbindex beállítását bármely árnyékolószakaszból. Ez a feladat általában csak a geometriai árnyékoló fázisban végezhető el, mivel a szemantika a Direct3D 11-hez van definiálva. Itt egy teljes példát mutatunk be arra, hogyan állíthat be renderelési folyamatot csak a csúcspont és a képpontárnyékoló fázisainak beállításával. A shader-kód a fent leírtak szerint történik.

Forrás : 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.
);

Fontos megjegyzés a nem HoloLens-eszközökön történő renderelésről

A renderelési céltömb indexének a csúcsárnyékolóban való beállításához a grafikus illesztőprogramnak támogatnia kell egy választható Direct3D 11.3-funkciót, amelyet a HoloLens támogat. Az alkalmazás biztonságosan implementálhatja ezt a megjelenítési technikát, és minden követelmény teljesül a Microsoft HoloLens való futtatáshoz.

Előfordulhat, hogy a HoloLens emulátort is használni szeretné, amely hatékony fejlesztőeszköz lehet a holografikus alkalmazáshoz, és támogatja Windows Mixed Reality Windows 10 számítógépekhez csatlakoztatott modern headset-eszközöket. A nem HoloLens megjelenítési útvonal támogatása – az összes Windows Mixed Reality esetében – a Windows Holographic alkalmazássablonba is be van építve. A sablonkódban talál egy kódot, amely lehetővé teszi a holografikus alkalmazás futtatását a GPU-n a fejlesztői pc-n. A DeviceResources osztály így ellenőrzi ezt az opcionális funkciótámogatást.

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

Ahhoz, hogy ez a választható funkció nélkül is támogassa a renderelést, az alkalmazásnak geometriai árnyékolóval kell beállítania a renderelési céltömbindexet. Ez a kódrészlet a VSSetConstantBuffersés a PSSetShaderután lesz hozzáadva az előző szakaszban bemutatott kódpéldában, amely elmagyarázza, hogyan renderelhető a sztereó a HoloLensen.

Forrás : 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 MEGJEGYZÉS: Ebben az esetben egy enyhén módosított csúcspontárnyékolót is be kell töltenie, amely a renderelési céltömb indexét egy mindig engedélyezett árnyékoló szemantika használatával adja át a geometriai árnyékolónak, például a TEXCOORD0-nak. A geometriai árnyékolónak nem kell semmilyen munkát végeznie; A sablongeometriai árnyékoló az összes adaton áthalad a renderelési céltömbindex kivételével, amely a SV_RenderTargetArrayIndex szemantikai beállítására szolgál.

A GeometryShader.hlsl alkalmazássablon-kódja:

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

Jelen

A holografikus keret engedélyezése a felcserélési lánc bemutatásához

A Windows Mixed Reality a rendszer vezérli a felcserélési láncot. A rendszer ezután felügyeli a képkockák megjelenítését minden holografikus kamera számára, hogy magas színvonalú felhasználói élményt biztosítson. Emellett minden kamerához biztosít egy nézetportot, hogy optimalizálja a rendszer olyan aspektusait, mint a képstabilizálás vagy a Mixed Reality Capture. A DirectX-et használó holografikus alkalmazások tehát nem hívják meg a Present függvényt egy DXGI-swapláncon. Ehelyett a HolographicFrame osztály használatával jelenítheti meg a keret összes swapláncát, miután elkészült a rajzolással.

From DeviceResources::P resent:

HolographicFramePresentResult presentResult = frame.PresentUsingCurrentPrediction();

Alapértelmezés szerint ez az API megvárja, amíg a keret befejeződik, mielőtt visszatér. A holografikus alkalmazásoknak meg kell várniuk, amíg az előző keret befejeződik, mielőtt megkezdenék a munkát egy új kereten, mivel ez csökkenti a késést, és jobb eredményeket tesz lehetővé a holografikus keret előrejelzéseiből. Ez nem egy kemény szabály, és ha egynél több képernyőfrissítést igénylő kerettel rendelkezik, letilthatja ezt a várakozást, ha a HolographicFramePresentWaitBehavior paramétert átadja az PresentUsingCurrentPrediction paraméternek. Ebben az esetben valószínűleg aszinkron renderelési szálat használna a GPU folyamatos terhelésének fenntartásához. A HoloLens-eszköz frissítési sebessége 60 hz, ahol egy keret időtartama körülbelül 16 ms. A modern mikrofonos fejhallgatók 60 hz és 90 hz közöttiek lehetnek; a kijelző 90 hz-es frissítésekor minden képkocka körülbelül 11 ms időtartamú lesz.

A DeviceLost-forgatókönyvek kezelése a HolographicFrame-el együttműködve

A DirectX 11-alkalmazások általában a DXGI swaplánc Present függvénye által visszaadott HRESULT-t szeretnék ellenőrizni, hogy történt-e DeviceLost-hiba . Ezt a HolographicFrame osztály kezeli. Vizsgálja meg a visszaadott HolographicFramePresentResult fájlt, és állapítsa meg, hogy ki kell-e szabadíttatnia és újra létre kell-e hoznia a Direct3D-eszközt és az eszközalapú erőforrásokat.

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

Ha a Direct3D-eszköz elveszett, és újra létrehozta, meg kell mondania a HolographicSpace-nek , hogy kezdje el használni az új eszközt. A felcserélési lánc újra létrejön ehhez az eszközhöz.

From DeviceResources::InitializeUsingHolographicSpace:

m_holographicSpace.SetDirect3D11Device(m_d3dInteropDevice);

A keret bemutatása után visszatérhet a fő programhurkhoz, és folytathatja a következő kerettel.

Hibrid grafikus pc-k és vegyes valósági alkalmazások

Windows 10 alkotói frissítés számítógépek különálló és integrált GPU-kkal is konfigurálhatók. Az ilyen típusú számítógépek esetében a Windows kiválasztja azt az adaptert, amelyhez a headset csatlakoztatva van. Az alkalmazásoknak gondoskodniuk kell arról, hogy az általa létrehozott DirectX-eszköz ugyanazt az adaptert használja.

A legtöbb általános Direct3D-mintakód bemutatja, hogyan hozhat létre DirectX-eszközt az alapértelmezett hardveradapterrel, amely hibrid rendszeren nem feltétlenül egyezik meg a headsethez használttal.

Az esetleges problémák megoldásához használja a HolographicSpace HolographicAdapterID azonosítóját. PrimaryAdapterId() vagy HolographicDisplay. AdapterId(). Ez az adapterId ezután a megfelelő DXGIAdapter kiválasztására használható az IDXGIFactory4.EnumAdapterByLuid paranccsal.

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 a DeviceResources frissítéséhez::CreateDeviceResources az IDXGIAdapter használatához

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

Hibrid grafikák és Media Foundation

A Media Foundation hibrid rendszereken való használata problémákat okozhat, ha a videó nem jelenik meg, vagy a videó textúra sérült, mert a Media Foundation alapértelmezés szerint rendszerviselkedést alkalmaz. Bizonyos esetekben külön ID3D11Device létrehozása szükséges a többszálúság támogatásához, és a megfelelő létrehozási jelzők be vannak állítva.

Az ID3D11Device inicializálásakor D3D11_CREATE_DEVICE_VIDEO_SUPPORT jelzőt a D3D11_CREATE_DEVICE_FLAG részeként kell definiálni. Az eszköz és a környezet létrehozása után hívja meg a SetMultithreadProtected parancsot a többszálúság engedélyezéséhez. Ha az eszközt az IMFDXGIDeviceManagerhez szeretné társítani, használja az IMFDXGIDeviceManager::ResetDevice függvényt .

Az ID3D11Device és az IMFDXGIDeviceManager társítására használható kód:

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

Lásd még