2025-11-28 00:35:46 +09:00

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;
}