※ 본 게시물은 DirectX11을 기준으로 작성한다. 

   또한 순수하게 학습용이므로 절대적으로는 믿지 말 것.


//  "DXApp.cpp"


bool DXApp::InitDirect3D()

{

HRESULT hr;


// 스왑체인 속성 설정 구조체 생성.

DXGI_SWAP_CHAIN_DESC swapDesc;

ZeroMemory(&swapDesc, sizeof(DXGI_SWAP_CHAIN_DESC));

swapDesc.BufferCount = 1;

swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;

swapDesc.OutputWindow = hwnd;

swapDesc.Windowed = true;

swapDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;

swapDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;

swapDesc.BufferDesc.Width = clientWidth;

swapDesc.BufferDesc.Height = clientHeight;

swapDesc.BufferDesc.RefreshRate.Numerator = 60;

swapDesc.BufferDesc.RefreshRate.Denominator = 1;


swapDesc.SampleDesc.Count = 1;

swapDesc.SampleDesc.Quality = 0;


// 장치 및 스왑체인의 생성.

hr = D3D11CreateDeviceAndSwapChain(

NULL, D3D_DRIVER_TYPE_HARDWARE,

NULL, NULL, NULL, NULL,

D3D11_SDK_VERSION, &swapDesc, &pSwapChain, &pDevice,

NULL, &pDeviceContext);

if (FAILED(hr) == true)

{

MessageBox(NULL, L"장치 생성 실패.", L"오류", MB_OK);

return false;

}

// 스왑체인으로부터 백버퍼 가져오기.

ID3D11Texture2D* pBackBufferTexture;

hr = pSwapChain->GetBuffer(NULL, __uuidof(ID3D11Texture2D), (void**)&pBackBufferTexture);

if (FAILED(hr) == true)

{

MessageBox(NULL, L"백버퍼 생성 실패.", L"오류", MB_OK);

return false;

}

// 렌더타겟 생성.

hr = pDevice->CreateRenderTargetView(pBackBufferTexture, NULL, &pRenderTargetView);

if (FAILED(hr) == true)

{

MessageBox(NULL, L"렌더타겟 생성 실패.", L"오류", MB_OK);

return false;

}

// 렌더타겟 설정.

pDeviceContext->OMSetRenderTargets(1, &pRenderTargetView, NULL);

// 백버퍼 텍스처 해제.

if (pBackBufferTexture != NULL)

{

pBackBufferTexture->Release();

pBackBufferTexture = NULL;

}

return true;

}

<HRESULT>

HRESULT는 함수들의 상태정보를 리턴받을 수 있는 타입이다.

BOOL과마찬가지로 SUCCEEDED/FAILED를 사용하는데,

반드시 리턴값을 받지않아도 된다.

cf.)이와 비슷한것으로 LRESULT가 있는데, 이는 콜백함수에서 쓰이며, Win32환경에서 메시지를 처리 후 운영체제에 신호를 주기위해 사용되는 것이다.

*자세한내용은

 http://rockdrumy.tistory.com/801 (참고)


<스왑체인 속성 설정 구조체 생성.>

DXGI_SWAP_CHAIN_DESC swapDesc;

1. swapDesc.BufferCount는 백버퍼 숫자를 의미한다.  프론트버퍼는 무조건 1개가 있다.(그래야 화면을 그리니깐)


2. swapDesc.BufferUsage는 체인을 바꾸는 기법을 나타낸다.  DXGI_USAGE_RENDER_TARGET_OUTPUT는 렌더 타겟의 출력을 목적으로한다는 것.


3. swapDesc.OutputWindow는 window창 출력설정하기위한 핸들을 넣어준다.


4. swapDesc.Windowed에서 true창모드 false는 전체화면모드 -->전체화면시 그래픽설정몇개를 더 바꿔야한다.


5. swapDesc.SwapEffect는 두개 화면 전환시 어떠한 효과를 넣을지 설정하는것. DXGI_SWAP_EFFECT_DISCARD 바로바꿔치게 이것을 사용하길 권장.(디스카드모드)


6. swapDesc.BufferDesc.Format 바꿔치기하는 버퍼의 대상(백버퍼를 생성할 포맷설정). R8G8B8A8-> 8이 4개니까 32bit를 뜻한다. UNORM -> unsigned Normalize 0~1사이값으로 정규화시켰다. 픽셀하나당 32비트고 각각 8비트씩 차지하며 데이터는 0~1까지로 설정됨.


7. swapDesc.BufferDesc.Width / Height 생성할 백버퍼의 해상도를 위한것. 윈도우크기와 같게 하기위해 ClientWidth, ClientHeight를 넣어줬다.


8. swapDesc.BufferDesc.RefreshRate.Numerator = 60; swapDesc.BufferDesc.RefreshRate.Denominator = 1;

화면 주사율 설정 -> 장치마다 다르기때문에... 원래는 라이브러리에따라 다르게 설정하는 api가 존재.

우리나라는 60Hz였을때 크게 문제는 되지않을것이긴하지만 필요할시 나중에 바꿔줘야한다.


9.  샘플링 관련 설정. Antialiasing을 해결하기위한 방법을 샘플링이라 한다.

swapDesc.SampleDesc.Count = 1;   swapDesc.SampleDesc.Quality = 0;

샘플링을 1개만한다는것은 안하겠다는 뜻과 같다 

--> Quality는 Count의 설정에 따라 달라진다.

--> 그래픽카드가 못버티는 수준까지 샘플링을 늘리면 또 안된다.

샘플카운트를 물어보는 api가 따로 존재한다. (super sampling , multi sampling ... ) 지금은 퀄리티를0하는게 맞다. 샘플링을 안한다했으니...


<D3D11CreateDeviceAndSwapChain함수의 인자값>
1. IDXGIAdapter* pAdapter는 표시할 디바이스(비디오카드)의 IDXGIAdapter 인터페이스를 설정. NULL일시에는 최초에 발견한 디바이스를 사용하게된다. 기본적으로 NULL을 많이사용하고, 지정할 디바이스가 있다면 사용해주자.

2. D3D_DRIVER_TYPE DriverType는 생성할 DX11의 디바이스 종류를 설정한다. 최근에 그래픽카드에서는 거의모두 DX를 지원하기에 HARDWARE TYPE을 쓰면 된다. (보통 하드웨어가속을위해...) 아주만약 그래픽처리를 하드웨어에서 지원하지않으면 SOFTWARE TYPE으로!

3. HMODULE Software는 소프트웨어 래스터라이저가 구현되어 있는 DLL 핸들을 지정할때 쓴다. 보통은 NULL값 사용.

4. UINT Flags는 사용할 DX11의 API 레이어를 D3D_CREATE_DEVICE_FLAG 값들을 조합하여 설정 할 수 있다. 우리는 일단 NULL로.

5. CONST D3D_FEATURE_LEVEL* pFeatureLevels을 NULL로 사용시에, 우선순위가 높은순서대로 배열을 채우게된다. DX11->DX10->DX9 순서.

6. UINT FeatureLevels는 5번에서 설정한 피처레벨 배열의 개수를 입력.

7. UINT SDKVersion 사용하고있는 SDK의 버전을 넘겨준다.

8. CONST DXGI_SWAP_CHAIN_DESC* pSwapChainDesc는 스왑체인의 설정값들을 저장한 구조체를 가리킬 포인터 변수이다.

9. IDXGISwapChain** ppSwapChain는 생성한 스왑체인 인터페이스의 인터를 담을 변수이다.

10. ID3D11Device** ppDevice는 생성한 디바이스 인터페이스 포인터를 담을 변수이다.

11. D3D_FEATURE_LEVEL* pFeatureLevel은 생성에 성공시 위 5.번에서 지정했던 배열의 처음값을 돌려준다.실패한 경우에는 0이 반환된다.

12. ID3D11DeviceContext** ppImmediateContext는 생성한 디바이스 컨텍스트 인터페이스의 포인터를 담을 변수이다. 
*자세한내용은 

<스왑체인으로부터 백퍼버 가져오기>
백버퍼 가져올공간만들자. 
ID3D11Texture2D* pBackBufferTexture;
--->백버퍼는 기본적으로 2D텍스처로 만들어져있다.
hr = pSwapChain->GetBuffer(NULL, 
__uuidof(ID3D11Texture2D), 
(void**)&pBackBufferTexture);
---> NULL을넣으면 하나있는 백버퍼가 바로넘어온다. 무슨버퍼를 가리킬지 설정하는게 첫번째 인자값이다.
(버퍼가 여러개면 버퍼의 index값을 넣어주면 된다.) 백버퍼에 접근하는 인터페이스의 타입 가리키는게 2번째 인자값. 백버퍼를 받아올 포인터 변수가 세번째 인자값이 된다.

<RenderTargetView의 생성>
텍스처는 파이프라인으로부터 View를 통해서 접근이가능하다. 따라서 렌더타겟도 텍스처의 일종이기에 렌더타겟뷰를 이용하는것이다.
hr = pDevice->CreateRenderTargetView(
pBackBufferTexture,
NULL,
&pRenderTargetView); 
여기서 첫번째 인자값은 View에서 액세스하는 리소스를 나타내며, (앞에서 백버퍼를 가져온 pBackBufferTexture를 가리키게됨) 두번째 인자값은 View에대한 정의이지만 보통 디폴트값으로 NULL
넘겨준다. 이는 리소스가 만들어졌을때의 포맷을 그대로 사용함을 의미하게되고, 모든 리소스의 밉맵 레벨0에 액세스하는 뷰를 생성.
cf.) 밉맵의 개념
세번째 인자값은 반환된 렌더타겟뷰의 포인터를 가리킬 변수이다.
이 함수 수행결과 pBackBufferTexture를 기반으로 pRenderTargetView가 만들어진다고 보면된다.
그리하면, 직접 백버퍼의 포인터에 접근하지않아도, RenderTargetView를 통해서 백버퍼에 접근할 수 있게된다.
RenderTargetView는 중간데이터라고 생각하면 편한데, 백버퍼라는 리소스와 렌더타겟뷰를 바운딩하여,
개발자가 SwapChain에있는 백버퍼에 직접 접근하지않고, 제사용하는 RenderTargetView를 통해 접근하게 되는것이다. 이는 매프레임마다 렌더타겟뷰에 렌더링을 하게되고(백버퍼와 바인딩된)마지막에 SwapChain을 이용하여 우리가원하는 프론트버퍼인 디바이스 화면에 그리게 되는것이다. 
pSwapChain->Present(1, 0); (후에 엔진클래스에서할것)
<pDeviceContext->OMSetRenderTargets()>
OM의 뜻은 Output-Merger에서 나온것이다. 말그대로 출력결과를 합쳐주는부분이라 할 수 있겠다. 현재까지로는 렌더타겟뷰만을 설정하는부분이다.  렌더타겟은 DX11기준 동시에 최대 8개까지 설정이가능하다.
그 중에서 설정할 수 있는 것이 깊이/스텐실버퍼인데, 깊이/스텐실버퍼는 하나만 가능하다.
첫 번째 인자값이 렌더타겟의 수, 두 번째 인자값이 렌더타겟 뷰의 배열세 번째 인자값이 깊이/스텐실 버퍼인데, 현재는 NULL로 해주겠다.

<pBackBufferTexture의 해제>
우리는 직접 백버퍼의 포인터에 접근할일이 없기 때문에, pBackBufferTexture를 해제해준다.
(다시말해 렌더타겟뷰를 만드는데 사용한 pBackBufferTexture는 이제 필요가 없어졌다.)


+ Recent posts