본문 바로가기

DirectX

[DirectX 12] DirectX 기초 지식

Direct3D는 Graphic Adapter / GPU를 제어하고 프로그래밍하는데 쓰이는 저수준 API
-> 이를 이용해서 응용프로그램이 3D 그래픽 가속 기능을 이용해서 3차원 세계를 그려낸다.

COM 객체
-> Component Object Model은 프로그램이 언어 독립성과 하위 호환성을 가능하게 해주는 기술
COM의 세부 사항은 프로그래머들에게 드러나지 않는다. 프로그래머들은 이 COM 객체를 이용해서 new를 직접할 필요 없이
관리할 수 있다. 그리고 delete 대신 Release를 이용해서 객체 메모리를 해제한다. 그리고 참조 횟수가 0이 되면 자동으로 메모리 해제를 한다.

윈도우에서는 WRL(Windows Runtime Library)를 이용해서 지원을 한다. Microsoft::WRL::ComPtr를 이용해서 선언할 수 있다.
그리고 COM객체가 scope를 벗어나면 알아서 release를 하기 때문에 직접 호출할 필요가 없다.
즉 스마트 포인터와 원리는 굉장히 유사한 것을 알 수 있다.

ComPtr에서 사용하는 메서드는 보통 3가지가 있다.

Get() : COM 인터페이스(객체)를 가리키는 포인터를 돌려준다.
GetAddressOf() : COM 인터페이스를 가리키는 포인터의 주소를 돌려준다. 함수 매개변수를 통해서 COM 인터페이스 포인터를 리턴받을 때 사용한다.
Reset() : COM 인터페이스를 nullptr로 설정하고 참조 횟수를 1 감소한다. 

텍스처 : 2차원의 자료 행렬이다. 각 원소당 픽셀의 색상을 담거나 이미지 등을 저장하고, 그 외 다양한 옵션을 지원한다.
텍스처는 특정 포맷의 자료 원소만 저장할 수 있는데, DXGI_FORMAT enum 타입을 이용해서 이를 지정한다.

Swap chain : 단순히 렌더링하면, 화면이 깜빡거리는 현상이 생긴다. 
이를 피하기 위해서는 보통 화면에 대한 텍스처 버퍼를 두개를 두고 하나는 그리고, 
하나는 그려진 상태를 화면에 이를 전시(Present)한다. 전자를 후면 버퍼(back buffer)고 후자는 전면 버퍼(front buffer)라 하며, 두개의 버퍼를 사용해서 이를 교환하기에 이중 버퍼링(Double buffering)이라 한다.
그리고 이 전면 버퍼와 후면 버퍼를 바꿔주는 역할을 하는 것이 스왑 체인(Swap chain)이라 한다.
이 스왑체인을 대표하는 인터페이스로는 IDXGISwapChain이다. 

Depth Buffer : 깊이 버퍼는 이미지 자료를 담지 않는 텍스처이다. 깊이 버퍼의 픽셀 깊이에 대한 정보를 담으며, 0.0~1.0까지의 값을 이용해서 시야 절두체(View frustum) 안에서 0에 가까울수록 가까우며 1에 가까울수록 멀다.
그리고 이 버퍼는 후면 버퍼와 크기가 비슷하다. 예로 들어 후면 버퍼의 크기가 1280 x 720이라면 깊이 버퍼 또한 1280 x 720이다.

Direct3D에서는 물체의 깊이 차이를 판별하기 위해서 2가지 방법을 사용하는데, 깊이 버퍼링과 Z-버퍼링을 사용한다.

Discriptor : 책에서는 서술자라 되어있지만 직관적이진 못한거 같다.
사실 Direct3D 입장에서는 자원들을 받아서 이를 처리하기 위해서는 이를 어떻게 처리할 것인가에 대한 기준이 있어야 할 것이다.
이런 기준에 대해 프로그래머가 작성하는 것을 바로 Discriptor라고 한다. 

먼저 그릴 자원들을 렌더링 파이프라인에 묶어준다(Binding, link). 하지만 직접적으로 파이프라인에 묶어주는 것이 아닌 
해당 자원을 Discriptor 참조하는 방식이다. 즉 GPU는 이 Discriptor를 이용해서 실제 자료로 접근하고 이 자원에서 사용하는데 필요한 정보를 Discriptor를 참조하면 얻을 수 있는 것이다.
그래서 Discriptor를 간접층(Level of indirection)이라고도 한다. 
참고로 형식을 지정하지 않은 자원 등등은 여기서 접근을 해서 형식을 지정해준다.

서술자도 굉장히 다양한 방식으로 사용되지만 여기서는 4가지만 소개하겠다.
1. CBV/SRV/UAV : 상수 버퍼나 셰이더 자원, 순서 없는 접근(unordered access view)에 대한 서술을 한다.
2. 표본 추출기 서술자를 통해서 텍스처 적용에 쓰이는 표본추출기(sampler)를 서술한다.
3. Render Targer View 서술자(RTV Discriptor)를 통해서 렌더 대상에 대한 서술을 한다.
4. Depth/Stencil View(DSV Discriptor)를 이용해서 자원에 대한 서술을 한다.

그리고 서술자는 배열을 서술자 힙(Discriptor Heap)을 이용해서 응용 프로그램을 사용하는 서술자들을 저장한다.
또 하나의 자원을 참조하는 서술자를 하나만 두지 않고, 여러 부분 영역에 대해 여러 서술자를 두고 이를 참조할 수 있게 하는데
서술자는 응용 프로그램의 초기화를 하는 시점에서 같이 생성을 해야한다. 그래야 형식 점검 및 유효성 검증을 할 수 있기 때문이다.

앨리어싱 : 모니터의 픽셀은 한정된 자원이다. 그렇기 때문에 픽셀 배열을 근사하다 보면 계단 현상이라 불리는 aliasing 현상이 일어난다.
이를 제거하기 위해 안티앨리어싱(Antialiasing)과정을 거쳐야 한다. 이를 위해서 사용하는 것으로는 초과 표본값(Super Sampling)이란 과정을 거친다.
이 방식은 후면 버퍼와 깊이 버퍼를 4배를 하고 후면 버퍼에 렌더링을 한 뒤 이미지를 화면에 전시할 때 다시 원래 크기로 버퍼를 환원(Resolve)를 한다.
그리고 이 환원 과정에서 4픽셀의 블록에 픽셀 값들을 평균을 내는 방식이다.
하지만 이 방식은 4배의 메모리를 사용한다는 소리이다. 그렇기 때문에 Direct3D에서는 다중표본화(Multi Sampling)을 사용을 한다.
이 방식은 일부 계산 결과를 부분 픽셀들 사이에서 공유하는 방식이기 때문에 초과 표본값보다 비용이 낮은 편이다.

4X 다중표본화(4X MSAA)는 픽셀당 부분 픽셀을 4개 사용해서 이 방식도 일단은 초과 표본화처럼 4배 크기를 가진 버퍼를 사용한다. 
그러나 다중 표본화는 이미지 색상을 각 부분 픽셀들의 가시성과 포괄도(부분 픽셀을 다각형이 얼마나 덮고 있는가)를 이용해서 최종 색상을 결정하는 방식이다.
Direct3D에서는 DXGI_SAMPLE_DESC라는 구조체를 작성하여 사용한다.

DXGI(DirectX Graphics Infrastructure) : DXGI는 Direct3D와 함께 쓰이는 API이다.
여러 그래픽 API들에는 필요한 공통 작업들이 있다. 스왑 체인이나 페이지 전환, 등등이 있는데 이러한 작업들을 하는데 필요한 정보나 공통적 그래픽 기능성을 처리한다.

'DirectX' 카테고리의 다른 글

[DirectX 12] 렌더링 파이프라인  (0) 2022.02.15
[DirectX 12] Direct3D 초기화  (0) 2022.01.10
[DirectX 12] 명령 대기열  (0) 2022.01.06