265 lines
10 KiB
C++
265 lines
10 KiB
C++
#include "stdafx.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;
|
|
}
|