Penyajian di DirectX
Catatan
Artikel ini berkaitan dengan API asli WinRT warisan. Untuk proyek aplikasi asli baru, sebaiknya gunakan OpenXR API.
Windows Mixed Reality dibangun di DirectX untuk menghasilkan pengalaman grafis 3D yang kaya bagi pengguna. Abstraksi penyajian berada tepat di atas DirectX, yang memungkinkan aplikasi beralasan tentang posisi dan orientasi pengamat adegan holografik yang diprediksi oleh sistem. Pengembang kemudian dapat menemukan hologram mereka berdasarkan setiap kamera, memungkinkan aplikasi merender hologram ini dalam berbagai sistem koordinat spasial saat pengguna bergerak.
Catatan: Panduan ini menjelaskan penyajian holografik di Direct3D 11. Templat aplikasi Direct3D 12 Windows Mixed Reality juga disediakan dengan ekstensi templat aplikasi Mixed Reality.
Pembaruan untuk bingkai saat ini
Untuk memperbarui status aplikasi untuk hologram, sekali per bingkai aplikasi akan:
- Dapatkan HolographicFrame dari sistem manajemen tampilan.
- Perbarui adegan dengan prediksi saat ini di mana tampilan kamera akan menjadi saat render selesai. Perhatikan, mungkin ada lebih dari satu kamera untuk adegan holografik.
Untuk merender tampilan kamera holografik, sekali per bingkai aplikasi akan:
- Untuk setiap kamera, render adegan untuk bingkai saat ini, menggunakan tampilan kamera dan matriks proyeksi dari sistem.
Membuat bingkai holografik baru dan mendapatkan prediksinya
HolographicFrame memiliki informasi yang perlu diperbarui dan dirender bingkai saat ini. Aplikasi memulai setiap bingkai baru dengan memanggil metode CreateNextFrame . Ketika metode ini dipanggil, prediksi dibuat menggunakan data sensor terbaru yang tersedia, dan dienkapsulasi dalam objek CurrentPrediction .
Objek bingkai baru harus digunakan untuk setiap bingkai yang dirender karena hanya valid untuk instan tepat waktu. Properti CurrentPrediction berisi informasi seperti posisi kamera. Informasi diekstrapolasi ke saat yang tepat ketika bingkai diharapkan terlihat oleh pengguna.
Kode berikut dikutip dari AppMain::Update:
// The HolographicFrame has information that the app needs in order
// to update and render the current frame. The app begins each new
// frame by calling CreateNextFrame.
HolographicFrame holographicFrame = m_holographicSpace.CreateNextFrame();
// Get a prediction of where holographic cameras will be when this frame
// is presented.
HolographicFramePrediction prediction = holographicFrame.CurrentPrediction();
Memproses pembaruan kamera
Buffer belakang dapat berubah dari bingkai ke bingkai. Aplikasi Anda perlu memvalidasi buffer belakang untuk setiap kamera, dan merilis dan membuat ulang tampilan sumber daya dan buffer kedalaman sesuai kebutuhan. Perhatikan bahwa set pose dalam prediksi adalah daftar otoritatif kamera yang digunakan dalam bingkai saat ini. Biasanya, Anda menggunakan daftar ini untuk melakukan iterasi pada set kamera.
Dari AppMain::Update:
m_deviceResources->EnsureCameraResources(holographicFrame, prediction);
Dari DeviceResources::EnsureCameraResources:
for (HolographicCameraPose const& cameraPose : prediction.CameraPoses())
{
HolographicCameraRenderingParameters renderingParameters = frame.GetRenderingParameters(cameraPose);
CameraResources* pCameraResources = cameraResourceMap[cameraPose.HolographicCamera().Id()].get();
pCameraResources->CreateResourcesForBackBuffer(this, renderingParameters);
}
Mendapatkan sistem koordinat untuk digunakan sebagai dasar untuk penyajian
Windows Mixed Reality memungkinkan aplikasi Anda membuat berbagai sistem koordinat, seperti bingkai referensi terlampir dan stasioner untuk melacak lokasi di dunia fisik. Aplikasi Anda kemudian dapat menggunakan sistem koordinat ini untuk alasan tentang tempat merender hologram setiap bingkai. Saat meminta koordinat dari API, Anda akan selalu meneruskan SpatialCoordinateSystem tempat Anda ingin koordinat tersebut diekspresikan.
Dari AppMain::Update:
pose = SpatialPointerPose::TryGetAtTimestamp(
m_stationaryReferenceFrame.CoordinateSystem(), prediction.Timestamp());
Sistem koordinat ini kemudian dapat digunakan untuk menghasilkan matriks tampilan stereo saat merender konten di adegan Anda.
Dari 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);
Tatapan proses dan input gerakan
Tatapan dan input tangan tidak berbasis waktu dan tidak perlu diperbarui dalam fungsi StepTimer . Namun input ini adalah sesuatu yang perlu dilihat aplikasi pada setiap bingkai.
Memproses pembaruan berbasis waktu
Setiap aplikasi penyajian real-time akan memerlukan beberapa cara untuk memproses pembaruan berbasis waktu - templat aplikasi Windows Holographic menggunakan implementasi StepTimer , mirip dengan StepTimer yang disediakan dalam templat aplikasi DirectX 11 UWP. Kelas pembantu sampel StepTimer ini dapat menyediakan pembaruan langkah waktu tetap, pembaruan langkah waktu variabel, dan mode default adalah langkah-langkah waktu variabel.
Untuk penyajian holografik, kami telah memilih untuk tidak memasukkan terlalu banyak ke dalam fungsi timer karena Anda dapat mengonfigurasinya menjadi langkah waktu tetap. Ini mungkin dipanggil lebih dari sekali per bingkai - atau tidak sama sekali, untuk beberapa bingkai - dan pembaruan data holografik kita harus terjadi sekali per bingkai.
Dari AppMain::Update:
m_timer.Tick([this]()
{
m_spinningCubeRenderer->Update(m_timer);
});
Posisikan dan putar hologram dalam sistem koordinat Anda
Jika Anda beroperasi dalam sistem koordinat tunggal, seperti yang dilakukan templat dengan SpatialStationaryReferenceFrame, proses ini tidak berbeda dari apa yang biasa Anda gunakan dalam grafik 3D. Di sini, kami memutar kubus dan mengatur matriks model berdasarkan posisi dalam sistem koordinat stasioner.
Dari 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));
Catatan tentang skenario lanjutan: Kubus berputar adalah contoh sederhana tentang cara memosisikan hologram dalam satu bingkai referensi. Dimungkinkan juga untuk menggunakan beberapa SpatialCoordinateSystems dalam bingkai yang dirender yang sama, pada saat yang sama.
Memperbarui data buffer konstanta
Transformasi model untuk konten diperbarui seperti biasa. Sekarang, Anda akan memiliki transformasi yang valid komputasi untuk sistem koordinat yang akan Anda render.
Dari SpinningCubeRenderer::Update:
// Update the model transform buffer for the hologram.
context->UpdateSubresource(
m_modelConstantBuffer.Get(),
0,
nullptr,
&m_modelConstantBufferData,
0,
0
);
Bagaimana dengan transformasi tampilan dan proyeksi? Untuk hasil terbaik, kita ingin menunggu sampai kita hampir siap untuk panggilan undian kita sebelum kita mendapatkan ini.
Merender bingkai saat ini
Penyajian pada Windows Mixed Reality tidak jauh berbeda dari penyajian pada layar mono 2D, tetapi ada beberapa perbedaan:
- Prediksi bingkai holografik penting. Semakin dekat prediksinya adalah ketika bingkai Anda disajikan, semakin baik hologram Anda akan terlihat.
- Windows Mixed Reality mengontrol tampilan kamera. Render ke masing-masing karena bingkai holografik akan menyajikannya untuk Anda nanti.
- Sebaiknya lakukan penyajian stereo menggunakan gambar instans ke array target render. Templat aplikasi holografik menggunakan pendekatan gambar instans yang direkomendasikan ke array target render, yang menggunakan tampilan target render ke Texture2DArray.
- Jika Anda ingin merender tanpa menggunakan instancing stereo, Anda harus membuat dua RenderTargetView non-array, satu untuk setiap mata. Setiap RenderTargetViews mereferensikan salah satu dari dua irisan dalam Texture2DArray yang disediakan untuk aplikasi dari sistem. Ini tidak disarankan, karena biasanya lebih lambat daripada menggunakan instancing.
Dapatkan prediksi HolographicFrame yang diperbarui
Memperbarui prediksi bingkai meningkatkan efektivitas stabilisasi gambar. Anda mendapatkan posisi hologram yang lebih akurat karena waktu yang lebih singkat antara prediksi dan kapan bingkai terlihat oleh pengguna. Idealnya perbarui prediksi bingkai Anda tepat sebelum penyajian.
holographicFrame.UpdateCurrentPrediction();
HolographicFramePrediction prediction = holographicFrame.CurrentPrediction();
Render ke setiap kamera
Perulangan pada set pose kamera dalam prediksi, dan render ke setiap kamera dalam set ini.
Menyiapkan pass penyajian Anda
Windows Mixed Reality menggunakan penyajian stereoskopis untuk meningkatkan ilusi kedalaman dan merender secara stereoskopis, sehingga tampilan kiri dan kanan aktif. Dengan penyajian stereoskopis, ada offset antara kedua layar, yang dapat direkonsiliasi otak sebagai kedalaman aktual. Bagian ini mencakup penyajian stereoskopis menggunakan instancing, menggunakan kode dari templat aplikasi Windows Holographic.
Setiap kamera memiliki target render sendiri (buffer belakang), dan matriks tampilan dan proyeksi, ke ruang holografik. Aplikasi Anda harus membuat sumber daya berbasis kamera lainnya - seperti buffer kedalaman - per kamera. Dalam templat aplikasi Windows Holographic, kami menyediakan kelas pembantu untuk menggabungkan sumber daya ini bersama-sama di DX::CameraResources. Mulailah dengan menyiapkan tampilan target render:
Dari 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);
Gunakan prediksi untuk mendapatkan matriks tampilan dan proyeksi untuk kamera
Matriks tampilan dan proyeksi untuk setiap kamera holografik akan berubah dengan setiap bingkai. Refresh data dalam buffer konstan untuk setiap kamera holografik. Lakukan ini setelah Anda memperbarui prediksi, dan sebelum Anda melakukan panggilan gambar untuk kamera tersebut.
Dari 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);
Di sini, kami menunjukkan bagaimana matriks diperoleh dari pose kamera. Selama proses ini, kami juga mendapatkan viewport saat ini untuk kamera. Perhatikan bagaimana kami menyediakan sistem koordinat: ini adalah sistem koordinat yang sama yang kami gunakan untuk memahami tatapan, dan itu sama dengan yang kami gunakan untuk memposisikan kubus berputar.
Dari 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))
);
}
Viewport harus diatur setiap bingkai. Shader vertex Anda (setidaknya) umumnya akan memerlukan akses ke data tampilan/proyeksi.
Dari CameraResources::AttachViewProjectionBuffer:
// Set the viewport for this camera.
context->RSSetViewports(1, &m_d3dViewport);
// Send the constant buffer to the vertex shader.
context->VSSetConstantBuffers(
1,
1,
m_viewProjectionConstantBuffer.GetAddressOf()
);
Render ke buffer belakang kamera dan terapkan buffer kedalaman:
Ada baiknya untuk memeriksa bahwa TryGetViewTransform berhasil sebelum mencoba menggunakan data tampilan/proyeksi, karena jika sistem koordinat tidak dapat di-locatable (misalnya, pelacakan terganggu) aplikasi Anda tidak dapat merender dengannya untuk bingkai tersebut. Templat hanya memanggil Render pada kubus berputar jika kelas CameraResources menunjukkan pembaruan yang berhasil.
Windows Mixed Reality mencakup fitur untuk stabilisasi gambar agar hologram tetap diposisikan di mana pengembang atau pengguna menempatkannya di dunia. Stabilisasi gambar membantu menyembunyikan latensi yang melekat dalam alur penyajian untuk memastikan pengalaman holografik terbaik bagi pengguna. Titik fokus dapat ditentukan untuk meningkatkan stabilisasi gambar lebih lanjut, atau buffer kedalaman dapat disediakan untuk menghitung stabilisasi gambar yang dioptimalkan secara real time.
Untuk hasil terbaik, aplikasi Anda harus memberikan buffer kedalaman menggunakan COMmitDirect3D11DepthBuffer API. Windows Mixed Reality kemudian dapat menggunakan informasi geometri dari buffer kedalaman untuk mengoptimalkan stabilisasi gambar secara real time. Templat aplikasi Windows Holographic menerapkan buffer kedalaman aplikasi secara default, membantu mengoptimalkan stabilitas hologram.
Dari 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);
}
}
Catatan
Windows akan memproses tekstur kedalaman Anda pada GPU, sehingga harus dimungkinkan untuk menggunakan buffer kedalaman Anda sebagai sumber daya shader. ID3D11Texture2D yang Anda buat harus dalam format tanpa jenis dan harus terikat sebagai tampilan sumber daya shader. Berikut adalah contoh cara membuat tekstur kedalaman yang dapat diterapkan untuk stabilisasi gambar.
Kode untuk pembuatan sumber daya buffer Kedalaman untuk 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
));
Gambar konten holografik
Templat aplikasi Windows Holographic merender konten dalam stereo dengan menggunakan teknik yang direkomendasikan untuk menggambar geometri instans ke Texture2DArray ukuran 2. Mari kita lihat bagian instancing dari ini, dan cara kerjanya pada Windows Mixed Reality.
Dari 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.
);
Setiap instans mengakses matriks tampilan/proyeksi yang berbeda dari buffer konstanta. Berikut adalah struktur buffer konstan, yang hanya merupakan array dari dua matriks.
Dari VertexShaderShared.hlsl, disertakan oleh 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];
};
Indeks array target render harus diatur untuk setiap piksel. Dalam cuplikan berikut, output.viewId dipetakan ke semantik SV_RenderTargetArrayIndex . Ini memerlukan dukungan untuk fitur Direct3D 11.3 opsional, yang memungkinkan semantik indeks array target render diatur dari tahap shader apa pun.
Dari 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;
};
Dari VertexShaderShared.hlsl, disertakan oleh 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;
}
Jika Anda ingin menggunakan teknik menggambar instans yang ada dengan metode menggambar ini ke array target render stereo, gambar dua kali jumlah instans yang biasanya Anda miliki. Dalam shader, bagi input.instId dengan 2 untuk mendapatkan ID instans asli, yang dapat diindeks ke dalam (misalnya) buffer data per objek: int actualIdx = input.instId / 2;
Catatan penting tentang merender konten stereo di HoloLens
Windows Mixed Reality mendukung kemampuan untuk mengatur indeks array target render dari tahap shader apa pun. Biasanya, ini adalah tugas yang hanya dapat dilakukan dalam tahap shader geometri karena cara semantik didefinisikan untuk Direct3D 11. Di sini, kami menunjukkan contoh lengkap tentang cara menyiapkan alur penyajian hanya dengan tahap vertex dan piksel shader yang ditetapkan. Kode shader seperti yang dijelaskan di atas.
Dari 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.
);
Catatan penting tentang penyajian di perangkat non-HoloLens
Mengatur indeks array target render di shader vertex mengharuskan driver grafis mendukung fitur Direct3D 11.3 opsional, yang didukung HoloLens. Aplikasi Anda mungkin dapat dengan aman mengimplementasikan teknik tersebut untuk penyajian, dan semua persyaratan akan terpenuhi untuk berjalan di Microsoft HoloLens.
Mungkin saja Anda ingin menggunakan emulator HoloLens juga, yang dapat menjadi alat pengembangan yang kuat untuk aplikasi holografik Anda - dan mendukung perangkat headset imersif Windows Mixed Reality yang melekat pada PC Windows 10. Dukungan untuk jalur penyajian non-HoloLens - untuk semua Windows Mixed Reality - juga dibangun ke dalam templat aplikasi Windows Holographic. Dalam kode templat, Anda akan menemukan kode untuk mengaktifkan aplikasi holografik agar berjalan pada GPU di PC pengembangan Anda. Berikut adalah cara kelas DeviceResources memeriksa dukungan fitur opsional ini.
Dari 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;
}
Untuk mendukung penyajian tanpa fitur opsional ini, aplikasi Anda harus menggunakan shader geometri untuk mengatur indeks array target render. Cuplikan ini akan ditambahkan setelah VSSetConstantBuffers, dan sebelum PSSetShader dalam contoh kode yang ditampilkan di bagian sebelumnya yang menjelaskan cara merender stereo di HoloLens.
Dari 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
);
}
CATATAN HLSL: Dalam hal ini, Anda juga harus memuat shader vertex yang sedikit dimodifikasi yang meneruskan indeks array target render ke shader geometri menggunakan semantik shader yang selalu diizinkan, seperti TEXCOORD0. Shader geometri tidak harus melakukan pekerjaan apa pun; shader geometri templat melewati semua data, dengan pengecualian indeks array target render, yang digunakan untuk mengatur semantik SV_RenderTargetArrayIndex.
Kode templat aplikasi untuk 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);
}
}
Hadir
Aktifkan bingkai holografik untuk menyajikan rantai pertukaran
Dengan Windows Mixed Reality, sistem mengontrol rantai pertukaran. Sistem kemudian mengelola penyajian bingkai ke setiap kamera holografik untuk memastikan pengalaman pengguna berkualitas tinggi. Ini juga menyediakan pembaruan viewport setiap bingkai, untuk setiap kamera, untuk mengoptimalkan aspek sistem seperti stabilisasi gambar atau Mixed Reality Capture. Jadi, aplikasi holografik yang menggunakan DirectX tidak memanggil Present pada rantai pertukaran DXGI. Sebagai gantinya , Anda menggunakan kelas HolographicFrame untuk menyajikan semua swapchain untuk bingkai setelah Anda selesai menggambarnya.
Dari DeviceResources::P resent:
HolographicFramePresentResult presentResult = frame.PresentUsingCurrentPrediction();
Secara default, API ini menunggu bingkai selesai sebelum kembali. Aplikasi Holografik harus menunggu bingkai sebelumnya selesai sebelum memulai pekerjaan pada bingkai baru, karena ini mengurangi latensi dan memungkinkan hasil yang lebih baik dari prediksi bingkai holografik. Ini bukan aturan yang sulit, dan jika Anda memiliki bingkai yang membutuhkan waktu lebih dari satu refresh layar untuk dirender, Anda dapat menonaktifkan tunggu ini dengan meneruskan parameter HolographicFramePresentWaitBehavior ke PresentUsingCurrentPrediction. Dalam hal ini, Anda mungkin akan menggunakan utas penyajian asinkron untuk mempertahankan beban berkelanjutan pada GPU. Kecepatan refresh perangkat HoloLens adalah 60 hz, di mana satu bingkai memiliki durasi sekitar 16 ms. Perangkat headset imersif dapat berkisar antara 60 hz hingga 90 hz; saat menyegarkan layar pada 90 hz, setiap bingkai akan memiliki durasi sekitar 11 mdtk.
Menangani skenario DeviceLost bekerja sama dengan HolographicFrame
Aplikasi DirectX 11 biasanya ingin memeriksa HRESULT yang dikembalikan oleh fungsi Sajikan rantai pertukaran DXGI untuk mengetahui apakah ada kesalahan DeviceLost. Kelas HolographicFrame menangani ini untuk Anda. Periksa HolographicFramePresentResult yang dikembalikan untuk mengetahui apakah Anda perlu merilis dan membuat ulang perangkat Direct3D dan sumber daya berbasis perangkat.
// 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();
}
Jika perangkat Direct3D hilang, dan Anda membuatnya kembali, Anda harus memberi tahu HolographicSpace untuk mulai menggunakan perangkat baru. Rantai pertukaran akan dibuat ulang untuk perangkat ini.
Dari DeviceResources::InitializeUsingHolographicSpace:
m_holographicSpace.SetDirect3D11Device(m_d3dInteropDevice);
Setelah bingkai disajikan, Anda dapat kembali ke perulangan program utama dan memungkinkannya untuk melanjutkan ke bingkai berikutnya.
PC grafis hibrid dan aplikasi realitas campuran
PC Pembaruan Pembuat Windows 10 dapat dikonfigurasi dengan GPU diskrit dan terintegrasi. Dengan jenis komputer ini, Windows akan memilih adaptor yang tersambung dengan headset. Aplikasi harus memastikan perangkat DirectX yang dibuatnya menggunakan adaptor yang sama.
Sebagian besar kode sampel Direct3D umum menunjukkan pembuatan perangkat DirectX menggunakan adaptor perangkat keras default, yang pada sistem hibrid mungkin tidak sama dengan yang digunakan untuk headset.
Untuk mengatasi masalah apa pun, gunakan HolographicAdapterID dari HolographicSpace. PrimaryAdapterId() atau HolographicDisplay. AdapterId(). AdapterId ini kemudian dapat digunakan untuk memilih DXGIAdapter yang tepat menggunakan IDXGIFactory4.EnumAdapterByLuid.
Dari 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();
}
Kode untuk memperbarui DeviceResources::CreateDeviceResources untuk menggunakan 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.
);
Grafik hibrid dan Media Foundation
Menggunakan Media Foundation pada sistem hibrid dapat menyebabkan masalah di mana video tidak akan dirender atau tekstur video rusak karena Media Foundation default ke perilaku sistem. Dalam beberapa skenario, membuat ID3D11Device terpisah diperlukan untuk mendukung multi-utas dan bendera pembuatan yang benar diatur.
Saat menginisialisasi ID3D11Device, bendera D3D11_CREATE_DEVICE_VIDEO_SUPPORT harus didefinisikan sebagai bagian dari D3D11_CREATE_DEVICE_FLAG. Setelah perangkat dan konteks dibuat, panggil SetMultithreadProtected untuk mengaktifkan multithreading. Untuk mengaitkan perangkat dengan IMFDXGIDeviceManager, gunakan fungsi IMFDXGIDeviceManager::ResetDevice .
Kode untuk mengaitkan ID3D11Device dengan IMFDXGIDeviceManager:
// create dx device for media pipeline
winrt::com_ptr<ID3D11Device> spMediaDevice;
// See above. Also make sure to enable the following flags on the D3D11 device:
// * D3D11_CREATE_DEVICE_VIDEO_SUPPORT
// * D3D11_CREATE_DEVICE_BGRA_SUPPORT
if (FAILED(CreateMediaDevice(spAdapter.get(), &spMediaDevice)))
return;
// Turn multithreading on
winrt::com_ptr<ID3D10Multithread> spMultithread;
if (spContext.try_as(spMultithread))
{
spMultithread->SetMultithreadProtected(TRUE);
}
// lock the shared dxgi device manager
// call MFUnlockDXGIDeviceManager when no longer needed
UINT uiResetToken;
winrt::com_ptr<IMFDXGIDeviceManager> spDeviceManager;
hr = MFLockDXGIDeviceManager(&uiResetToken, spDeviceManager.put());
if (FAILED(hr))
return hr;
// associate the device with the manager
hr = spDeviceManager->ResetDevice(spMediaDevice.get(), uiResetToken);
if (FAILED(hr))
return hr;