C++ Rookiss Part2 게임 수학과 DirectX12 : 기본 지식
🙇♀️DirectX3D의 초기화
- 3차원 그래픽 하드웨어의 프로그래밍에서 Direct3D의 역할을 개괄적으로 이해
- Direct3D에서 COM의 역할을 이해
- 2차원 이미지의 저장 방식, 페이지 전환, 깊이 버퍼링, 다중표본환 같은 기초 그래픽 개념 배우기
- 성능 카운터 함수들을 이용해서 고해상도 타이머 값을 얻는 방법 배우기
- Direct3D를 초기화하는 방법을 파악
- 이 책의 모든 예제 프로그램이 사용하는 응용 프로그램 프레임워크의 전반적인 구조를 숙지
🪐기본 지식
🪐Direct3D
Direct3D는 응용 프로그램에서 GPU를 제어하고 프로그래밍하는 데 쓰이는 저수준 그래픽 API이다.
🪐COM
COM (Component Object Model)은 DirectX의 프로그래밍 언어 독립성과 하위 호환성을 가능하게 하는 기술이다.
이 책에서 사용하는 매서드
- Get : 바탕 COM 인터페이스를 가리키는 포인터를 돌려준다. 해당 COM 인터페이스 포인터 형식의 인수를 받는 함수를 호출할 때 흔히 쓰인다. 예를 들면 다음과 같다.
ComPtr<ID3D12RootSignature> mRootSignature;
...
// SetGraphicsRootSignature는 ID3D12RootSignature* 형식의 인수를 받는다
mCommandList->SetGraphicsRootSignature(mRootSignature.Get());
- GetAddressOf : 바탕 COM 인터페이스를 가리키는 포인터의 주소를 돌려준다. 함수 매개변수를 통해서 COM 인터페이스 포인터를 돌려받을 때 흔히 쓰인다. 예를 들면 다음과 같다.
ComPtr<ID3D12CommandAllocator> mDirectCmdListAlloc;
...
ThrowIfFailed(md3dDevice->CreateCommandAllocator(
D3D12_COMMAND_LIST_TYPE_DIRECT,
mDirectCmdListAlloc.GetAddressOf()));
- Reset : ComPtr 인스턴스를 nullptr로 설정하고 바탕 COM 인터페이스의 참조 횟수를 1 감소한다. 이 메서드를 사용하는 대신 ComPtr 인스턴스에 직접 nullptr를 배정해도 된다 (역시 참조 횟수가 감소한다)
참고 : COM 인터페이스들은 이름이 대문자 I로 시작한다.
🪐텍스처 형식
2차원 텍스처는 자료 원소들의 행렬(2차원 배열)이다. 이미지 자료를 저장할 수 있고, 이때 텍스처의 각 원소는 픽셀 하나의 색상을 담는다. 혹은 벡터를 담을 수 있다.
1차원 텍스처 -> 1차원 배열, $\,$ 3차원 텍스처 -> 3차원 배열
텍스처에는 특정 형식의 자료 원소들만 담을 수 있는데, 구체적인 형식은 DXGI_FORMAT
이라는 열거형으로 지정한다. 다음은 텍스처에 담을 수 있는 자료 원소 형식들의 예이다.
- DXGI_FORMAT_R32G32B32_FLOAT : 각 원소는 32비트 부동소수점 성분 세 개로 이루어진다.
- DXGI_FORMAT_R16G16B16A16_UNORM : 각 원소는 [0, 1] 구간으로 사상되는 16비트 성분 네 개로 이루어진다.
- DXGI_FORMAT_R32G32_UINT : 각 원소는 부호 없는 32비트 정수 성분 두 개로 이루어진다.
- DXGI_FORMAT_R8G8B8A8_UNORM : 각 원소는 [0, 1] 구간으로 사상되는 부호 없는 8비트 성분 네 개로 이루어진다.
- DXGI_FORMAT_R8G8B8A8_SNORM : 각 원소는 [-1, 1] 구간으로 사상되는 부호 있는 8비트 성분 네 개로 이루어진다.
- DXGI_FORMAT_R8G8B8A8_SINT : 각 원소는 [-128, 127] 구간으로 사상되는 부호 있는 8비트 정수 성분 네 개로 이루어진다.
- DXGI_FORMAT_R8G8B8A8_UINT : 각 원소는 [0, 255] 구간으로 사상되는 부호 없는 8비트 정수 성분 네 개로 이루어진다.
$
R : red
G : green
B : blue
A : alpha
$
무형식 텍스처들도 있다. 메모리만 확보해 두고 자료의 구체적인 해석 방식은 나중에 텍스처를 파이프라인에 묶을 때 지정하는 용도로 쓰인다. 예를 들어 다음의 무형식 텍스처 형식은 원소마다 16비트 성분 네 개를 할당하되, 각 16비트 성분의 구체적인 자료 형식은 지정하지 않는다.
DXGI_FORMAT_R16G16B16A16_TYPELESS
DXGI_FORMAT 열거형은 정점 자료 형식과 색인 자료 형식을 서술할 때에도 쓰인다.
🪐교환 사슬과 페이지 전환
- 애니메이션이 껌벅이는 현상 피하기
- 애니메이션의 한 프레임 전체를 화면 바깥(off-screen)의 텍스처에 그린다. => 후면 버퍼(back buffer)
- 그 후면 버퍼를 하나의 완전한 프레임으로서 화면에 표시
- 이러면 그려지는 과정 x => 이중 버퍼링
- 전면 버퍼와 후면 버퍼, 두 개의 텍스처 버퍼를 번갈아가며 화면에 출력
- 전면 버퍼가 화면에 표시된 동안 다음 프레임을 후면 버퍼에 그리고 역할을 맞바꾼다.
- 후면 버퍼와 전면 버퍼의 역할을 교환해서 페이지가 전환되게 하는 것을 Direct3D에서는 제시라고 부른다.
전면 버퍼와 후면 버퍼는 하나의 교환 사슬을 형성한다. Direct3D에서 교환 사슬을 대표하는 인터페이스는 IDXGISwapChain이다. 이 인테페이스는 전면 버퍼 텍스처와 후면 버퍼 텍스처를 담으며, 버퍼 크기 변경을 위한 메서드(IDXGISwapChain::ResizeBuffers)와 버퍼의 제시를 위한 메서드(IDXGISwapChain::Present)도 제공한다.
삼중 버퍼링도 가능! 하지만 일반적으론 이중 버퍼링으로 충분
🪐깊이 버퍼링
깊이 버퍼는 이미지 자료를 담지 않는 텍스처의 한 예이다. 깊이 버퍼는 각 픽셀의 깊이 정보를 담는다. 픽셀의 깊이는 0.0에서 1.0까지 값으로, 0은 관찰자에 최대한 가까운거 1은 최대한 먼 물체에 해당한다. 깊이 버퍼의 원소들과 후면 버퍼의 픽셀들은 일대일로 대응된다. 후면 버퍼의 해상도가 $1280 \times 1024$라면 깊이 버퍼는 $1280 \times 1024$개의 원소들로 구성된다.
한 물체의 픽셀들이 다른 물체보다 앞에 있는지 판정하기 위해, Direct3D는 깊이 버퍼링또는 z-버퍼링이라는 기법을 사용. 깊이 값을 비교해서 가장 가까운 픽셀이 후면 버퍼에 저장.
깊이 버퍼는 하나의 텍스처이므로, 생성 시 특정한 자료 원소 형식을 지정할 필요가 있다. 깊이 버퍼링을 위한 텍스처 자료 원소 형식으로는 다음과 같은 것들이 있다.
- DXGI_FORMAT_D32_FLOAT_S8X24_UINT : 각 텍셀은 32비트 부동소수점 깊이 값과 [0, 255] 구간으로 사상되는 부호 없는 8비트 정수 스텐실 값(스텐실 버퍼에 쓰임), 그리고 다른 용도 없이 채움(padding)용으로만 쓰이는 24비트로 구성된다.
- DXGI_FORMAT_D32_FLOAT : 각 텍셀은 하나의 32비트 부동소수점 깊이 값이다.
- DXGI_FORMAT_D24_UNORM_S8_UINT : 각 텍셀은 [0, 1] 구간으로 사상되는 부호 없는 24비트 깊이 값 하나와 [0, 255] 구간으로 사상되는 부호 없는 8비트 정수 스텐실값으로 구성된다.
- DXGI_FORMAT_D16_UNORM : 각 텍셀은 [0, 1] 구간으로 사상되는 부호 없는 16비트 깊이 값이다.
🪐자원과 서술자
랜더링 과정에서 GPU는 자원들에 자료를 기록하거나 (후면 버퍼, 깊이 버퍼, 스텐실 버퍼) 자원들에서 자료를 읽어들인다(표면의 모습을 서술하는 텍스처, 장면 안의 기하구조의 3차원 위치들을 담은 버퍼). 그리기 명령을 제출하기 전에, 먼저 해당 그리기 호출이 참조할 자원들을 랜더링 파이프라인에 묶어야한다. => 자원을 파이프라인에 “연결한다”또는 “바인딩한다”라고 말하기도 한다. GPU 자원들이 파이프라인에 직접 묶이는 것은 아니다. 실제로 파이프라인에 묶이는 것은 해당 자원을 참조하는 서술자 객체이다. GPU는 자원 서술자를 통해서 자언의 실제 자료를 접근, 자료를 사용하는 데 필요한 정보도 자원 서술자로부터 얻는다.
서술자의 형식들
- CBV/SRV/UAV 서술자들은 각각 상수 버퍼(contant buffer), 셰이더 버퍼(shader buffer), 순서 없는 접근(unordered access view)을 서술한다.
- 표본추출기 서술자는 텍스처 적용에 쓰이는 표본추출기(sampler)자원을 서술한다.
- RTV 서술자는 렌더 대상(render target) 자원을 서술한다.
- DSV 서술자는 깊이/스텐실(depth/stencil) 자원을 서술한다.
서술자 힙은 서술자들의 배열이다.
서술자들은 응용 프로그램으 초기화 시점에서 생성해야 한다.
🪐다중표본화의 이론
흔히 ‘계단 현상’이라고 불리는 앨리어싱을 없애기 위한 방법 중 하나가 초과표본화이다. 초과표본화에서는 후면 버퍼와 깊이 버퍼를 화면 해상도보다 4배(가로, 세로 두 배씩) 크게 잡고, 3차원 장면을 4배 크기의 해상도에서 후면 버퍼에 렌더링한다. 이미지를 화면에 제시할 때가 되면 후면 버퍼를 원래 크기의 버퍼로 환원한다.
Direct3D는 다중표본화라는 앨리어싱 제거 기법을 자원한다.
🪐DXGI(DirectX Graphics Infrastructure)
여러 가지 공통적인 그래픽 기능성을 처리.