Grahpics

[Graphics] DirectX12 - Depth Stencil View

송만덕 2022. 1. 29. 03:27

 

Depth Stencil View

 

깊이 버퍼 (Depth):

가장 가까운 '보여지는 정점'의 깊이 정보를 저장하는 2차원 텍스쳐.

모든 정점들의 깊이 정보를 저장해서, 가장 얕은(카메라와 가까운) 대상이 정해져서, 최종 Draw가 되는 것을 결정해, 모니터에 뿌려준다.

  1. 모든 객체들은 깊이(z성분)을 갖고 있으며 카메라의 위치에서 볼 때, 겹처서 렌더링 된다.
  2. 렌더링 순서는 랜덤이지만, 카메라에 가까운 깊이 값을 갖고 있는 객체가 렌더링 되고, 뒤에 있는 객체는 가려져야만 한다. 이를 위해 깊이/스텐실퍼버가 사용된다.
  3. 깊이 스텐실 버퍼는 백 버퍼와 같은 가로-세로 크기를 가지고 있다.
  4. 모든 객체가 랜더링 시에 각 Depth 버퍼의 픽셀이 깊이Depth 값이 저장된다.
  5. 투영 좌표계상의 정점(x,y,z,w)에서 z 성분 또는 w 성분이 깊이 버퍼에 저장된다.
  6. 기본적으로 픽셀에 깊이 값들이 중복 저장될 때, 깊이 값이 작은 것으로 '최종 저장'된다.
  7. DX에서는 깊이 버퍼의 값이 0.0~1.0f 범위로 저장된다. (범위 외는 걸러진다.)
  8. 깊이 버퍼는 랜더링 하고자 하는 소스 값과 이미 랜더링 되어 있는 깊이 값(대상)과 비교하여 처리 한다. 
  9. 기본적으로는 소스 깊이 값이 대상 깊이 값보다 작을 경우(카메라에 가까울 경우)에만 렌더링 된다.   //<그림1>


2D화면을 보고 거리를 알 수 없다. 그러나 비율은 유지된다.
따라서 투영좌표계는 직사각형으로 되어있다.(비율만 따지겠다!)
중간에 있건 뒤에 있건 상관없이 비율의 결과물만 최종 결과물이 된다.    //<그림2>

 

스텐실 버퍼 (Stencil):

특정 픽셀들이 후면버퍼에 기록되지 않도록 하는 버퍼.

특정 부분들이 랜더링되지 않도록 하는 것이다.

후면 버퍼의 일정 부분이 랜더링 되지 않도록 한다.

흔히 거울이나, 그림자의 구현에 사용되는데, 예를 들어 벽면에 거울이 있는 경우, 스텐실 버퍼를 사용하면 벽면을 제외하고,  거울이 있는 영역에 대해서만 반사되는 물체를 그려야 한다.

 

 

 

 

그림 1.

 

그림 2.

 

 

 


 

<Game.cpp>

 

더보기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include "pch.h"
#include "Game.h"
#include "Engine.h"
 
shared_ptr<Mesh> mesh = make_shared<Mesh>();
shared_ptr<Shader> shader = make_shared<Shader>();
shared_ptr<Texture> texture = make_shared<Texture>();
 
void Game::Init(const WindowInfo& info)
{
    GEngine->Init(info);
 
    vector<Vertex> vec(4);
    vec[0].pos = Vec3(-0.7f, 0.7f, 0.5f);
    vec[0].color = Vec4(1.f, 0.f, 0.f, 1.f);
    vec[0].uv = Vec2(0.f, 0.f);
    vec[1].pos = Vec3(0.7f, 0.7f, 0.5f);
    vec[1].color = Vec4(0.f, 1.f, 0.f, 1.f);
    vec[1].uv = Vec2(1.f, 0.f);
    vec[2].pos = Vec3(0.7f, -0.7f, 0.5f);
    vec[2].color = Vec4(0.f, 0.f, 1.f, 1.f);
    vec[2].uv = Vec2(1.f, 1.f);
    vec[3].pos = Vec3(-0.7f, -0.7f, 0.5f);
    vec[3].color = Vec4(0.f, 1.f, 0.f, 1.f);
    vec[3].uv = Vec2(0.f, 1.f);
 
    vector<uint32> indexVec;
    {
        indexVec.push_back(0);
        indexVec.push_back(1);
        indexVec.push_back(2);
    }
    {
        indexVec.push_back(0);
        indexVec.push_back(2);
        indexVec.push_back(3);
    }
 
    mesh->Init(vec, indexVec);
 
    shader->Init(L"..\\Resources\\Shader\\default.hlsli");
 
    texture->Init(L"..\\Resources\\Texture\\Manduk.png");
 
    GEngine->GetCmdQueue()->WaitSync();
}
 
void Game::Update()
{
    GEngine->RenderBegin();
 
    shader->Update();
 
    {
        Transform t;
        t.offset = Vec4(0.25f, 0.25f, 0.2f, 0.f);
        mesh->SetTransform(t);
 
        mesh->SetTexture(texture);
 
        mesh->Render();
    }
 
    {
        Transform t;
        t.offset = Vec4(0.f, 0.f, 0.3f, 0.f);
        mesh->SetTransform(t);
 
        mesh->SetTexture(texture);
 
        mesh->Render();
    }
 
    
 
    GEngine->RenderEnd();
}
 
cs

 

 

  • 이전과는 다르게 사각형을 두개 생성해주는 것을 확인할 수 있다.
  • 또 Transform t를 활용하여 사각형의 pos와 depth 값을 변경하여 차이를 주는 모습도 확인할 수 있다.

 

 

<DepthStencilBuffer.cpp>

 

더보기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include "pch.h"
#include "DepthStencilBuffer.h"
#include "Engine.h"
 
void DepthStencilBuffer::Init(const WindowInfo& window, DXGI_FORMAT dsvFormat)
{
    _dsvFormat = 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);
}
 
cs

 

 

  • 우선 현재까지는 Stencil 기능을 제외한 Depth Buffer로만 사용할 것이기 때문에 dsvFormat은 기본적으로 DXGI_FORMAT_D32_FLOAT (4Byte) 으로 지정하였다. (Stencil까지 활용하려면 DXGI_FORMAT_D24_UNORM_S8_UINT 를 사용하면 된다.)
  • 또 window를 받아줌으로써 화면의 크기를 받은 뒤, 같은 크기의 Depth Stencil Tex2D를 생성한다.
  • optimizedClearValue = Depth Buffer를 DXGI_FORMAT_D32_FLOAT 포멧, 1.0f 값으로 초기화.
  • 위의 정보를 토대로 _dsvBuffer를 생성한 뒤 DSV 타입의 Descriptor heap을 만들어준 뒤 DSV 생성.

 

 


 

 

 

결과

 

결과물 출력

 

여태 중앙에 출력했던 사각형 오브젝트 보다

우측 상단에 새롭게 생성한 사각형이 더욱 가까워 이전의 사각형이 덮어 씌워진 모습을 확인할 수 있다.