diff options
Diffstat (limited to 'support/hololens/ServoApp/Common/CameraResources.cpp')
-rw-r--r-- | support/hololens/ServoApp/Common/CameraResources.cpp | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/support/hololens/ServoApp/Common/CameraResources.cpp b/support/hololens/ServoApp/Common/CameraResources.cpp new file mode 100644 index 00000000000..4391a55c74e --- /dev/null +++ b/support/hololens/ServoApp/Common/CameraResources.cpp @@ -0,0 +1,234 @@ +#include "pch.h" + +#include "CameraResources.h" +#include "Common/DirectXHelper.h" +#include "DeviceResources.h" + +using namespace DirectX; +using namespace Microsoft::WRL; +using namespace winrt::Windows::Foundation::Numerics; +using namespace winrt::Windows::Graphics::DirectX::Direct3D11; +using namespace winrt::Windows::Graphics::Holographic; +using namespace winrt::Windows::Perception::Spatial; + +DX::CameraResources::CameraResources(HolographicCamera const &camera) + : m_holographicCamera(camera), m_isStereo(camera.IsStereo()), + m_d3dRenderTargetSize(camera.RenderTargetSize()) { + m_d3dViewport = CD3D11_VIEWPORT(0.f, 0.f, m_d3dRenderTargetSize.Width, + m_d3dRenderTargetSize.Height); +}; + +// Updates resources associated with a holographic camera's swap chain. +// The app does not access the swap chain directly, but it does create +// resource views for the back buffer. +void DX::CameraResources::CreateResourcesForBackBuffer( + DX::DeviceResources *pDeviceResources, + HolographicCameraRenderingParameters const &cameraParameters) { + ID3D11Device *device = pDeviceResources->GetD3DDevice(); + + // Get the WinRT object representing the holographic camera's back buffer. + IDirect3DSurface surface = cameraParameters.Direct3D11BackBuffer(); + + // Get the holographic camera's back buffer. + // Holographic apps do not create a swap chain themselves; instead, buffers + // are owned by the system. The Direct3D back buffer resources are provided to + // the app using WinRT interop APIs. + ComPtr<ID3D11Texture2D> cameraBackBuffer; + winrt::check_hresult(surface + .as<::Windows::Graphics::DirectX::Direct3D11:: + IDirect3DDxgiInterfaceAccess>() + ->GetInterface(IID_PPV_ARGS(&cameraBackBuffer))); + + // Determine if the back buffer has changed. If so, ensure that the render + // target view is for the current back buffer. + if (m_d3dBackBuffer.Get() != cameraBackBuffer.Get()) { + // This can change every frame as the system moves to the next buffer in the + // swap chain. This mode of operation will occur when certain rendering + // modes are activated. + m_d3dBackBuffer = cameraBackBuffer; + + // Create a render target view of the back buffer. + // Creating this resource is inexpensive, and is better than keeping track + // of the back buffers in order to pre-allocate render target views for each + // one. + winrt::check_hresult(device->CreateRenderTargetView( + m_d3dBackBuffer.Get(), nullptr, &m_d3dRenderTargetView)); + + // Get the DXGI format for the back buffer. + // This information can be accessed by the app using + // CameraResources::GetBackBufferDXGIFormat(). + D3D11_TEXTURE2D_DESC backBufferDesc; + m_d3dBackBuffer->GetDesc(&backBufferDesc); + m_dxgiFormat = backBufferDesc.Format; + + // Check for render target size changes. + winrt::Windows::Foundation::Size currentSize = + m_holographicCamera.RenderTargetSize(); + if (m_d3dRenderTargetSize != currentSize) { + // Set render target size. + m_d3dRenderTargetSize = currentSize; + + // A new depth stencil view is also needed. + m_d3dDepthStencilView.Reset(); + } + } + + // Refresh depth stencil resources, if needed. + if (m_d3dDepthStencilView == nullptr) { + // 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)); + } + + // Create the constant buffer, if needed. + if (m_viewProjectionConstantBuffer == nullptr) { + // Create a constant buffer to store view and projection matrices for the + // camera. + CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ViewProjectionConstantBuffer), + D3D11_BIND_CONSTANT_BUFFER); + winrt::check_hresult(device->CreateBuffer(&constantBufferDesc, nullptr, + &m_viewProjectionConstantBuffer)); + } +} + +// Releases resources associated with a back buffer. +void DX::CameraResources::ReleaseResourcesForBackBuffer( + DX::DeviceResources *pDeviceResources) { + ID3D11DeviceContext *context = pDeviceResources->GetD3DDeviceContext(); + + // Release camera-specific resources. + m_d3dBackBuffer.Reset(); + m_d3dDepthStencil.Reset(); + m_d3dRenderTargetView.Reset(); + m_d3dDepthStencilView.Reset(); + m_viewProjectionConstantBuffer.Reset(); + + // Ensure system references to the back buffer are released by clearing the + // render target from the graphics pipeline state, and then flushing the + // Direct3D context. + ID3D11RenderTargetView *nullViews[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = { + nullptr}; + context->OMSetRenderTargets(ARRAYSIZE(nullViews), nullViews, nullptr); + context->Flush(); +} + +// Updates the view/projection constant buffer for a holographic camera. +void DX::CameraResources::UpdateViewProjectionBuffer( + std::shared_ptr<DX::DeviceResources> deviceResources, + HolographicCameraPose const &cameraPose, + SpatialCoordinateSystem const &coordinateSystem) { + // 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))); + } + + // Use the D3D device context to update Direct3D device-based resources. + ID3D11DeviceContext *context = deviceResources->GetD3DDeviceContext(); + + // Loading is asynchronous. Resources must be created before they can be + // updated. + if (context == nullptr || m_viewProjectionConstantBuffer == nullptr || + !viewTransformAcquired) { + m_framePending = false; + } else { + // Update the view and projection matrices. + context->UpdateSubresource(m_viewProjectionConstantBuffer.Get(), 0, nullptr, + &viewProjectionConstantBufferData, 0, 0); + + m_framePending = true; + } +} + +// Gets the view-projection constant buffer for the HolographicCamera and +// attaches it to the shader pipeline. +bool DX::CameraResources::AttachViewProjectionBuffer( + std::shared_ptr<DX::DeviceResources> &deviceResources) { + // This method uses Direct3D device-based resources. + ID3D11DeviceContext *context = deviceResources->GetD3DDeviceContext(); + + // Loading is asynchronous. Resources must be created before they can be + // updated. Cameras can also be added asynchronously, in which case they must + // be initialized before they can be used. + if (context == nullptr || m_viewProjectionConstantBuffer == nullptr || + m_framePending == false) { + return false; + } + + // 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()); + + // The template includes a pass-through geometry shader that is used by + // default on systems that don't support the D3D11_FEATURE_D3D11_OPTIONS3:: + // VPAndRTArrayIndexFromAnyShaderFeedingRasterizer extension. The shader + // will be enabled at run-time on systems that require it. + // If your app will also use the geometry shader for other tasks and those + // tasks require the view/projection matrix, uncomment the following line + // of code to send the constant buffer to the geometry shader as well. + /*context->GSSetConstantBuffers( + 1, + 1, + m_viewProjectionConstantBuffer.GetAddressOf() + );*/ + + m_framePending = false; + + return true; +} |