Depth stencil view
3d 물체를 표현하기 위한 뷰
깊이 값을 통하여 투영 시 비율을 설정하고
다른 픽셀에 의해 가려질 시 그리지 않는 등 추적
랜더링 파이프라인에서 Rasterizer 단계일 때,
투영 좌표계를 벗어날 경우 clipping하여 표현하고 있었음
(-1 <= x, y <= 1 / 0 <= z <= 1)
깊이 추적 방법
화면의 크기와 같은 크기의 버퍼를 준비하고 해당 버퍼에 가장 가까운 객체의 깊이값을 저장
픽셀화 단계에서 픽셀이 하나 하나 수정될 때마다 해당 좌표의 버퍼와 깊이값을 비교하여
더 가까운 픽셀일 시 픽셀에 적용하고 버퍼를 업데이트 한다.
스텐실
깊이 버퍼가 0.0 ~ 1.0 사이의 float 형식으로 나타낼 때,
float의 바이트 크기를 3바이트로 낮추면서 정밀도를 희생하며 남은 1바이트를 스텐실 값으로 사용
스텐실 값에 따라 표현 하지 않는 등 처리 방법에 대해 저장할 수 있도록 함
class DepthStencilBuffer
{
public:
void Init(const WindowInfo& window, DXGI_FORMAT dsvFormat = DXGI_FORMAT_D32_FLOAT);
...
private:
ComPtr<ID3D12Resource> _dsvBuffer;
ComPtr<ID3D12DescriptorHeap> _dsvHeap;
D3D12_CPU_DESCRIPTOR_HANDLE _dsvHandle = {};
DXGI_FORMAT _dsvFormat = {};
};
리소스 버퍼와 버퍼에 대해 기술할 Descriptor heap로 구성
버퍼를 깊이 용도로만 사용할 경우 깊이 값으로 4 바이트를 모두 사용하도록 DXGI_FORMAT_D32_FLOAT 포맷으로 설정
스텐실을 사용하려면 DXGI_FORMAT_D24_UNORM_S8_UINT 포맷으로 설정
void DepthStencilBuffer::Init(const WindowInfo& window, DXGI_FORMAT dsvFormat)
{
...
D3D12_HEAP_PROPERTIES heapProperty = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT);
D3D12_RESOURCE_DESC desc = CD3DX12_RESOURCE_DESC::Tex2D(_dsvFormat, window.width, window.height);
desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
D3D12_CLEAR_VALUE optimizedClearValue = CD3DX12_CLEAR_VALUE(_dsvFormat, 1.0f, 0);
DEVICE->CreateCommittedResource(
&heapProperty,
D3D12_HEAP_FLAG_NONE,
&desc,
D3D12_RESOURCE_STATE_DEPTH_WRITE,
&optimizedClearValue,
IID_PPV_ARGS(&_dsvBuffer));
D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
heapDesc.NumDescriptors = 1;
heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
DEVICE->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&_dsvHeap));
_dsvHandle = _dsvHeap->GetCPUDescriptorHandleForHeapStart();
DEVICE->CreateDepthStencilView(_dsvBuffer.Get(), nullptr, _dsvHandle);
}
버퍼 타입은 버퍼가 아니라 아니라 Tex2D 타입이다. (CD3DX12_RESOURCE_DESC::Tex2D)
프레임마다 optimizedClearValue를 통하여 해당 버퍼를 특정 값으로 초기화
descriptor heap의 타입은 D3D12_DESCRIPTOR_HEAP_TYPE_DSV으로 설정하고
CreateDepthStencilView 함수를 통하여 생성
void CommandQueue::RenderBegin(const D3D12_VIEWPORT* vp, const D3D12_RECT* rect)
{
...
D3D12_CPU_DESCRIPTOR_HANDLE backBufferView = _swapChain->GetBackRTV();
_cmdList->ClearRenderTargetView(backBufferView, Colors::LightSteelBlue, 0, nullptr);
D3D12_CPU_DESCRIPTOR_HANDLE depthStencilVeiw = GEngine->GetDepthStencilBuffer()->GetDSVCpuHandle();
_cmdList->OMSetRenderTargets(1, &backBufferView, FALSE, &depthStencilVeiw);
_cmdList->ClearDepthStencilView(depthStencilVeiw, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr);
}
command queue에서 렌더링을 시작하는 부분에서 DSV를 RTV와 묶어서 요청
ClearDepthStencilView 함수를 통하여 DSV 버퍼를 특정 값으로 초기화 요청
스텐실 값을 사용할 시 D3D12_CLEAR_FLAG_STENCIL 플래그를 or 해주고,
초기화 값을 넣어주면 된다.
void Shader::Init(const wstring& path)
{
...
_pipelineDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
_pipelineDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
//_pipelineDesc.DepthStencilState.DepthEnable = TRUE;
//_pipelineDesc.DepthStencilState.StencilEnable = FALSE;
_pipelineDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
_pipelineDesc.SampleMask = UINT_MAX;
_pipelineDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
_pipelineDesc.NumRenderTargets = 1;
_pipelineDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
_pipelineDesc.SampleDesc.Count = 1;
_pipelineDesc.DSVFormat = DXGI_FORMAT_D32_FLOAT;
DEVICE->CreateGraphicsPipelineState(&_pipelineDesc, IID_PPV_ARGS(&_pipelineState));
}
쉐이더 구현부에서 depth와 stencil 사용 여부를 설정해준다.
CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT)로 설정 시 depth만 사용
또한 깊이를 비교하는 함수 또한 설정할 수 있는데
default는 D3D12_COMPARISON_FUNC_LESS로 0에 가까운 픽셀을 표시하는 것이다.
버퍼 생성시 사용한 DSV의 포맷을 여기서도 동일하게 설정