ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [DirectX] 1. DirectX 초기화 및 배경 색 칠하기
    Game Development/DirectX 2024. 6. 1. 18:01

    이번 글에서는 DirectX의 초기화와 화면의 배경을 칠해보도록 하겠습니다.

     

    먼저 DirectX를 사용하기 위한 설정부터 해보도록 하겠습니다.

    '프로젝트 속성 -> 구성 속성 -> 링커 -> 입력'으로 들어간 뒤,

    추가 종속성에 d3d11.lib; D3DCompiler.lib;를 작성합니다. 

     

    이제 설정이 끝났으니, DirextX 초기화, 메시지 루프, 창 초기화 등을 담당하는

    Engine.h와 Engine.cpp를 작성해 보도록 하겠습니다.

    // Engine.h
    
    #pragma once
    #include "Window.h"
    #include <d3d11.h>
    #include <d3dcompiler.h>
    #include <wrl.h>
    
    // COM 객체를 관리하는 스마트 포인터
    using Microsoft::WRL::ComPtr;
    
    class Engine {
    public:
    	Engine(HINSTANCE hInstance, int widht, int height, std::wstring title);
    
    	// 초기화 한 번에 실행
    	bool Init();
    	// 메시지 루프
    	int Run();
    
    private:
    	// 여러가지 처리를 담당
    	void Update();
    	// 화면에 렌더링하거나 리소스 바인딩
    	void Draw();
    
    	// 장면 초기화
    	bool InitScene();
    	// DirectX 초기화
    	bool InitDirect3D();
    
    	// Graphics Pipeline에서 사용될 리소스 생성하는데 사용한다.
    	ComPtr<ID3D11Device> device;
    	// 생성된 리소스를 바인딩하고, GPU가 수행할 렌더링 명령들을 지시하는데 사용된다.
    	ComPtr<ID3D11DeviceContext> deviceContext;
    	// DirectX에서 SwapChain을 사용하기 위해 사용한다.
    	ComPtr<IDXGISwapChain> swapChain;
    	// 렌더타겟에 접근할 때 사용한다.
    	ComPtr<ID3D11RenderTargetView> renderTargetView;
    	// 렌터타겟의 렌더링 영역에 관한 설정과 관련된 데이터를 담는다. 
    	D3D11_VIEWPORT viewport;
    
    	int vertexCount = 0;
    };
    // Engine.cpp
    
    #include "Engine.h"
    
    Engine::Engine(HINSTANCE hInstance, int width, int height, std::wstring title) {
    	// 저번에 작성했던 InitWindow()와 DirectX랑 씬을 초기화하는 Init() 호출
    	// 둘 중에 하나라도 실패하면 엔진 초기화 실패를 화면에 띄움
    	if (!Window::InitWindow(hInstance, width, height, title) || !Init()) {
    		MessageBox(nullptr, L"엔진 초기화 실패", L"오류", 0);
    		exit(-1);
    	}
    }
    
    bool Engine::Init() {
    	// DirectX 초기화
    	if (!InitDirect3D()) return false;
    	// 씬 초기화
    	if (!InitScene()) return false;
    	return true;
    }
    
    int Engine::Run() {
    	// 메시지 정보를 가지는 구조체이다.
    	MSG msg;
    	ZeroMemory(&msg, sizeof(msg));
    
    	// GetMessage()를 활용한 메시지 루프
    	// while(GetMessage(&msg, nullptr, 0, 0))
    	// {
    	//  	TranslateMessage(&msg);
    	//  	DispatchMessage(&msg);
    	// }
    
    	// PeekMessage()를 활용한 메시지 루프
    	// GetMessage()는 메시지가 없으면 대기시간을 가지는데, 
    	// 이런 대기시간이 길기 때문에 PeekMessage()를 쓰는 것이 더 좋다. 
    	while (msg.message != WM_QUIT) {
    	// 메시지 큐에 메시지가 존재하면 메시지를 가져오고 없으면 바로 0을 리턴한다.
    		if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
    			// 키 입력 메시지를 프로그램에서 쉽게 쓸 수 있는 문자 메시지로 변환한다.
    			TranslateMessage(&msg);
    			// 메시지 큐에서 꺼낸 메시지를 윈도우의 메시지 처리 함수로 전달한다.
    			DispatchMessage(&msg);
    		}
    		else {
    			// 업데이트 및 렌더링
    			Update();
    			Draw();
    		}
    	}
    
    	return 0;
    }
    
    void Engine::Update() {
    
    }
    
    void Engine::Draw() {
    	
    }
    
    bool Engine::InitScene() {
    	return true;
    }
    
    bool Engine::InitDirect3D() {
    	//  Swap Chain에 대한 설정 정보
    	DXGI_SWAP_CHAIN_DESC sc_desc;
    	ZeroMemory(&sc_desc, sizeof(sc_desc));
    	sc_desc.BufferCount = 1; // 백버퍼 개수
    	sc_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // 사용 목적
    	sc_desc.OutputWindow = Window::GetHWND(); // 출력할 윈도우 핸들
    	sc_desc.Windowed = true; // 창 모드 여부
    	sc_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; // Buffer Swap 효과
    	sc_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // 버퍼 디스플레이 형식
    	sc_desc.BufferDesc.Width = Window::Width(); // 버퍼 해상도 너비
    	sc_desc.BufferDesc.Height = Window::Height(); // 버퍼 해상도 높이
    	sc_desc.SampleDesc.Count = 1; // 픽셀당 추출할 표본의 갯수(멀티샘플링)
    	sc_desc.SampleDesc.Quality = 0; // 품질의 수준
    
    	// Device, DeviceContext, SwapChain 생성
    	HRESULT ret = D3D11CreateDeviceAndSwapChain(
    		nullptr, // 디스플레이 디바이스의 IDXGIAdapter 인터페이스
    		D3D_DRIVER_TYPE_HARDWARE, // 생성할 DX11 디바이스의 종류를 지정, D3D_DRIVER_TYPE_HARDWARE는 하드웨어 가속
    		nullptr, // 소프트웨어 래스터라이저가 구현되어있는 DLL이 핸들을 지정
    		0, // 사용할 DX11의 API 레이어를 D3D_CREATE_DEVICE_FLAG 값들을 조합하여 설정
    		nullptr, // 피처 레벨(지원 가능 레벨)을 설정. 우선순위가 높은 순서대로 배열을 채움
    		0, // 피처 레벨의 배열의 개수
    		D3D11_SDK_VERSION, // DirectX SDK 버전
    		&sc_desc, // DXGI_SWAP_CHAIN_DESC에 대한 주소
    		swapChain.GetAddressOf(), // IDXGISwapChain에 대한 주소
    		device.GetAddressOf(), // ID3D11Device 주소
    		NULL, // 피처 레벨 배열 값의 처음 값
    		deviceContext.GetAddressOf() // ID3D11DeviceContext 주소
    	);
    
    	if (FAILED(ret)) return false;
    
    	// 백버퍼 설정
    	// SwapChain을 생성한 뒤에 backbufferTexture를 통해서 백버퍼에 접근할 수 있도록 설정
    	ID3D11Texture2D* backbufferTexture;
    	ret = swapChain.Get()->GetBuffer(
    		// 접근할 버퍼의 번호
    		NULL,
    		// 백버퍼를 받을 인터페이스의 타입
    		__uuidof(ID3D11Texture2D),
    		// 반환된 백버퍼 인터페이스에 대한 포인터
    		(void**)(&backbufferTexture)
    	);
    
    	if (FAILED(ret)) return false;
    
    	// 렌더타겟 뷰 생성
    	ret = device.Get()->CreateRenderTargetView(
    		// 렌더타겟 뷰가 엑세스하는 리소스
    		backbufferTexture,
    		// D3D11_RENDER_TARGET_VIEW_DESC의 포인터
    		nullptr,
    		// ID3D11RenderTargetView의 포인터
    		renderTargetView.GetAddressOf()
    	);
    
    	if (FAILED(ret)) return false;
    
    	// 포인터 연결 해제
    	backbufferTexture->Release();
    
    	// 렌더타겟 뷰를 렌더타겟으로 설정
    	deviceContext.Get()->OMSetRenderTargets(
    		// 렌더타겟 수(최대 8개)
    		1,
    		// 렌더 타겟 뷰의 배열
    		renderTargetView.GetAddressOf(),
    		// 깊이/스텐실 뷰의 포인터
    		nullptr
    	);
    
    	// viewport 설정
    	viewport.TopLeftX = 0; // 좌상단 x좌표
    	viewport.TopLeftY = 0; // 좌상단 y좌표
    	viewport.Width = (float)Window::Width(); // 영역의 너비
    	viewport.Height = (float)Window::Height(); // 영역의 높이
    	viewport.MinDepth = 0.0f; // 최소 깊이
    	viewport.MaxDepth = 1.0f; // 최대 깊이
    
    	// 뷰포트를 바인딩한다.
    	deviceContext.Get()->RSSetViewports(1, &viewport);
    
    	return true;
    }

     

    이렇게 해서 DirectX를 초기화 해보았습니다.

    그 다음으로 배경 색을 칠하기 위해서 Engine.cpp의 Draw()의 내용을 채워주겠습니다.

    // Engine.cpp
    
    void Engine::Draw() {
    	// 색 배열
    	float backgroundColor[4] = { 0.1f, 0.5f, 0.1f, 1 };
    
    	// 렌더링 대상을 해당 색으로 전부 채움
    	deviceContext.Get()->ClearRenderTargetView(renderTargetView.Get(), backgroundColor);
    
    	// Swap Chain의 후면 버퍼를 렌더링
    	swapChain.Get()->Present(1, 0);
    }

     

    이제 이렇게 완성된 Engine 클래스를 한번 실행해보도록하겠습니다.

    // main.cpp
    
    #include "Engine.h"
    
    int WINAPI wWinMain(
    	HINSTANCE hInstance,
    	HINSTANCE hPrevInstance,
    	PWSTR pCmdLine,
    	int nCmdShow)
    {
    	Engine engine = Engine(hInstance, 1280, 8000, L"Show Potato");
    
    	engine.Run();
    
    	return 0;
    }

     

    이렇게 코드를 작성해주면 아래와 같이 나옵니다.

    결과 화면

     

    그럼 다음 글에서는 Vector 클래스를 만들기 위해서 벡터 연산들에 대해 알아보도록 하겠습니다.

    읽어주셔서 감사합니다.

    'Game Development > DirectX' 카테고리의 다른 글

    [DirectX] 3-2. World 행렬  (0) 2024.06.17
    [DirectX] 3-1. 행렬  (0) 2024.06.17
    [DirectX] 2-2. Vector3 및 Vector2 클래스 제작  (0) 2024.06.08
    [DirectX] 2-1. 벡터  (0) 2024.06.05
    [DirectX] 0. 창 띄우기  (0) 2024.05.31
Designed by Tistory.