-
[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