Vykreslování v DirectX
Poznámka:
Tento článek se týká starších nativních rozhraní API WinRT. Pro nové nativní projekty aplikací doporučujeme použít rozhraní API OpenXR.
Windows Mixed Reality je založená na DirectX a poskytuje bohaté 3D grafické prostředí pro uživatele. Abstrakce vykreslování se nachází těsně nad Rozhraním DirectX, což umožňuje aplikacím zdůvodnění pozice a orientace pozorovatelů holografických scén, které systém predikoval. Vývojář pak může vyhledat své hologramy na základě jednotlivých fotoaparátů 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 pro Windows Mixed Reality je také dodávána s rozšířením šablon aplikací hybridní reality.
Aktualizace aktuálního rámce
Pokud chcete aktualizovat stav aplikace pro hologramy, jednou za rámec aplikace:
- Získejte HolographicFrame ze systému správy zobrazení.
- Aktualizujte scénu s aktuální predikcí místa, kde bude zobrazení fotoaparátu po dokončení vykreslení. Všimněte si, že pro holografickou scénu může existovat více než jedna kamera.
Pokud chcete vykreslit zobrazení holografické kamery, jednou za snímek bude aplikace:
- 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 aktualizovat a vykreslit aktuální rámec. Aplikace začíná každý nový rámec voláním CreateNextFrame metoda. Při zavolání této metody se předpovědi provádějí pomocí nejnovějších dostupných dat snímačů a zapouzdřené do objektu CurrentPrediction .
Pro každý vykreslovaný snímek musí být použit nový objekt rámce, protože je platný pouze pro okamžik v čase. Vlastnost CurrentPrediction obsahuje informace, jako je umístění kamery. Informace se extrapolují na přesný okamžik v čase, kdy se očekává, že bude snímek viditelný pro uživatele.
Z AppMain::Update se zobrazí následující kód:
// 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
Vyrovnávací paměti zpět se můžou změnit z rámce na rámec. Aplikace musí ověřit 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 predikce představuje autoritativní seznam fotoaparátů používaných v aktuálním rámečku. Tento seznam obvykle používáte k iteraci na sadě fotoaparátů.
Z AppMain::Update:
m_deviceResources->EnsureCameraResources(holographicFrame, prediction);
Z 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 vaší aplikaci vytvářet různé souřadnicové systémy, jako jsou připojené a statické referenční rámce pro sledování umístění ve fyzickém světě. Aplikace pak může tyto souřadnicové systémy použít k odůvodnění, kde vykreslit hologramy jednotlivých snímků. Když požadujete souřadnice z rozhraní API, vždy předáte 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 k vygenerování matic stereo zobrazení při vykreslování obsahu ve scéně.
Z 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 ruční vstup nejsou založené na čase a nemusí se aktualizovat ve funkci StepTimer . Tento vstup je ale něco, co aplikace potřebuje prohlédnout každý rámec.
Zpracování aktualizací založených na čase
Každá vykreslovací aplikace 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 UPW. Tato pomocná třída pomocné rutiny StepTimer může poskytovat pevné aktualizace časového kroku, aktualizace proměnných časových kroků a výchozí režim je proměnlivý časový postup.
V případě holografického vykreslování jsme se rozhodli, že se do funkce časovače příliš nezadá, protože ho můžete nakonfigurovat jako krok s pevným časem. U některých snímků se může volat více než jednou za rámec ( nebo vůbec vůbec) a aktualizace holografických dat by se měly na každý rámec nacházet jednou.
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, protože šablona funguje s SpatialStationaryReferenceFrame, tento proces se neliší od toho, na co jste jinak zvyklí v 3D grafikách. Tady otočíme datovou krychli a nastavíme matici modelu na základě pozice v 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 představuje jednoduchý příklad umístění hologramu v rámci jednoho referenčního rámce. Současně je také možné použít více systémů SpatialCoordinateSystems ve stejném vykresleném rámečku.
Aktualizace dat konstantní vyrovnávací paměti
Transformace modelů pro obsah se aktualizují obvyklým způsobem. 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 nejlepší výsledky, chceme počkat, až budeme skoro připraveni na naše hovory na losování, než je získáme.
Vykreslení aktuálního rámce
Vykreslování ve Windows Mixed Reality se moc neliší od vykreslování na 2D mono displeji, ale existuje několik rozdílů:
- Predikce holografických snímků jsou důležité. Čím blíž je predikce při prezentování snímku, tím lépe budou hologramy vypadat.
- Windows Mixed Reality řídí zobrazení fotoaparátu. Vykreslujte je pro každou z nich, protože holografický rámeček je bude prezentovat později.
- Stereo vykreslování doporučujeme pomocí vykresleného výkresu použít k vykreslení cílového pole. Šablona holografické aplikace používá doporučený přístup při vykreslování výkresu k cílovému poli vykreslení, který používá zobrazení cíle vykreslení na Texture2DArray.
- Pokud chcete vykreslit bez použití stereo instanceng, budete muset vytvořit dvě nematicové RenderTargetViews, jednu pro každé oko. Každý RenderTargetViews odkazuje na jeden ze dvou řezů v Texture2DArray poskytnuté aplikaci ze systému. Tento postup 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 obrázků. 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ě před vykreslováním aktualizujte predikci snímků.
holographicFrame.UpdateCurrentPrediction();
HolographicFramePrediction prediction = holographicFrame.CurrentPrediction();
Vykreslení na každou kameru
Smyčka na sadě fotoaparátů představuje v předpovědích a vykresluje se pro každou kameru v této sadě.
Nastavení průchodu vykreslování
Windows Mixed Reality používá stereoskopické vykreslování k vylepšení iluze hloubky a vykreslení stereoskopicky, takže levý i pravý displej jsou aktivní. Při stereoskopickém vykreslování je mezi těmito dvěma displeji posun, který může mozek odsouhlasit jako skutečnou hloubku. Tato část popisuje stereoskopické vykreslování pomocí vytváření instancí pomocí kódu ze šablony aplikace Pro Windows Holographic.
Každá kamera má svůj vlastní cíl vykreslení (vyrovnávací paměť) a zobrazení a projekce matice do holografického prostoru. Vaše aplikace bude muset na základě kamery vytvořit další prostředky založené na fotoaparátu, jako je například vyrovnávací paměť hloubky. V šabloně aplikace pro Windows Holographic poskytujeme pomocnou třídu, která tyto prostředky spojí dohromady v DX::CameraResources. Začněte nastavením cílových zobrazení vykreslení:
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);
Pomocí předpovědi získáte matice zobrazení a projekce pro kameru.
Matice zobrazení a projekce pro každou holografickou kameru se změní 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 provedením jakýchkoli volání kreslení pro danou 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);
Zde si ukážeme, jak se matice získávají z pozice kamery. Během tohoto procesu také získáme aktuální zobrazení fotoaparátu. Všimněte si, jak poskytujeme souřadnicový systém: jedná se o stejný souřadnicový systém, který jsme použili k pochopení pohledů, a je to stejný systém, který jsme použili k umístění rotující datové krychle.
Z 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))
);
}
Každý rámec by měl být nastaven na oblast zobrazení. Váš vrchol shader (alespoň) bude obecně potřebovat přístup k datům zobrazení/projekce.
Z 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 vyrovnávací paměti fotoaparátu zpět a potvrďte hloubkovou vyrovnávací paměť:
Než se pokusíte použít data zobrazení nebo projekce, je vhodné zkontrolovat, jestli byl TryGetViewTransform úspěšný, protože pokud souřadnicový systém není lokovatelný (například sledování bylo přerušeno), nemůže se s ním aplikace vykreslit pro daný rámec. Šablona volá pouze render na rotující krychli, pokud cameraResources třída indikuje úspěšnou aktualizaci.
Windows Mixed Reality obsahuje funkce pro stabilizaci obrázků, aby byly hologramy umístěné tam, kde je vývojář nebo uživatel umístí do světa. Stabilizace obrázků pomáhá skrýt latenci, která je součástí kanálu vykreslování, aby se zajistilo nejlepší holografické prostředí pro uživatele. Bod fokusu může být určen k vylepšení stabilizace obrazu ještě více, nebo je možné poskytnout vyrovnávací paměť hloubky pro výpočet optimalizované stabilizace obrázků v reálném čase.
Pro zajištění nejlepších výsledků by vaše aplikace měla poskytnout hloubkovou vyrovnávací paměť pomocí rozhraní CommitDirect3D11DepthBuffer API. Windows Mixed Reality pak může pomocí informací o geometrii z hloubkové vyrovnávací paměti optimalizovat stabilizaci obrázků v reálném čase. Šablona aplikace Pro Windows Holographic ve výchozím nastavení potvrdí hloubkovou vyrovnávací paměť aplikace a 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 vyrovnávací paměť hloubky jako prostředek shaderu. Id3D11Texture2D, který vytvoříte, by měl být v beztypovém formátu a měl by být vázán jako zobrazení prostředků shaderu. Tady je příklad vytvoření hloubkové textury, kterou lze potvrdit pro stabilizaci obrázků.
Kód pro vytvoření prostředku vyrovnávací paměti hloubky 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 Pro Windows Holographic vykresluje obsah stereo pomocí doporučené techniky vykreslování instance geometrie na Texture2DArray velikosti 2. Pojďme se podívat na část této instance a na to, jak funguje ve 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, což je pouze pole dvou matic.
Od 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émantický SV_RenderTargetArrayIndex. To vyžaduje podporu volitelné funkce Direct3D 11.3, která umožňuje nastavení sémantického 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;
};
Od 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 pomocí této metody kreslení použít existující techniky vykreslování na cílové pole stereo vykreslování, nakreslete dvakrát počet instancí, které obvykle máte. V shaderu vydělte input.instId 2, abyste získali PŮVODNÍ ID instance, které lze indexovat do vyrovnávací paměti dat pro jednotlivé objekty: int actualIdx = input.instId / 2;
Důležitá poznámka k vykreslování stereo obsahu na HoloLens
Windows Mixed Reality podporuje možnost nastavit index cílového pole vykreslování z jakékoli fáze shaderu. Obvykle se jedná o úlohu, která by mohla být provedena pouze ve fázi shaderu geometrie kvůli způsobu, jakým je sémantika definována pro Direct3D 11. Tady si ukážeme úplný příklad nastavení vykreslovacího kanálu s nastavenými fázemi vrcholu a pixelového shaderu. Kód shaderu je popsaný 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 vykreslování v shaderu vrcholů vyžaduje, aby grafický ovladač podporoval volitelnou funkci Direct3D 11.3, kterou HoloLens podporuje. Vaše aplikace může bezpečně implementovat pouze tuto techniku vykreslování a všechny požadavky budou splněny pro spuštění v Microsoft HoloLensu.
Může se jednat o případ, že chcete použít také emulátor HoloLensu, což může být výkonný vývojový nástroj pro vaši holografickou aplikaci – a podporovat imerzivní náhlavní soupravy Windows Mixed Reality, která jsou připojená k počítačům s Windows 10. Podpora cesty vykreslování mimo HoloLens – pro všechny windows Mixed Reality – je také integrovaná do šablony aplikace Pro Windows Holographic. V kódu šablony najdete kód, který umožní holografické aplikaci běžet na GPU ve vývojovém počítači. Tady je postup, jak třída DeviceResources kontroluje podporu této volitelné funkce.
Z 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 aplikace podporovala vykreslování bez této volitelné funkce, musí k nastavení indexu cílového pole vykreslování použít shader geometrie. Tento fragment kódu by se přidal za VSSetConstantBuffers a před PSSetShader v příkladu kódu uvedeném v předchozí části, který vysvětluje, jak vykreslit stereo na HoloLens.
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
);
}
HLSL POZNÁMKA: V tomto případě musíte také načíst mírně upravený vrchol shader, který předává index cílového pole vykreslení do shaderu geometrie pomocí vždy povolené sémantiky 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ý slouží 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);
}
}
Současnost
Povolení holografického rámce k prezentaci řetězu prohození
V systému Windows Mixed Reality systém řídí řetěz prohození. Systém pak spravuje prezentace snímků pro každou holografickou kameru, aby se zajistilo vysoce kvalitní uživatelské prostředí. Poskytuje také aktualizaci pohledu každý snímek pro každou kameru, aby optimalizoval aspekty systému, jako je stabilizace obrazu nebo Mixed Reality Capture. Holografická aplikace využívající DirectX tedy nevolá funkci Prezentovat v řetězci prohození DXGI. Místo toho použijete třídu HolographicFrame k prezentaci všech prohození pro rámeček, jakmile ho nakreslete.
Z 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 rámce, protože tím se snižuje latence a umožňuje lepší výsledky předpovědí holografických snímků. Nejedná se o pevné pravidlo a pokud máte snímky, které se vykreslují déle než jedna aktualizace obrazovky, můžete toto čekání zakázat předáním parametru HolographicFramePresentBehavior do PresentUsingCurrentPrediction. V takovém případě byste pravděpodobně použili asynchronní vykreslovací vlákno k zachování průběžného zatížení GPU. Frekvence aktualizace zařízení HoloLens je 60 hz, kde jeden rámec 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 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í Prezentačního řetězce DXGI a zjistit, jestli došlo k chybě DeviceLost. Třída HolographicFrame to za vás zpracovává. 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 vy jste ho vytvořili znovu, musíte informovat HolographicSpace , aby začal používat nové zařízení. Řetězec prohození se pro toto zařízení znovu vytvoří.
Z DeviceResources::InitializeUsingHolographicSpace:
m_holographicSpace.SetDirect3D11Device(m_d3dInteropDevice);
Jakmile se snímek zobrazí, můžete se vrátit zpět do hlavní smyčky programu a povolit mu pokračovat k dalšímu snímku.
Hybridní grafické počítače a aplikace hybridní reality
Počítače s Windows 10 Creators Update můžou být nakonfigurované 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é vytváří, používalo stejný adaptér.
Nejběžnější vzorový kód 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.
Pokud chcete vyřešit případné problémy, použijte HolographicAdapterID z holographicSpace. PrimaryAdapterId() nebo HolographicDisplay. AdapterId(). Toto id adaptéru lze pak použít k výběru správného DXGIAdapter pomocí IDXGIFactory4.EnumAdapterByLuid.
Z 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 pro použití 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í Media Foundation v hybridních systémech může způsobit problémy, kdy video nevykreslí nebo textura videa jsou poškozené, protože Media Foundation ve výchozím nastavení používá systémové chování. V některých scénářích se k podpoře více vláken vyžaduje vytvoření samostatného ID3D11Device a jsou nastaveny správné příznaky 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. Jakmile se zařízení a kontext vytvoří, zavolejte SetMultithreadProtected a povolte multithreading. Chcete-li zařízení přidružit k MMFDXGIDeviceManager, použijte funkci MMFDXGIDeviceManager::ResetDevice .
Kód pro přidružení 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;