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;