본문 바로가기
서적 정리/DirectX11을 이용한 3D 게임 프로그래밍 입문

25.Direct3D의 초기화

by 민돌이2 2022. 1. 20.

Direct3D 초기화 과정은 크게 다음과 같은 순서로 구성된다.

1.D3D11CreateDevice 함수를 이용해서 ID3D11Device 인터페이스인 장치와 ID3D11DeviceContext 인터페이스인 장치 문맥을 생성한다.

2.ID3D11Device::CheckMultisampleQualityLevels 메서드를 이용해서 4X MSAA(*주 1) 품질 수준 지원 여부를 점검한다.

3.생성할 교환 사슬의 특성을 서술하는 DXGI_SWA_CHAIN_DESC 구조체를 채운다.

4.장치를 생성하는 데 사용했던 IDXGIFactory 인터페이스를 질의해서 IDXGISwapChain 인스턴스를 생성한다.

5.교환 사슬의 후면 버퍼에 대한 렌더 대상 뷰를 생성한다.

6.깊이·스텐실 버퍼와 그에 연결되는 깊이·스텐실 뷰를 생성한다.

7.렌더 대상 뷰와 깊이·스텐실 뷰를 Direct3D가 사용할 수 있도록 렌더링 파이프라인의 출력 병합기 단계에 묶는다.

8.뷰포트를 설정한다.

 

 

1.장치와 장치 문맥 생성

Direct3D 초기화의 시작은 Direct3D 11 장치(ID3D11Device)장치 문맥(ID3D11DeviceContext)을 생성하는 것이다. 이 두 인터페이스는 Direct3D의 주된 인터페이스로, 그래픽 장치 하드웨어에 대한 소프트웨어 제어기라고 생각하면 된다. 응용 프로그램은 ID3D11Device와 ID3D11DeviceContext를 통해서 하드웨어에게 할 일을 지시한다. 할 일이란 GPU 메모리에 자원 할당, 후면 버퍼 지우기, 자원을 여러 파이프라인 단계에 묶기, 기하구조 그리기 등을 말한다.

 

ID3D11Device와 ID3D11DeviceContext 인터페이스는 구체적으로 무엇을 담당하는가?

ID3D11Device : 기능 지원 점검과 자원 할당에 쓰인다.

ID3D11DeviceContext : 렌더 대상을 설정하고, 자원을 그래픽 파이프라인에 묶고, GPU가 수행할 렌더링 명령들을 지시하는데 쓰인다.

 

아래의 코드는 장치와 장치 문맥을 생성하는 함수이다.

HRESULT D3D11CreateDevice( ‌IDXGIAdapter* pAdapter, //생설할 장치를 나나태는 디스플레이 어댑터를 지정 ‌D3D_DRIVER_TYPE DriverType, //생성할 드라이버의 타입 지정 ‌HMODULE Software, //소프트웨어 구동기를 지정 ‌UINT Flags, //추가적인 장치 플래그들을 지정 ‌CONST D3D_FEATURE_LEVEL* pFeatureLevels, //D3D_FEATURE_LEVEL 원소들의 배열, 기능 수준 점검하는 순서 ‌UINT FeatureLevels, //pFeatureLevels의 D3D_FEATURE_LEVEL 원소의 개수 ‌UINT SDKVersion, //항상 D3D11_SDK_VERSION을 지정 ‌ID3D11Device** ppDevice, //함수가 생성한 장치를 반환 ‌D3D_FEATURE_LEVEL* pFeatureLevel, //pFeatureLevels 배열에서 처음으로 지원되는 기능을 반환 ‌ID3D11DeviceContext** ppImmediateContext //생성된 장치 문맥 반환 );

D3D11CreateDevice 함수의 매개변수들을 정리해보자.

1.pAdater : 생성할 장치를 나타내는 디스플레이 어댑터를 지정한다. 이 매개변수에 널 값(NULL 또는 0)을 지정하면 기본 디스플레이 어댑터가 사용된다.

2.DriverType : 생성할 Direct3D 디바이스의 종류를 지정한다. 일반적으로 렌더링에 3차원 그래픽 가속이 적용되게 하기 위해 D3D_DRIVER_TYPE_HARDWARE를 지정한다. pAdapter에 NULL 이외의 값을 지정한 경우에는 D3D_DRIVER_TYPE_UNKNOWN을 지정한다.

typedef enum D3D_DRIVER_TYPE { ‌D3D_DRIVER_TYPE_UNKNOWN, //드라이버 유형을 알 수 없다. ‌D3D_DRIVER_TYPE_HARDWARE, //하드웨어에서 Direct3D 기능을 구현하는 드라이버 ‌D3D_DRIVER_TYPE_REFERENCE, //모든 Direct3D 기능을 지원하는 소프트웨어 구현인 참조 드라이버 ‌D3D_DRIVER_TYPE_NULL, //렌더링 기능이 없는 참조 드라이버 ‌D3D_DRIVER_TYPE_SOFTWARE, //소프트웨어에서 완전히 구현된 드라이버 ‌D3D_DRIVER_TYPE_WARP, //고성능 소프트웨어 래스터라이저 };

3.Software : 소프트웨어 래스터라이저를 구현하는 DLL에 대한 핸들이다. DriverType이 D3D_DRIVER_SOFTWARE인 경우 NULL이 들어와서는 안된다. 그외에는 보통 NULL을 사용한다.

4.Flags : DirectX의 API 레이어를 D3D_CREATE_DEVICE_FLAG 값들을 조합하여 설정한다. 조합은 OR 결합을 사용한다.

typedef enum D3D11_CREATE_DEVICE_FLAG { ​​D3D11_CREATE_DEVICE_SINGLETHREADED, //단일 스레드 ​​D3D11_CREATE_DEVICE_DEBUG, //디버그 계층을 지원 ​​D3D11_CREATE_DEVICE_SWITCH_TO_REF, //Direct3D 11에서는 사용하지 않는다. ​​D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS, //다수 스레드가 생성되는 것을 방지 ​​D3D11_CREATE_DEVICE_BGRA_SUPPORT, //BGRA 형식을 지원하는 장치를 만든다. ​​D3D11_CREATE_DEVICE_DEBUGGABLE, //장치와 드라이버가 셰이더 디버깅에 사용할 수 있는 정보를 유지 가능하게 한다. ​​D3D11_CREATE_DEVICE_PREVENT_ALTERING_LAYER_SETTINGS_FROM_REGISTRY, ​​D3D11_CREATE_DEVICE_DISABLE_GPU_TIMEOUT, ​​D3D11_CREATE_DEVICE_VIDEO_SUPPORT };

5.pFeatureLevels : D3D_FEATURE_LEVEL 형식 원소들의 배열을 지정한다. 

6.FeatureLevels : pFeatureLevels 매개변수 배열의 개수를 지정한다. pFeatureLevels이 NULL이면 이 매개변수는 0으로 지정하면 된다.

7.SDKVersion : 사용하고 있는 DirectX의 SDK 버전을 지정한다. 사실상 D3D11_SDK_VERSION만 사용한다고 생각하면 된다.

8.ppDevice : 생성된 장치 개체에 대한 포인터 주소를 반환한다. 이 매개변수가 NULL이면 ID3D11Device가 반환되지 않는다.

9.pFeatureLevel : 성공하면 성공한 pFeatureLevels 배열에서 첫 번째 D3D_FEATURE_LEVEL을 반환한다. 지원되는 기능 수준을 결정할 필요가 없는 경우 NULL을 사용하면 된다.

10.ppImmediateContext : 생성된 장치 문맥 개체에 대한 포인터 주소 반환한다. 이 매개변수가 NULL이면 ID3D11DeviceContext가 반환되지 않는다.

 

 

2.4X MSAA 품질 수준 지원 점검

장치를 생성했으면, 하드웨어가 4X MSAA를 위한 품질 수준을 지원하는지 점검할 수 있다. 모든 Direct3D 11 대응 장치는 모든 렌더 대상 형식에 대해 지원하는 품질 수준이 서로 다르더라도 4X MSAA를 지원한다.

UINT m4xMsaaQuality; HR(md3dDevice->CheckMultisampleQualityLevels(DXGI_FORMAT_F8G8B8A8_UNORM, 4, &m4xMsaaQuality)); assert(m4xMsaaQuality > 0);

4X MSAA가 항상 지원되므로, 반환된 품질 수준 값은 반드시 0보다 커야 한다.

 

 

3.교환 사슬(swap chain)의 설정

품질 수준을 점검했으면, 교환 사슬을 생성해야 한다. 생성하기 이전에 DXGI_SWAP_CHAIN_DESC 구조체의 인스턴스를 만들어서 교환 사슬의 특성들을 설정해야 한다.

typedef struct DXGI_SWAP_CHAIN_DESC { ‌DXGI_MODE_DESC BufferDesc; ‌DXGI_SAMPLE_DESC SampleDesc; ‌DXGI_USAGE BufferUsage; ‌UINT BufferCount; ‌HWND OutputWindow; ‌BOOL Windowed; ‌DXGI_SWAP_EFFECT SwapEffect; ‌UINT Flags; } DXGI_SWAP_CHAIN_DESC;

DXGI_SWAP_CHAIN_DESC 구조체의 매개변수들을 정리해보자.

1.BufferDesc : 생성하고자 하는 후면 버퍼의 속성들을 서술하는 구조체이다.

typedef struct DXGI_MODE_DESC { ‌UINT Width; //해상도 너비 ‌UINT Height; //해상도 높이 ‌DXGI_RATIONAL RefreshRate; //디스플레이 재생빈도(헤르츠 단위) ‌DXGI_FORMAT Format; //후면 버퍼 픽셀 형식 ‌DXGI_MODE_SCANLINE_ORDER ScanlineOrdering; //디스플레이 스캔라인 모드 ‌DXGI_MODE_SCALING Scaling; //디스플레이 비례 모드 } DXGI_MODE_DESC;

2.SampleDesc : 다중표본화를 위해 추출할 표본 개수와 품질 수준을 서술하는 구조체이다(22.8 참고).
3.BufferUsage : 버퍼의 용도를 서술하는 구조체이다. 일반적으로 후면 버퍼는 렌더링용으로 사용하므로 DXGI_USAGE_RENDER_TARGET_OUTPUT을 사용한다.

#define DXGI_CPU_ACCESS_NONE ( 0 ) #define DXGI_CPU_ACCESS_DYNAMIC ( 1 ) #define DXGI_CPU_ACCESS_READ_WRITE ( 2 ) #define DXGI_CPU_ACCESS_SCRATCH ( 3 ) #define DXGI_CPU_ACCESS_FIELD 15 #define DXGI_USAGE_SHADER_INPUT 0x00000010UL #define DXGI_USAGE_RENDER_TARGET_OUTPUT 0x00000020UL #define DXGI_USAGE_BACK_BUFFER 0x00000040UL #define DXGI_USAGE_SHARED 0x00000080UL #define DXGI_USAGE_READ_ONLY 0x00000100UL #define DXGI_USAGE_DISCARD_ON_PRESENT 0x00000200UL #define DXGI_USAGE_UNORDERED_ACCESS 0x00000400UL typedef UINT DXGI_USAGE;

4.BufferCount : 교환 사슬에 사용할 후면 버퍼의 개수이다. 일반적으로 후면 버퍼 하나만 사용하므로 1을 지정한다(이중 버퍼링). 삼중 버퍼링을 원하면 2를 지정하면 된다.
5.OutputWindow : 렌더링 결과를 표시할 창의 핸들을 지정한다.
6.Windowed : 렌더링 화면이 창모드인지 여부를 설정한다. 창 모드를 원하면 true, 전체화면 모드를 원하면 false를 지정하면 된다.
7.SwapEffect : 화면을 표시한 후 표시 버퍼의 처리를 설정한다. 일반적으로 후면 버퍼를 사용한 후에 재사용하지 않고 비우므로 DXGI_SWAP_EFFECT_DISCARD를 사용한다.

enum DXGI_SWAP_EFFECT { ‌DXGI_SWAP_EFFECT_DISCARD = 0, ‌DXGI_SWAP_EFFECT_SEQUENTIAL = 1, ‌DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL = 3, ‌DXGI_SWAP_EFFECT_FLIP_DISCARD = 4 } DXGI_SWAP_EFFECT;

8.Flags : 추가적인 플래그를 설정한다. DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH를 사용하면 응용 프로그램이 전체 화면으로 전활 될 때 응용 프로그램 창의현재 크기에 잘 맞는 디스플레이 모드를 선택한다.

enum DXGI_SWAP_CHAIN_FLAG { ‌DXGI_SWAP_CHAIN_FLAG_NONPREROTATED = 1, ‌DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH = 2, ‌DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE = 4, ‌DXGI_SWAP_CHAIN_FLAG_RESTRICTED_CONTENT = 8, ‌DXGI_SWAP_CHAIN_FLAG_RESTRICT_SHARED_RESOURCE_DRIVER = 16, ‌DXGI_SWAP_CHAIN_FLAG_DISPLAY_ONLY = 32, ‌DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT = 64, ‌DXGI_SWAP_CHAIN_FLAG_FOREGROUND_LAYER = 128, ‌DXGI_SWAP_CHAIN_FLAG_FULLSCREEN_VIDEO = 256, ‌DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO = 512, ‌DXGI_SWAP_CHAIN_FLAG_HW_PROTECTED = 1024, ‌DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING = 2048, ‌DXGI_SWAP_CHAIN_FLAG_RESTRICTED_TO_ALL_HOLOGRAPHIC_DISPLAYS = 4096 } DXGI_SWAP_CHAIN_FLAG;

 

 

 

4.교환 사슬(swap chain)의 생성

교환 사슬을 서술하는 구조체를 설정했다면, IDXGIFactory 인스턴스를 통해 IDXGIFactory::CreateSwapChain 메서드를 호출하여 교환 사슬 인터페이스(IDXGISwapChain)를 생성한다.

HRESULT CreateSwapChain( ‌IUnknown* pDevice, //ID3D11Device를 가리키는 포인터 ‌DXGI_SWAP_CHAIN_DESC* pDesc, //교환 사슬 구조체를 가리키는 포인터 ‌IDXGISwapChain** ppSwapChain //생성된 교환 사슬 인터페이스를 반환 );

IDXGIFactory 인스턴스는 CreateDXGIFactory 함수를 이용해서 얻을 수도 있다. 하지만 CreateDXGIFactory로 얻은IDXGIFactory 인스턴스로 IDXGIFactory::CreateSwapChain을 호출하면 오류가 난다.

따라서 이 오류를 피하기 위해선 장치의 생성에 쓰인 IDXGIFactory 인스턴스를 사용해야 한다. 이 인스턴스를 얻기 위해선 일련의 COM 질의 과정을 거쳐야 한다.

IDXGIDevice* dxgiDevice = 0; HR(md3dDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice)); IDXGIAdapter* dxgiAdapter = 0; HR(dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&dxgiAdapter)); IDXGIFactory* dxgiFactory = 0; HR(dxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)&dxgiFactory)); IDXGISwapChain* mSwapChain; HR(dxgiFactory->CreateSwapChain(md3dDevice, &sd, &mSwapChain)); ReleaseCom(dxgiDevice); ReleaseCom(dxgiAdapter); ReleaseCom(dxgiFactory);

 

 

5.렌더 대상 뷰의 생성

어떤 자원을 파이프라인의 단계에 직접 묶는 것은 아니다. 대신 반드시 자원에 대한 뷰를 생성하고 그 뷰를 파이프라인 단계에 묶어야 한다. 구체적으로, 후면 버퍼를 파이프라인의 출력 병합기(Output Merger : OM) 단계에 묶으려면 우선 후면 버퍼에 대한 렌더 대상 뷰를 생성해야 한다.

ID3D11RenderTargetView* mRenderTargetView; ID3D11Texture2D* backBuffer; mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&backBuffer)); md3dDevice->CreateRenderTargetView(backBuffer, 0, &mRenderTargetView); ReleaseCOM(backBuffer);

위 코드에서 mSwapChain의 함수 GetBuffer는 교환 사슬을 가리키는 포인터를 얻는다. dxgi.h에 들어가면 찾을 수 있다.

HRESULT GetBuffer(UINT Buffer, REFIID riid, void** ppSurface);

1.Buffer : 사용할 후면 버퍼의 인덱스이다. 일반적으로 후면 버퍼는 1개를 사용하므로 주로 0을 지정한다.

2.rrid : 버퍼를 조작하는 데 사용되는 인터페이스 유형이다. 쉽게 말해서 사용될 인터페이스나 클래스의 종류이다.

3.ppSurface : 후면 버퍼 인터페이스에 대한 포인터이다.

 

위 코드에서 md3dDevice의 함수 CreateRenderTargetView는 렌더 대상 뷰를 생성한다. dxgi.h에 들어가면 찾을 수 있다.

HRESULT CreateRenderTargetView( ‌ID3D11Resource *pResource, const D3D11_RENDER_TARGET_VIEW_DESC *pDesc, ‌ID3D11RenderTargetView **ppRTView );

1.pResource : 렌더 대상으로 사용할 자원이다.

2.pDesc : 자원에 담긴 원소들의 자료 형식을 서술하는 구조체이다. 이 매개변수에 널 값(NULL 또는 0)으로 설정하면 밉맵 수준 0의 모든 하위 리소스에 액세스하는 뷰를 만든다.

3.ppRTView : 생성된 렌더 타겟 뷰를 반환한다.

 

 

6.깊이·스텐실 버퍼와 뷰 생성

깊이 버퍼는 그저 깊이 정보를 담는 2차원 텍스처이다. 스텐실을 사용하는 경우엔 스텐실 정보도 담는다. 2차원 텍스처를 생성할 때에는 생성할 텍스처를 서술하는 D3D11_TEXTURE2D_DESC 구조체를 생성하고 ID3D11Device::CreateTexture2D 메서드를 호출해야 한다.

typedef struct D3D11_TEXTURE2D_DESC { ‌UINT Width; //텍스처의 너비(텍셀 단위) ‌UINT Height; //텍스처의 높이(텍셀 단위) ‌UINT MipLevels; //밈맵 수준의 개수. 깊이/스텐실 버퍼를 위한 텍스처에는 하나만 있으면 된다. ‌UINT ArraySize; //텍스처 배열의 텍스처 개수. 깊이/스텐실 버퍼의 경우 텍스처 하나만 있으면 된다. ‌DXGI_FORMAT Format; //텍셀의 형식 ‌DXGI_SAMPLE_DESC SampleDesc; //다중 표본 개수와 품질 수준 ‌D3D11_USAGE Usage; //텍스처의 용도 ‌UINT BindFlags; //자원을 파이프라인에 어떤 식으로 묶을 것인지 지정한다. 결합하여 복수도 가능 ‌UINT CPUAccessFlags; //CPU가 자원에 접근하는 방식을 결정 ‌UINT MiscFlags; //기타 플래그. 깊이/스텐실 버퍼에는 적용되지 않으므로 0을 지정하면 된다. } D3D11_TEXTURE2D_DESC;

 

후면 버퍼와 마찬가지로, 깊이·스텐실 버퍼를 사용하려면 깊이·스텐실 뷰를 생성하고 파이프라인에 붙여야 한다. 그 과정은 렌더 타겟 뷰와 비슷하다.

D3D11_TEXTURE2D_DESC depthStencilDesc; depthStencilDesc.Width = mClientWidth; depthStencilDesc.Height = mClientHeight; depthStencilDesc.MipLevels = 1; depthStencilDesc.ArraySize = 1; depthStencilDesc.Format = DXGI_FORAMT_D24_UNORM_S8_UINT; if (mEnable4xMsaa) { ‌depthStencilDesc.SampleDesc.Count = 4; ‌depthStencilDesc.SampleDesc.Quality = m4xMsaaQuality - 1; } else { ‌depthStencilDesc.SampleDesc.Count = 1; ‌depthStencilDesc.SampleDesc.Quality = 0; } depthStencilDesc.Usage = D3D11_USAGE_DEFUALT; depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; depthStencilDesc.CPUAccessFlags =0; depthStencilDesc.MiscFlags = 0; ID3D11Texture2D* mDepthStencilBuffer; ID3D11DepthStencilView* mDepthStencilView; HR(md3dDevice->CreateTexture2D(&depthStencilDesc, 0, &mDepthStencilBuffer)); HR(md3dDevice->CreateDepthStencilView(mDepthStencilBuffer, 0, &mDepthStencilView));

위 코드에서 md3dDevice의 CreateTexture2D 함수는 2D 텍스처 배열을 만든다. d3d11.h에서 찾을 수 있다.

HRESULT CreateTexture2D( const D3D11_TEXTURE2D_DESC* pDesc, const D3D11_SUBRESOURCE_DATA* pInitialData, ‌ID3D11Texture2D** ppTexture2D; );

1.pDesc : 2D 텍스처 리소스를 설명하는 D3D11_TEXTURE2D_DESC 구조체에 대한 포인터이다.

2.pInitialData : 2D 텍스처 리소스에 대한 하위 리소스를 설명하는 D3D11_SUBRESOURCE_DATA 구조체의 배열에 대한 포인터이다. 텍스처에 채울 초기 자료를 가리키는 포인터라고 생각하면 된다. 깊이·스텐실은 채울 필요가 없다.

3.ppTexture2D : 생성된 텍스처를 반환한다.

 

위 코드에서 md3dDevice의 CreateDepthStencilView 함수는 리소스 데이터에 액세스하기 위한 깊이·스텐실 뷰를 만든다. d3d11.h에서 찾을 수 있다.

HRESULT CreateDepthStencilView( ‌ID3D11Resource* pResource, const D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc, ‌ID3D11DepthStencilView** ppDepthStencilView; );

1.pResource : 깊이·스텐실 표면(*주 2)으로 사용할 리소스에 대한 포인터이다. 뷰를 생성하고자 하는 자원이라고 생각하면 된다. 이 리소스는 D3D11_BIND_DEPTH_STENCIL 플래그로 생성되어야 한다.

2.pDesc : 자원 원소의 자료 형식을 서술하는 D3D11_DEPTH_STENCIL_VIEW_DESC 구조체를 가리키는 포인터이다. 형식을 완전히 지정해서 자원을 생성했다면 널 값을 지정해도 되는데, 널 값을 넣은 경우 주어진 자원을 생성했을 때 지정한 형식을 적용해서 자원의 첫 번째 밉맵 수준(밉맵 0레벨)에 대한 뷰를 생성한다.

3.ppDepthStencilView : 깊이·스텐실 뷰를 반환한다.

 

 

7.뷰들을 출력 병합기(Output Merger : OM) 단계에 묶기

후면 버퍼와 깊이·스텐실 버퍼에 대한 뷰들을 파이프라인의 출력 병합기 단계에 묶어야 한다. 이 과정을 거쳐야 자원들이 파이프라인의 렌더 대상과 깊이·스텐실 버퍼로 작용하게 된다.

md3dImmediateContext->OMSetRenderTargets(1, &mRenderTargetView, mDepthStencilView);

위 코드에서 OMSetRenderTargets 함수의 선언은 아래와 같다.

void OMSetRenderTargets( ‌UINT NumViews, ‌ID3D11RenderTargetView* const* ppRenderTargetViews, ‌ID3D11DepthStencilView* pDepthStencilView );

1.NumViews : 바인드할 렌더 타겟의 수 이다.

2.ppRenderTargetViews : 파이프라인에 바인딩할 렌더 대상을 나타내는 ID3D11RenderTargetView의 배열에 대한 포인터이다. 이 매개변수가 NULL이고 NumViews가 0이면 렌더 타겟이 바인딩되지 않는다.

3.pDepthStencilView : 파이프라인에 바인딩할 깊이·스텐실 뷰이다. 이 매개변수가 NULL이면 깊이·스텐실 뷰가 바인딩되지 않는다.

 

 

8.뷰포트 설정

일반적으로 렌더링할 화면을 후면 버퍼 전체에 그린다. 하지만 화면을 후면 버퍼의 일부만 그리는 것도 가능하다. 쉽게 설명하자면 전체 그림에서 임의의 구역만 그릴 수 도 있다는 뜻이다. 임의의 구역이라고 하지만 직사각형으로 한정되어 있는 것 같다. 이런 후면 버퍼의 임의의 구역을 뷰포트(viewport)라고 한다.

typedef struct D3D11_VIEWPORT { ‌FLOAT TopLeftX; //상단 좌측 x좌표 ‌FLOAT TopLeftY; //상돤 좌측 y좌표 ‌FLOAT Width; //너비 ‌FLOAT Height; //높이 ‌FLOAT MinDepth; //최소 깊이 버퍼 값 ‌FLOAT MaxDepth; //최대 깊이 버퍼 값 } D3D11_VIEWPORT;

MinDepth와 MaxDepth에서 생각해야 할 것은 Direct3D에서 깊이 버퍼 값의 범위는 0 ~ 1이다. 그러므로 특수한 효과를 바라는 것이 아니라면 MinDepth는 0으로, MaxDepth는 1로 설정한다.

 

D3D11_VIEWPORT 구조체를 생성한 후, ID3D11DeviceContext::RSSetViewports 메서드를 호출하여 Direct3D에게 뷰포트를 알려줘야 한다.

D3D11_VIEWPORT vp; md3dImmediateContext->RSSetViewports(1, &vp);

첫 번째 변수는 묶을 뷰포트 개수이고, 두 번째 변수는 뷰포트 배열을 가리키는 포인터이다.

 

뷰포트는 2인용 모드에서 사용할 것이다. It Take Two라던가 A Way Out를 생각하면 된다.

 

 

(*주 1) 4X MSAA

4X는 4배수를 의미하고 MSAA는 multisample anti-aliasing의 약자이다. 즉, 4배 다중표본화를 이용한 앨리어싱 제거를 뜻한다.

 

(*주 2) 표면(surface)

Direct3D에서 표면은 주로 2D 이미지 데이터를 보관하는데 이용하는 픽셀의 행렬을 말한다.

728x90

댓글