← 개념 · 데모 가이드 | 구현 가이드 (C++ / DirectX 11)
IMPLEMENTATION GUIDE

C++ / DirectX 11로 직접 만들기

개념 가이드에서 "무엇이 어떻게 동작하는가"를 봤다면, 여기서는 "그것을 실제로 어떻게 코딩하는가"를 다룹니다. 모든 코드는 복사해 바로 컴파일할 수 있는 수준의 Direct3D 11 예제이며, 셰이더는 HLSL(Shader Model 5.0)로 작성합니다.

이 가이드가 가정하는 것

왜 DirectX 11인가 D3D11은 OpenGL 3.3과 추상화 수준이 비슷해(상태 기반, 드라이버가 동기화 담당) 개념을 그대로 옮기기 좋습니다. D3D12/Vulkan의 명시적 GPU 제어(커맨드 리스트·PSO·수동 동기화)는 코드량이 3~4배라 학습 단계에서는 D3D11이 최적입니다. 5장에서 D3D12·Vulkan으로의 이식 개념을 다룹니다.

개발 환경 (한 번만 세팅)

D3D11은 Windows SDK에 기본 포함이라 별도 설치가 없습니다. 링크할 라이브러리만 지정하면 됩니다.

구성요소역할비고
Win32 API창 생성 · 입력 · 메시지 루프OS 기본 (GLFW 대체)
d3d11.lib디바이스 · 컨텍스트 · 리소스Windows SDK 포함
dxgi.lib스왑체인 · 어댑터 열거Windows SDK 포함
d3dcompiler.lib런타임 HLSL 컴파일Windows SDK 포함
DirectXMath벡터/행렬 수학 (헤더 온리)<DirectXMath.h>, GLM 대체
stb_image이미지 로딩 (헤더 온리)또는 WIC

프로젝트 설정 (Visual Studio 또는 CMake)

Visual Studio에서 빈 C++ 프로젝트를 만들고 링커 입력에 아래 라이브러리를 추가하거나, CMake라면 다음과 같습니다.

CMakeLists.txtcmake
cmake_minimum_required(VERSION 3.16)
project(gfx_impl)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_executable(app WIN32 src/main.cpp)   # WIN32: 콘솔 없는 GUI 앱

# Windows SDK에 이미 포함된 라이브러리를 링크만 한다
target_link_libraries(app PRIVATE d3d11 dxgi d3dcompiler)

소스 파일 상단에서 #pragma comment로 링크해도 됩니다(Visual Studio 전용, CMake 불필요):

링크 지시cpp
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "dxgi.lib")
#pragma comment(lib, "d3dcompiler.lib")
TIP COM 객체는 수동 Release() 대신 Microsoft::WRL::ComPtr(<wrl/client.h>)를 쓰면 스마트 포인터처럼 자동 해제됩니다. 이 가이드의 예제도 ComPtr을 기본으로 씁니다.

최소 실행 코드: 창 띄우고 지우기

모든 예제의 출발점입니다. Win32로 창을 만들고, 디바이스·스왑체인을 생성한 뒤, 렌더 루프를 돕니다.

src/main.cppcpp
#include <windows.h>
#include <d3d11.h>
#include <dxgi.h>
#include <wrl/client.h>
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "dxgi.lib")

using Microsoft::WRL::ComPtr;

ComPtr<ID3D11Device>         g_device;
ComPtr<ID3D11DeviceContext>  g_context;
ComPtr<IDXGISwapChain>       g_swapChain;
ComPtr<ID3D11RenderTargetView> g_rtv;

// 윈도우 메시지 처리
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
    if (msg == WM_DESTROY) { PostQuitMessage(0); return 0; }
    return DefWindowProc(hwnd, msg, wp, lp);
}

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, int) {
    // 1) 윈도우 클래스 등록 + 창 생성
    WNDCLASS wc = {};
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInst;
    wc.lpszClassName = L"D3D11Window";
    RegisterClass(&wc);
    HWND hwnd = CreateWindow(wc.lpszClassName, L"DirectX 11",
        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 1280, 720,
        nullptr, nullptr, hInst, nullptr);
    ShowWindow(hwnd, SW_SHOW);

    // 2) 디바이스 + 스왑체인 생성 (한 번에)
    DXGI_SWAP_CHAIN_DESC scd = {};
    scd.BufferCount = 2;
    scd.BufferDesc.Width = 1280;
    scd.BufferDesc.Height = 720;
    scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    scd.OutputWindow = hwnd;
    scd.SampleDesc.Count = 1;              // MSAA 없음
    scd.Windowed = TRUE;
    scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;

    D3D11CreateDeviceAndSwapChain(
        nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0,
        nullptr, 0, D3D11_SDK_VERSION,
        &scd, &g_swapChain, &g_device, nullptr, &g_context);

    // 3) 백버퍼를 렌더 타깃 뷰로 감싼다 (OpenGL의 기본 프레임버퍼에 해당)
    ComPtr<ID3D11Texture2D> backBuffer;
    g_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer));
    g_device->CreateRenderTargetView(backBuffer.Get(), nullptr, &g_rtv);

    // 4) 뷰포트 설정 (glViewport 대응)
    D3D11_VIEWPORT vp = { 0, 0, 1280, 720, 0.0f, 1.0f };
    g_context->RSSetViewports(1, &vp);

    // 5) 렌더 루프
    MSG msg = {};
    while (msg.message != WM_QUIT) {
        if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
            continue;
        }
        // 화면 지우기 (glClearColor + glClear 대응)
        float clear[4] = { 0.06f, 0.07f, 0.10f, 1.0f };
        g_context->OMSetRenderTargets(1, g_rtv.GetAddressOf(), nullptr);
        g_context->ClearRenderTargetView(g_rtv.Get(), clear);

        // ── 여기서 그린다 ──

        g_swapChain->Present(1, 0);   // V-Sync ON (glfwSwapBuffers 대응)
    }
    return 0;
}
함정 OMSetRenderTargets는 매 프레임 또는 렌더 타깃이 바뀔 때마다 다시 호출해야 합니다. 또한 창 크기가 바뀌면 g_rtv를 해제하고 swapChain->ResizeBuffers() 후 RTV를 다시 만들어야 합니다. OpenGL과 달리 백버퍼 크기가 자동으로 따라오지 않습니다.
좌표계 주의 D3D는 OpenGL과 몇 가지가 다릅니다: 깊이 범위 [0,1](GL은 [-1,1]), 텍스처 V축이 위→아래(GL은 아래→위), 기본 왼손 좌표계. DirectXMath의 ...LH 계열 함수(XMMatrixPerspectiveFovLH 등)를 쓰면 자연스럽게 맞습니다. 각 챕터에서 해당 지점마다 짚습니다.

구현 챕터

개념 가이드와 같은 순서입니다. 각 챕터는 독립적으로 읽을 수 있지만, 1~3장이 나머지의 토대입니다.

CHAPTER 1

기초 수학

벡터·행렬·변환을 C++로 한 줄 한 줄 직접 구현하고 DirectXMath로 넘어가기. 6개 세부 페이지로 분해.

벡터 · 행렬 · 변환 · 내적/외적 · 삼각함수 · 기하 교차
CHAPTER 2

2D 그래픽스

프레임버퍼에 직접 픽셀을 찍어 선·삼각형을 래스터화하기.

픽셀/색 · 래스터화 · 이미지 필터 · 알파 블렌딩 · 스프라이트
CHAPTER 3

3D 그래픽스

버텍스 버퍼·입력 레이아웃부터 MVP·카메라·Z버퍼·퐁 조명·텍스처까지 실제 D3D11로.

MVP · 카메라 · 메시 · 깊이버퍼 · 조명 · 텍스처
CHAPTER 4

GPU · 셰이더

HLSL 컴파일, 버텍스/픽셀/컴퓨트 셰이더와 상수 버퍼 작성.

셰이더 컴파일 · Vertex · Pixel · Compute · HLSL · cbuffer
CHAPTER 5

그래픽스 API

D3D11 디바이스·상태 관리·렌더 루프의 실전, 그리고 타 API로의 개념 이식.

디바이스/컨텍스트 · 상태관리 · 디버깅 · D3D12/Vulkan/Metal/WebGPU 매핑
CHAPTER 6

고급 렌더링

PBR·HDR·섀도우맵·디퍼드·SSAO, 그리고 CPU 레이/패스 트레이서.

PBR · HDR · Shadow Map · Deferred · Screen-Space · Ray/Path Tracing · GI
CHAPTER 7

실전 렌더링 기법

안티앨리어싱·감마·밉맵·투명·AO·LOD/컬링의 실전 구현.

안티앨리어싱 · 감마 · 밉맵 · 투명 · AO · LOD/컬링
CHAPTER 8 · 사례연구

잔디 렌더링

앞 장의 기법들이 실제로 합쳐지는 캡스톤. 대량 잔디 10가지 렌더링 기법을 D3D11/HLSL로.

인스턴싱 · 빌보드 · 셸 · 레이마칭 · 밟힘 · 베지어 · 툰 · 바람 · LOD