Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
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
Archives
Today
Total
관리 메뉴

codingfarm

4. Direct3D의 초기화 본문

computer graphics/DX12 book

4. Direct3D의 초기화

scarecrow1992 2021. 1. 25. 18:03

이제 Direct3D를 초기화하는 구체적인 방법을 살펴본다.

Direct3D의 초기화 과정은 꽤 길지만, 응용 프로그램 실행시 한 번만 해 주면 된다.

이 포스팅에서 다루는 Direct3D 초기화 과정은 다음과 같은 단계들로 구성된다.

1. Device 생성

2. Fence 객체 생성, 서술자들의 크기 확보

3. 4X MSAA 품질 수준 지원 여부 점검

4. command queue와 command allocator 그리고 command list를 생성한다.

5. 교환사슬을 서술하고 생성한다.

6. 응용 프로그램에 필요한 서술자 힙들을 생성한다.

7. 후면 버퍼의 크기를 설정하고, 후면 버퍼에 대한 렌더 대상 뷰를 생성한다.

8. 깊이$\cdot$스텐실 버퍼를 생성하고, 그와 연관된 깊이$\cdot$스텐실 뷰를 생성한다.

9. 뷰포트와 가위 판전용 사각형들을 설정한다.

 


1. 장치 생성

링크 참조


2. 울타리 생성과 서술자 크기 얻기

링크 참조


3. 4X MSAA 품질 수준 지원 점검

4X MSAA 지원여부를 점검하는 방법에 대해 알아본다.

4X MSAA를 기본으로 선택한 이유는 비용이 그리 크지 않으면서도 화질이 많이 개선된다는 점과 모든 Direct3D 11급 장치가 모든 렌더 대상 형식에서 4X MSAA를 지원한다는 점이다. 현재 장치의 기능 수준이 Direct3D 11이상임을 확인했다면 4X MSAA 지원 여부는 따로 확인할 필요가 없지만, 그래도 이 책의 예제들은 다음과 같이 코드를 통해서 4X MSAA 지원 여부를 명시적으로 점검한다.

1
2
3
4
5
6
7
8
9
10
11
12
D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msQualityLevels;
    msQualityLevels.Format = mBackBufferFormat;
    msQualityLevels.SampleCount = 4;
    msQualityLevels.Flags = D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE;
    msQualityLevels.NumQualityLevels = 0;
    ThrowIfFailed(md3dDevice->CheckFeatureSupport(
        D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,
        &msQualityLevels,
        sizeof(msQualityLevels)));
 
    m4xMsaaQuality = msQualityLevels.NumQualityLevels;
    assert(m4xMsaaQuality > 0 && "Unexpected MSAA quality level.");
cs

4X MSAA가 항상 지원되므로, 반환된 품질 수준(m4xMsaaQuality)는 항상 0보다 커야 한다. 위의 코드는 이 점을 단언문(assert)을 이용해서 확인한다.

 


4. Command Queue와 Command List 생성

링크 참조


5. Swap Chain의 서술과 생성

링크 참조


6. 서술자 힙 생성

링크 참조


7. 렌더 대상 뷰(RGV) 생성

링크 참조


8. 깊이$\cdot$스텐실 버퍼와 뷰(DSV) 생성

링크 참조


9. 뷰포트 설정

보통은 3차원 장면을 화면 전체에 해당하는 후면 버퍼(전체 화면 모드의 경우) 또는 창의 클라이언트 영역 전체에 해당하는 후면 버퍼 전체에만 그리지만, 필요하다면 3차원 장면을 후면 버퍼의 일부를 차지하는 직사각형 영역에만 그리는 것도 가능하다. 그 예는 아래 그림과 같다.

뷰포트를 수정하여 3차원 장면을 후면 버퍼의 한 부분직사각형에 그린 모습이다. 이후 후면 버퍼가 응용 프로그램 창의 클라이언트 영역에 제시된다.

 

장면을 그려 놓고자 하는 후면 버퍼의 부

분직사각형(subrectangle) 영역을 뷰포트(viewport)라고 부른다. 다음은 이 뷰포트를 서술하는 데 쓰이는 구조체이다.

1
2
3
4
5
6
7
8
typedef struct D3D12_VIEWPORT {
  FLOAT TopLeftX;
  FLOAT TopLeftY;
  FLOAT Width;
  FLOAT Height;
  FLOAT MinDepth;
  FLOAT MaxDepth;
} D3D12_VIEWPORT;
cs

이 구조체의 처음 네 자료 멤버는 뷰포트 직사각형의 위치와 크기를 결정한다(자료 멤버들의 형식이 float 이므로 분수(소수점) 픽셀 좌표도 사용할 수 있음에 주목하라).

Direct3D에서 깊이 값들은 0 이상 1 이하의 구간(범위)으로 정규화된다. MinDepth 멤버와 MaxDepth 멤버는 깊이 구간[0, 1]을 깊이 구간 [MinDepth, MaxDepth]로 변환하는데 쓰인다. 이러한 깊이 구간 변환을 활용하면 몇가지 특별한 효과를 구현할 수 있다. 예를 들어 MinDepth=0, MaxDepth=0으로 설정하면 이 뷰포트에 그려진 모든 물체는 깊이 값이 0이 되어서 장면의 다른 모든 객체보다 앞에 나타나게 된다. 그렇지만 보통은 MinDepth를 0으로, MaxDepth를 1로 설정해서 깊이 값들이 바뀌지 않게 한다.

D3D12_VIEWPORT 구조체를 모두 채운 후에는 ID3D12CommandList::RSSetViewports 메서드를 이용해서 뷰포트를 Direct3D에 설정한다. 다음은 후면 버퍼 전체에 장면을 그리는 뷰포트를 설정하는 예이다.

1
2
3
4
5
6
7
D3D12_VIEWPORT vp;
vp.TopLeftX = 0.0f
vp.TopLeftY = 0.0f
vp.Width    = static_cast<float>(mClientWidth);
vp.Height    = static_cast<float>(mClientHeight);
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
cs

 

RSSetViewports 메서드의 첫 매개변수는 설정할 뷰포트들의 갯수이고(고급 효과에는 여러 개의 뷰포트가 필요할 수 있다.), 둘째 매개변수는 뷰 포트 구조체들의 배열을 가리키는 포인터이다.

하나의 렌더 대상에 여러 개의 뷰포트를 지정할 수는 없다. 다붕 뷰포트는 장면을 동시에 여러 개의 렌더 대상에 렌더링 하는 고급 기법들에 쓰인다.
명령 목록을 재설정(Reset) 하면 뷰포트들도 재설정해야 한다.

뷰포트의 용도 중 하나는 2인용 모드를 위한 화면 분할이다.

그런 경우 화면 왼쪽 절반을 위한 뷰포트와 화면 오른쪽 절반을 위한 뷰포트를 만들고, 플레이어 1의 관점에서 본 3차원 장면을 왼쪽 뷰포트에, 플레이어 2의 관점에서 본 장면은 오른쪽 뷰포트에 그리면 된다.

 


10. 가위 직사각형(scissor rectangle) 설정

scissor rectangle은 특정 픽셀들을 선별(culling)하는 용도로 쓰인다. 후면 버퍼를 기준으로 가위 직사각형을 정의, 설정하면, 렌더링 시 가위 직사각형의 바깥에 있는 픽셀들은 후면 버퍼에 래스터화 되지 않는다. 이러한 픽셀 선별은 일종의 최적화 기법이다. 예를 들어 다른 모든것을 가리는 직사각형 UI요소가 화면의 특정 영역에 있다면, 그 부분에 있는 3차원 세계의 픽셀들은 처리할 필요가 없다(어차피 그 UI 요소가 가릴 것이므로).

가위 직사각형은 D3D12_RECT 라는 구조체로 서술한다. 사실 이 구조체는 구조체 RECT에 typedef를 이용해서 다른 이름을 붙인 것이다. 구조체 RECT의 정의는 다음과 같다.

1
2
3
4
5
6
typedef struct tagRECT {
    LONG left;
    LONG top;
    LONG right;
    LONG bottom;
} RECT;
cs

가위 직사각형을 Direct3D에 설정할 때에는 ID3D12CommandList::RSSetScissorRects 라는 메서드를 사용한다. 다음은 후면 버퍼의 왼쪽 위 사분면(제 2 사분면)을 덮는 가위 직사각형을 설정하는 예이다.

1
2
mScissorRect = { 00, mClientWidth/2, mClientHeight/2 };
mCommandList->RSSetScissorRects(1&mScissorRect);
cs

RSSetViewports 메서드와 비슷하게, 이 메서드의 첫 매개변수는 설정할 가위 직사각형들의 갯수이고(고급 효과에는 여러 개의 가위 직사각형이 필요할 수 있다), 둘째 매개변수는 직사각형 구조체들의 배열을 가리키는 포인터이다.

하나의 렌더 대상에 여러개의 가위 직사각형을 지정할 수는 없다. 다중 가위 직사각형은 장면을 동시에 여러 개의 렌더 대상에 렌더링 하는 고급 기법들에 쓰인다.
명령 목록을 재설정(Reset)하면 가위 직사각형들도 재설정해야 한다.

 

 

 

 

Comments