요 몇 일간 Toon-Table Texture를 적용해서 아웃라인을 제외한 Toon Shading을 가능하도록 했다. 이제 그림자를 처리하려고 한다.그림자 처리를 위해 Shadow Map에 씬을 렌더링 해야한다.
그 전에 할 일이 있다.
Render Target으로 사용한 텍스쳐를 화면에 렌더링 할 수 있도록 해야한다. 디버깅을 위해서 이 기능은 필수다. Shadow Map은 물론 snow처리나 Mirror효과, Out-line, Glow등의 Post Processing을 구현할때도 Render Target을 화면에 출력하는 기능이 꼭 필요하다. 이게 안되면 정상적인 디버깅이 불가능하다. 게다가 현재는 익숙하지 않은 D3D12 API를 사용하고 있기 때문에 최소한 내가 Render Target에 렌더링한게 제대로 렌더링 되었는지는 알아야한다.
일단 현재 사용중인 Depth Buffer(Z Buffer)를 화면에 렌더링해보기로 했다.
- 엔진 초기화시에 Depth Buffer로부터 ShaderResourceView를 를 설정해둔다.
- 기존에 만들어둔 스프라이트 코드를 거의 그대로 이용한다. 다만 파라미터로 위의SRV를 넘겨준다는 점이 다르다.
- 렌더링 코드로 Depth Buffer의 SRV를 넘기기 전에 Depth Buffer의 리소스 상태를 변경해야한다. ResourceBarrier()함수를 사용해서 D3D12_RESOURCE_STATE_DEPTH_WRITE -> D3D12_RESOURCE_STATE_GENERIC_READ상태로 변경한다. 렌더링 커맨드를 기록한 후에는 다시 D3D12_RESOURCE_STATE_GENERIC_READ -> D3D12_RESOURCE_STATE_DEPTH_WRITE 로 바꿔준다.
- 스프라이트 렌더링 코드에서 넘겨받은 SRV가 유효한 값이면 자신의 Descriptor Table로 SRV를 카피한다(CopyDescriptorsSimple()함수 사용)
- Depth Buffer는 R32 format을 사용하므로 r채널만 읽어서 bw로 바꿔 렌더링 해주는 Pixel Shader를 사용해야한다. D3D12에선 픽셀쉐이더만 교체할순 없으므로 Depth Shader가 세팅된 ID3D12PipelineState를 미리 만들어둔다.
<주의사항>
코딩 자체는 어려울것이 없다.주의할 점이 몇 가지 있다.
- CopyDescriptorsSimple()를 사용하기 위해선 source descriptor heap이 cpu write only로 설정되면 안된다. 즉 Descriptor Heap을 생성할때 D3D12_DESCRIPTOR_HEAP_DESC구조체의 Flags필드를 D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE이 아닌 D3D12_DESCRIPTOR_HEAP_FLAG_NONE로 설정해야 한다.
- Depth Buffer를 스프라이트로 렌더링할때 Depth Write가 켜져있으면 문제가 된다. 당연하다. Depth Buffer가 SRV상태이고 Depth Write상태가 아니기 때문이다. 따라서 Depth Buffer렌더링을 위한 ID3D12PipelineState객체를 만들때 D3D12_GRAPHICS_PIPELINE_STATE_DESC구조체의 DepthStencilState.DepthEnable = FALSE , DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO로 설정한다.
그래서 잘 나온다. 만세. 이제 Shadow Map만들자.