
DirectX 11 의 처리 흐름도는 크게 다음과 같다.
DirectX 11 library 참조
#include <d3d11.h> #include <d3dcompiler.h> #include <DirectXMath.h> #pragma comment(lib, "d3d11") #pragma comment(lib, "d3dcompiler") using namespace DirectX;
Smart Pointer library 참조
#include <wrl.h> using namespace Microsoft::WRL;
DirectX의 Reference Counter는 객체에 대한 이해가 필요하므로 관리가 어렵다.
용이한 관리 위해 MS에서 만든 Smart Pointer 기능을 사용한다.
template <typename T> class ComPtr { private: T* m_Ptr; public: void* GetAddressOf(){return &m_Ptr;} T* Get(){return m_Ptr;} public: ComPtr() :m_Ptr(nullptr){} ~ComPtr(){ if(m_Ptr) Release(m_Ptr); } }
GetAdressOf() : 멤버포인터의 주소를 넘김 (doublePointer)Get() : 멤버포인트가 가진 주소를 넘김 (Pointer)DirectX 11에서는 6단계의 Feature Level을 정의하여 이전 버전의 디바이스여도(DirectX 9/10/10.1) 호환 가능하다.
어플리케이션은 Feature Level에 따라 DirectX 11의 기능을 사용해 실행된다.
이 전 포스팅에서도 설명하였지만 DirectX 11의 기능은 피처 레벨에 의해 6단계로 나누어져있다
about D3D_FEATURE_LEVEL
// array of feature levels D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0, }; // array size UINT numFeatureLevels = ARRAYSIZE( featureLevels ); // device 생성 시 넘길 feature level 변수 D3D_FEATURE_LEVEL g_featureLevel = D3D_FEATURE_LEVEL_11_0;
DirectX 11을 사용하려면 [ Device ] [ Device Context ] [ SwapChain(DXGI) ] 인터페이스를 얻어야 한다.
D3D11CreateDeviceAndSwapChain 함수를 사용하면 위에서 언급한 3개의 인터페이스를 한번에 얻을 수 있다.
interface 변수 선언
// interface ComPtr<ID3D11Device> pDevice; ComPtr<ID3D11DeviceContext> pImmediateContext; ComPtr<IDXGISwapChain> pSwapChain;
Device flag 설정
debug version에서는D3D11_CREATE_DEVICE_DEBUG를, release version에선 0으로 설정한다.
D3D11_CREATE_DEVICE_DEBUG: 세팅하는 경우 GPU의 log 출력됨UINT createDeviceFlags = 0; #ifdef _DEBUG createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; #endif
Swap Cahin 설정
DXGI_SWAP_CHAIN_DESC구조체를 사용해 설정할 수 있으며
백버퍼 설정, SwapChain과 관련할 윈도우 멀티샘플 설정, 화면모드 설정 등을 지정한다.
- 해당 멤버들은 디폴트 동작이 0으로 설정되어 있는 경우가 많으므로
모든 멤버를 설정하지 않을 경우에는::ZeroMemory함수로 초기화하는 것이 편리함- 1600*900 resolution의 backBuffer 1개 SwapChain을 설정하는 예
DXGI_SWAP_CHAIN_DESC sd; ZeroMemory( &sd, sizeof( sd ) ); // 구조체 초기화 sd.BufferCount = 1; // backBuffer Count sd.BufferDesc.Width = 1600; // backBuffer Resolution sd.BufferDesc.Height = 900; sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // backBuffer Format sd.BufferDesc.RefreshRate.Numerator = 60; // 화면 주사율 (기본적으로 60/1) sd.BufferDesc.RefreshRate.Denominator = 1; sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // backBuffer 용도 sd.OutputWindow = g_hWnd; // buffuer output window sd.SampleDesc.Count = 1; // multi sampling count sd.SampleDesc.Quality = 0; // multi sampling quality sd.Windowed = TRUE; // window mod
D3D11CreateDeviceAndSwapChain 호출
D3D11CreateDevice,CreateSwapChain으로 나누어 호출해도 됨CreateSwapChain: Factory가 호출
- SwapChain 생성 과정: Device -> Adapter -> Factory -> Swapchain
hr = D3D11CreateDeviceAndSwapChain( NULL, //사용할 IDXGIAdapter 인터페이스 D3D_DRIVER_TYPE_HARDWARE, //DirectX 11 디바이스 종류 NULL, //보통 NULL createDeviceFlags, //디바이스 플래그 featureLevels, //featureLevel 사용할 배열 numFeatureLevels, //featureLevel arr count D3D11_SDK_VERSION, //DirectX SDK 버전 &sd, //스왑체인 구조체 pSwapChain.GetAddressOf(), //할당할 SwapChain 인터페이스 포인터 pDevice.GetAddress(), //할당할 Device 인터페이스 포인터 &g_featureLevel, //featureLevel 얻어낼 포인터 pImmediateContext.GetAddressOf() ); //할당할 Device Context 인터페이스 포인터
swapChain의 backBuffer는 render target으로 설정되어 있지 않다.
swapChain으로부터 backBuffer를 얻어 Device의 renderTarget으로 설정해야 한다.
Get BackBuffer
SwapChain으로부터 BackBuffer를 얻어온다.
IDXGISwapChain::GetBuffer함수: backBuffer의 포인터 얻음ComPtr<ID3D11Texture2D> pBackBuffer; hr = pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), ( LPVOID* )pBackBuffer.GetAddress() ); if( FAILED( hr ) ) return hr;
Create Render Target View
texture는 view를 통해 pipeline과 access한다.
render target view는D3D11_RENDER_TARGET_VIEW_DESC구조체로 설정하며, 디폴트 설정으로 NULL을 넘긴다.hr = g_pd3dDevice->CreateRenderTargetView( pBackBuffer.Get() //access할 resource , NULL , &pRenderTargetView.GetAddressOf() ); //render target view를 받아올 변수 ptr if( FAILED( hr ) ) return hr;
Create Depth Stencil Texture
D3D11_TEXTURE2D_DESC구조체로 설정한다.
- DepthStencil Buffer: https://velog.io/@howru_dv/Culling
D3D11_TEXTURE2D_DESC Desc = {}; ZeroMemory( &descDepth, sizeof(descDepth) ); //초기화 Desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; // depth 24bit + stencil 8bit Desc.Width = (UINT)m_vRenderResolution.x; // render target texture 해상도와 같아야 함 Desc.Height = (UINT)m_vRenderResolution.y; Desc.BindFlags = D3D11_BIND_DEPTH_STENCIL; // 용도 Desc.CPUAccessFlags = 0; // CPU 접근 불가 Desc.Usage = D3D11_USAGE_DEFAULT; Desc.SampleDesc.Count = 1; // multi sampling Desc.SampleDesc.Quality = 0; Desc.MipLevels = 1; // 저퀄리티 버전 사본 생성여부 Desc.MiscFlags = 0; // 그 외 설정 없음 Desc.ArraySize = 1; hr = m_Device->CreateTexture2D(&Desc, nullptr, m_DSTex.GetAddressOf()); if (FAILED( hr )) return hr;
Get Depth Stencil View
ID3D11DepthStencilView인터페이스 사용ID3D11Device::CreateDepthStencilView함수로 생성m_Device->CreateDepthStencilView(m_DSTex.Get(), nullptr, m_DSView.GetAddressOf());
Set RenderTarget
Output Merger(OM)에서 render target을 설정한다.
렌더타겟은 동시에 8개까지 설정할 수 있지만 깊이/스텐실 버퍼는 1개 뿐이다.
ID3D11DeviceContext::OMSetRenderTargets()함수를 통해 설정한다g_pImmediateContext->OMSetRenderTargets( 1 //renderTarget count , pRenderTargetView.GetAddressOf() //renderTargetView arr pp , m_DSTex.Get() ); //DepthStencil
viewport는 render target의 rendering 영역에 대한 설정이다.
render target에 rendering하려면 각 render target마다 viewport를 설정해야 한다.
ID3D11DeviceContext::RSSetViewports() 함수로 viewport 설정D3D11_VIEWPORT 구조체로 수행하며, float 형으로 사용geometry shader, 또는 vertex shader로부터 출력되는 vertex의 위치좌표(3D)는 투영변환 후 투영좌표계의 값이 된다 (x,y = -1 ~1, z = 0~1)
rasterizer는 뷰포트변환을 수행해 3D 투영좌표계로부터 2D 스크린 좌표(x,y = 0~1)을 계산한다
Viewport 설정
D3D11_VIEWPORT vp; vp.Width =1900.f; vp.Height = 600.f; vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = 0; vp.TopLeftY = 0; g_pImmediateContext->RSSetViewports( 1, &vp ); // rasterizer viewport setting
References
[1] DirectX Tutorial: https://blog.naver.com/sorkelf/40161126408