Tutorial 3: Initializing DirectX 11

Tutorial 3: Initializing DirectX 11 This tutorial will be the first introduction to working with DirectX 11. We will address how to initialize and shut down Direct3D as well as how to render to a window. Updated Framework We are going to add another class

www.rastertek.com

DirectX11의 공부 목적으로 위 링크의 튜토리얼을 보고 제 생각을 포함하여 정리하였습니다.


들어가며

 

이전 포스팅에 이어 D3DClass의 Initialize의 중간인 Swap chain부터 시작한다.

 

 


D3DClass.cpp - Initialzie( )

 

스왑체인부터 시작하는데 이 영상을 보고오면 더 이해하기 쉽다.

https://www.youtube.com/watch?v=7J0tA3Bg6vc

// 스왑체인의 세팅값(DXGI_SWAP_CHAIN_DESC)을 설정하기전 0으로 초기화 한다.
ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));

// 버퍼를 보통 2개, 혹은 3개로 설정하지만 일단 튜토리얼에서는 버퍼 개수를 1개, 싱글 버퍼링으로 동작시킨다.
swapChainDesc.BufferCount = 1;

// 버퍼(도화지)의 크기 설정.
swapChainDesc.BufferDesc.Width = screenWidth;
swapChainDesc.BufferDesc.Height = screenHeight;

// 버퍼(도화지)의 픽셀 형식을 설정.
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;

// 버퍼의 주사율을 설정, 수직 동기화 여부에 따라 분기가 갈린다.
if (m_vsync_enabled)
{
	swapChainDesc.BufferDesc.RefreshRate.Numerator = numerator;
	swapChainDesc.BufferDesc.RefreshRate.Denominator = denominator;
}
// 수직 동기화가 아니라면 주사율의 제한이 없어진다.
else
{
	swapChainDesc.BufferDesc.RefreshRate.Numerator = 0;
	swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
}

// 버퍼의 용도를 설정하는건데 일단 튜토리얼에서는 렌더링할 목적으로 설정했다.
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;

// 버퍼의 핸들을 설정.
swapChainDesc.OutputWindow = hwnd;

// 멀티 샘플링(안티 에일리어싱) 을 끈다.
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;

// 전체 화면의 설정 분기.
if (fullscreen)
{
	swapChainDesc.Windowed = false;
}
else
{
	swapChainDesc.Windowed = true;
}

// 버퍼를 위에서부터 차례대로 그릴건지, 짝수 줄부터 그릴건지, ..등에 대한 세팅, 튜토리얼에서는 기본값 사용.
swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
// 스케일링에 대한 설명, 튜토리얼에서는 기본값 사용.
swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;

// 버퍼의 교체 방식의 세팅 값인데 지금은 단일 버퍼라 의미 없음.
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;

// 플래그를 설정하지 않는다 = 일단 중요하지 않다.
swapChainDesc.Flags = 0;

// 사용할 DirectX의 버전을 정의
featureLevel = D3D_FEATURE_LEVEL_11_0;

// 여태 세팅한 DXGI_SWAP_CHAIN_DESC를 이용해 스왑체인, Direct3D device, Direct3D device context를 생성한다.
result = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, &featureLevel, 1,
		D3D11_SDK_VERSION, &swapChainDesc, &m_swapChain, &m_device, NULL, &m_deviceContext);

여기까지 스왑체인 생성과 동시에 버퍼가 생성되었다. (버퍼는 따로 DX를 통해 운영체제단까지 가서 생성되어 포인터로 연결되는듯 하다.)

 

DX가 그림을 그리는 버퍼 칸이 있는데 이 칸을 Render target view 라고 한다. 우리가 만든 버퍼를 이 칸에 장착시키자.

Render target이라하여 자칫 모니터와 바로 연결된다 착각할 수 도 있지만(바로 나..) 정말 단지 그려지는 타겟(백 버퍼)일 뿐이고 모니터에 뿌려지는 그림은 프론트 버퍼가 담당한다.

이 Render target view를 생성하고 스왑체인의 버퍼와 연결한다.

// 스왑체인의 버퍼 포인터를 가져온다.
result = m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&backBufferPtr);

// 렌더 타겟 뷰(실제 버퍼)를 버퍼를 연결하면서 생성한다.
result = m_device->CreateRenderTargetView(backBufferPtr, NULL, &m_renderTargetView);

// 이제 이용가치가 사라진 버퍼의 포인터를 메모리 해제한다.
backBufferPtr->Release();
backBufferPtr = nullptr;

 

다음은 DepthBuffer(깊이 버퍼), StencilBuffer(스텐실 버퍼) 가 작성된다.

DepthBuffer 는 3d 공간에서 각 픽셀의 깊이 값을 저장하는 버퍼이다.

게임에서 여러 건물이 겹쳐면 화면에서는 가려진 건물은 보이지 않고 가장 앞으로 나와있는 건물만 픽셀로 표현되는데, 이렇게 어떤게 가려지고 어떤걸 렌더링 해야 하는지의 방법에 주로 사용 된다.

https://learn.microsoft.com/en-us/windows/win32/direct3d9/depth-buffers

StencilBuffer 는 특정 조건을 충족하는 픽셀만 렌더링되도록 할때 사용되는 버퍼다.

같은 스텐실... 혹시 불어불어 불어펜을 아시나요..?

그럼 Depth, StencilBuffer(이하 D,S buffer) 를 만들고 DX에 등록해보자.

 

1. 버퍼는 결국 2D Texture이기에 사용할 2D Texture 생성.

// Initialize the description of the depth buffer.
ZeroMemory(&depthBufferDesc, sizeof(depthBufferDesc));

// 버퍼는 결국 2D 텍스쳐일 뿐이기에 버퍼로 사용할 2D 텍스쳐부터 만들것이다.
// Set up the description of the depth buffer.
depthBufferDesc.Width = screenWidth;
depthBufferDesc.Height = screenHeight;
depthBufferDesc.MipLevels = 1;
depthBufferDesc.ArraySize = 1;
// 32bit중 24bit는 Depth buffer로, 8bit는 Stencil buffer로 사용.
depthBufferDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
depthBufferDesc.SampleDesc.Count = 1;
depthBufferDesc.SampleDesc.Quality = 0;
depthBufferDesc.Usage = D3D11_USAGE_DEFAULT;
depthBufferDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
depthBufferDesc.CPUAccessFlags = 0;
depthBufferDesc.MiscFlags = 0;

// 하나의 2D Texture를 깊이, 스텐실 버퍼로 사용한다.
m_device->CreateTexture2D(&depthBufferDesc, NULL, &m_depthStencilBuffer);

위 코드에서 마지막 부분에 // 하나의 2D Texture를 D,S buffer로 사용한다 고 하는데,

중간에 depthBufferDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT의 뜻이 32bit중 24bit는 Depth buffer로, 8bit는 Stencil buffer로 사용한다는 뜻이기에 하나의 Texture에 두 개의 버퍼를 사용가능하게 해준다.

 

2. D,S buffer 의 동작 방법을 정의하는 D3D11_DEPTH_STENCIL_DESC 생성 후 등록

// Initialize the description of the stencil state.
ZeroMemory(&depthStencilDesc, sizeof(depthStencilDesc));

// Set up the description of the stencil state.
depthStencilDesc.DepthEnable = true;
depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
depthStencilDesc.DepthFunc = D3D11_COMPARISON_LESS;

depthStencilDesc.StencilEnable = true;
depthStencilDesc.StencilReadMask = 0xFF;
depthStencilDesc.StencilWriteMask = 0xFF;

// 픽셀이 전면을 향하고 있는 경우 스텐실 작업. 
depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;

// 픽셀이 후면을 향하고 있는 경우 스텐실 작업. 
depthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
depthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;

// depth stencil state 생성
m_device->CreateDepthStencilState(&depthStencilDesc, &m_depthStencilState);

// depth stencil state 등록
m_deviceContext->OMSetDepthStencilState(m_depthStencilState, 1);

 

3. 런타임중 D,S buffer 에 접근할 수 있는 ID3D11DepthStencilView 생성 후 등록

// depth stencil view 초기화
ZeroMemory(&depthStencilViewDesc, sizeof(depthStencilViewDesc));

// depth stencil view Desc 설정
depthStencilViewDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
depthStencilViewDesc.Texture2D.MipSlice = 0;

// depth stencil view 생성
result = m_device->CreateDepthStencilView(m_depthStencilBuffer, &depthStencilViewDesc, &m_depthStencilView);

// 렌더 타겟 뷰와 깊이 스텐실 버퍼를 출력 렌더 파이프라인에 바인딩합니다. 
m_deviceContext->OMSetRenderTargets(1, &m_renderTargetView, m_depthStencilView);

위 코드의 마지막 OMSetRenderTargets은 렌더 파이프 라인의 OM단계에 배치한다는 말인데 나중에 더 자세히 알게 된다.

여기까지 Render target view와 D, S buffer를 생성 후 렌더링 파이프 라인에 배치 하였다.

 


중간 마감

 

Initialize 내용이 너무너무너무너무너무너무 길어서;;; 진짜 다음 포스팅에서 마무리한다;;;;;;;

 


개념 정리

 

스왑체인 : 두 개 이상의 버퍼를 체인처럼 연결해 프레임마다 버퍼를 교체하며 사용하는 기술.

 

Direct3D device(ID3D11Device) : 그래픽 리소스의 생성, 관리를 맡는 DXGI의 주 인터페이스.

특히 생성했다 하면 대부분 이 인터페이스를 사용한다.

 

Direct3D device context(ID3D11DeviceContext) : 그래픽 리소스를 등록하고 렌더링 명령을 하는 DXGI의 주 인터페이스.

위의 D3Ddevice로 만든 리소스들을 파이프 라인에 등록한다거나 셰이더를 등록한다거나 이런 등록이 대부분 이 인터페이스를 사용한다.

 

Render target view : 프레임마다 렌더링 결과물이 그려질 버퍼를 가리키는 포인터를 가진 인터페이스

 

Depth buffer : 각 픽셀의 깊이 값을 저장하는 버퍼

 

Stencil buffer : 각 픽셀의 스텐실 값을 저장하는 버퍼

'DirectX 11 > DX11 Tutorial' 카테고리의 다른 글

[05] 텍스쳐링  (0) 2024.05.23
[04] 버퍼, 셰이더, HLSL  (0) 2024.05.21
[03] DirectX 11 초기화 (3)  (0) 2024.05.20
[01] DirectX 11 초기화 (1)  (0) 2024.05.19
[00] 프레임 워크와 창 생성  (0) 2024.05.17

+ Recent posts