[DX11] 기본 프레임워크와 장치 초기화

vector·2025년 10월 13일

인프런 Rookiss님의 [게임 프로그래머 도약반]DirectX11 입문 강의를 듣고 공부하기 위해 정리해둡니다.

기본 프레임워크

  • Visual Studio2022에서 Window 데스크톰 애플리케이션으로 프로젝트 생성
  • 기본적으로 사용할 헤더파일 추가하기
    • Types.h
    • Values.h
    • Struct.h
  • 미리 컴파일된 헤더(pch.h) 설정하기
    • 프로젝트 속성 - C/C++ - 미리 컴파일된 헤더
  • 프로젝트 설정하기
    • 프로젝트 속성 - 일반 - 출력 디렉토리
    • 프로젝트 속성 - C/C++ - 일반 - 추가 포함 디렉터리
    • 프로젝트 속성 - 링커 - 일반 - 추가 라이브러리 디렉터리
    • 미리 파일 생성해두기 (Binaries, Libraries)
  • pch.h 추가하기
    • 프로젝트에서 공통으로 사용되는 헤더

프로젝트 기본 세팅

Game.h

#pragma once


// DirectX11 렌더링을 관리하는 게임 엔진으 최소 단위 클래스
class Game
{
public:
	Game();
	~Game();

public:
	void Init(HWND hwnd);		// 초기화 : device, swapchain, RTV, viewport 초기화
	void Update();				// 매 프레임 갱신 로직 (입력, 게임상태 업데이트 등)	
	void Render();				// 매 프레임 렌더링

private:
	void RenderBegin();			// 렌더 타겟 바인딩, 클리어, 뷰포트 설정
	void RenderEnd();			// 화편 표시 (Present)


private:
	void CreateDeviceAndSwapChain();		// D3D11 Device, DeviceContext ,SwapChain 생성
	void CreateRenderTargertView();			// 백버퍼로부터 RTV 생성
	void SetViewport();						// 뷰포트 설정

private:
	HWND _hwnd;					// 윈도우 핸들
	uint32 _width = 0;			// 윈도우 창 크기
	uint32 _height = 0;			// 윈도우 창 크기

private:
	// Device & SwapChain
	ComPtr<ID3D11Device> _device = nullptr;					//	GPU 디바이스 (리로스 생성 추제)
	ComPtr<ID3D11DeviceContext> _deviceContext = nullptr;	// 	디바이스 컨텍스트 (렌더링 명령 전달)
	ComPtr<IDXGISwapChain> _swapChain = nullptr;			//	spawChain (화면에 보여질 버퍼 교체 관리)

	// RTV 
	ComPtr<ID3D11RenderTargetView> _renderTargetView;		//	후면 버퍼를 그릴 수 있게 하는 뷰

	// Misc
	D3D11_VIEWPORT _viewport = { 0 };
	float _clearColor[4] = { 0.f, 0.f, 0.f, 0.f };
};
Game.cpp
#include "pch.h"
#include "Game.h"

Game::Game()
{
}

Game::~Game()
{
}

void Game::Init(HWND hwnd)
{
	_hwnd = hwnd;
	_width = GWinSizeX;
	_height = GWinSizeY;

	// TODO
	CreateDeviceAndSwapChain();
	CreateRenderTargertView();
	SetViewport();
}

void Game::Update()
{
	// 매 프레임 게임 로직 업데이트

}

void Game::Render()
{
	RenderBegin();

	//TODO

	RenderEnd();
}

void Game::RenderBegin()
{
	// 1) 출력 병합 단계(OM)에 렌더 타깃을 묶는다. (DSV 없음)
	_deviceContext->OMSetRenderTargets(1, _renderTargetView.GetAddressOf(), nullptr);
	// 2) 현재 렌더 타깃을 지정한 색으로 초기화
	_deviceContext->ClearRenderTargetView(_renderTargetView.Get(), _clearColor);
	// 3) 레스터라이저 단계(RS)에 사용할 뷰포트 설정
	_deviceContext->RSSetViewports(1, &_viewport);
}

void Game::RenderEnd()
{
	// 더블 버퍼링 : 후면 버퍼에 그린 내용을 화면(전면)으로 표시
	// 첫번째 인자 1은 VSync를 1로 맞춰 화면 주사율에 동기화 (티어링 방지)
	// 0으로 하면 즉시 표시 (티어링 발생 가능)
	_swapChain->Present(1, 0);
}

void Game::CreateDeviceAndSwapChain()
{
	DXGI_SWAP_CHAIN_DESC desc;
	ZeroMemory(&desc, sizeof(desc)); // ::memset(&desc, 0, sizeof(desc));
	{
		// 출력 버퍼 크기를 윈도 크기에 맞춘다.
		desc.BufferDesc.Width = _width;
		desc.BufferDesc.Height = _height;
		desc.BufferDesc.RefreshRate.Numerator = 60; // 60Hz
		desc.BufferDesc.RefreshRate.Denominator = 1;
		desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // 32bit RGBA (정규화)
		desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
		desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
		desc.SampleDesc.Count = 1;					// 멀티샘플링 비활성화 (MSAA x)
		desc.SampleDesc.Quality = 0;
		desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // 렌더타겟으로 사용
		desc.BufferCount = 1;						// 후면 버퍼 개수 (레거시 Blt 모델 : 1이면 더블 버퍼링)
		desc.OutputWindow = _hwnd;					// 렌더링할 대상 윈도우
		desc.Windowed = TRUE;						// 창모드(True), 전체화면 (False)
		desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; // 스왑 후 버퍼 내용 폐기 (레거시 모델)
	}

	// comPtr 팁 : Get()은 원 포인터, GetAddressOf()는 포인터의 주소
	// 매개변수에서 *이면 Get(), **이면 GetAddressOf()
	_device.Get(); // ID3D11Device*를 꺼내오고 싶을때
	_device.GetAddressOf(); // ID3D11Device*의 주소를 꺼내오고 싶을때

	// device와 swapChain을 동시 생성(레거시 경로)
	HRESULT hr = ::D3D11CreateDeviceAndSwapChain(
		nullptr,						// 디폴트 어댑터
		D3D_DRIVER_TYPE_HARDWARE,		// 하드웨어 디바이스
		nullptr,						// 소프트웨어 래스터라이저(HAL 사용시 nullptr)
		0,								// 플래그(디버그 레이어는 디버그 빌드에서 D3D11_CREATE_DEVICE_DEBUG 권장)
		nullptr,						// 원하는 피처레벨 목록 (nullptr이면 내부 기본 목록)
		0,								// 피처레벨 개수
		D3D11_SDK_VERSION,				// SDK 버전
		&desc,							// 스왑체인 설명
		_swapChain.GetAddressOf(),		// [out] 스왑체인
		_device.GetAddressOf(),			// [out] 디바이스
		nullptr,						// [out] 선택된 피처레벨 (필요시 포인터 전달)
		_deviceContext.GetAddressOf()	// [out] 디바이스 컨텍스트
	);

	CHECK(hr); // 성공 여부 매크로


}

void Game::CreateRenderTargertView()
{
	HRESULT hr;

	// 후면 버퍼(텍스처) 임시 포인터
	ComPtr<ID3D11Texture2D> backBuffer = nullptr;

	// swapChain에서 후면 버퍼에 해당하는 리소스를 ID3D11Textrue2D로 가져오고
	hr = _swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)backBuffer.GetAddressOf());
	CHECK(hr);

	// 가져온 후면버퍼를 묘사하는 RenderTargetView로 만들어줬고
	_device->CreateRenderTargetView(backBuffer.Get(), nullptr, _renderTargetView.GetAddressOf());
	CHECK(hr);
}

void Game::SetViewport()
{
	_viewport.TopLeftX = 0.f;
	_viewport.TopLeftY = 0.f;
	_viewport.Width = static_cast<float>(_width);
	_viewport.Height = static_cast<float>(_height);
	_viewport.MinDepth = 0.f;
	_viewport.MaxDepth = 1.f;
}

profile
게임 클라이언트 프로그래머 준비중 (공부 및 기록용)

0개의 댓글