11P by GN⁺ 11일전 | ★ favorite | 댓글 1개
  • 3개월 동안 Vulkan을 학습하며 두 개의 데모 게임을 포함한 소형 게임 엔진을 직접 구현한 경험 정리
  • 기존 OpenGL 경험을 바탕으로 Vulkan의 복잡성을 단계적으로 극복, glTF 로딩·스키닝·섀도 매핑 등 핵심 기능 구현
  • 엔진은 EDBR(Elias Daler’s Bikeshed Engine) 으로, 약 1.9만 줄의 코드로 구성되어 있으며 바인드리스 디스크립터·PVP·BDA 등 현대적 그래픽스 기법 활용
  • 글에서는 vk-bootstrap, VMA, volk 같은 필수 라이브러리와 파이프라인 패턴, 셰이더 빌드 자동화, 동기화 관리 등 실무적 구현 세부를 공유
  • Vulkan 전환을 통해 글로벌 상태 제거, 명시적 제어, 향상된 디버깅 환경, GPU 간 일관성을 얻었으며, 향후 렌더 그래프·SDF 폰트·볼류메트릭 효과 추가 계획

Vulkan 학습과 엔진 개발 개요

  • 저자는 그래픽스 프로그래밍을 독학으로 시작해 1년 반 전 OpenGL로 3D 엔진을 작성한 경험이 있음
  • Vulkan 기반 엔진은 소규모 레벨 기반 게임에 적합하며, 효율성보다는 학습과 실험 목적 중심
  • 초기에는 단순 3D 게임을 만들고, 재사용 가능한 부분을 분리해 엔진화하는 방식으로 진행
  • 3개월 만에 완성할 수 있었던 이유는 범용 엔진이 아닌 특정 목적 엔진으로 한정했기 때문

그래픽스 프로그래밍 학습 경로

  • 초보자는 OpenGL로 시작해 텍스처 모델 표시, Blinn-Phong 조명, 그림자 매핑 등을 익히는 것이 권장됨
  • 추천 자료로 learnopengl.com, Anton’s OpenGL 4 Tutorials, Thorsten Thormählen 강의 등이 제시됨
  • 최신 OpenGL 4.6 실습 자료와 함께 선형대수학(벡터, 행렬, 쿼터니언) 이해의 중요성 강조

Bike-shedding 방지 조언

  • 불필요한 과도한 설계와 추상화를 피하고, “지금 필요한 것만 구현” 원칙 유지
  • “일단 작동하게 만들고 나중에 개선” 접근 권장
  • 일반 목적 엔진보다는 작은 게임을 먼저 완성하는 것이 효율적
  • 다른 사람의 복잡한 코드나 구조를 그대로 모방하지 말고, 단순한 구조에서 출발

Vulkan 선택 이유

  • AAA 게임에는 DirectX, macOS/iOS에는 Metal, 웹에는 WebGPU/WebGL이 주로 사용됨
  • 저자는 오픈소스와 표준 기술 선호, 데스크톱용 소형 3D 게임 개발 목적에 맞춰 Vulkan 선택
  • OpenGL은 더 이상 발전이 없고 macOS에서 폐기됨
  • WebGPU는 간결하지만 안정성 부족, 기능 제약, 바인드리스·푸시 상수 미지원 등의 한계 존재

Vulkan 학습 과정

  • 초기에는 “그래픽 드라이버를 직접 작성하는 수준”으로 느껴질 만큼 어려웠으나,
    동적 렌더링, vk-bootstrap, vkguide 등의 등장으로 접근성이 향상됨
  • 주요 학습 자료:
    • vkguide.dev (기초부터 실습 중심)
    • TU Wien Vulkan Lecture Series
    • 3D Graphics Rendering Cookbook, Mastering Graphics Programming with Vulkan
  • 첫 달에 glTF 로딩, 컴퓨트 스키닝, 프러스텀 컬링, 섀도 매핑 구현 완료

EDBR 엔진 구조와 프레임 처리

  • 엔진 코드 약 19,000줄, 3D 게임 4,600줄, 2D 플랫폼 게임 1,200줄
  • 주요 렌더링 단계:
    • Compute 스키닝Cascaded Shadow Mapping(4096×4096)PBR 기반 지오메트리 셰이딩
    • Depth ResolvePost FX(깊이 기반 안개)UI 렌더링
  • 모든 그래픽스 시스템은 Vulkan 전용으로 재작성, 이전 OpenGL 코드와 혼합하지 않음

Vulkan 개발 실무 팁

추천 라이브러리

  • vk-bootstrap: 초기화 및 스왑체인 설정 단순화
  • Vulkan Memory Allocator(VMA) : 메모리 관리 자동화
  • volk: 확장 함수 로딩 단순화

GfxDevice 추상화

  • VkDevice, VkQueue, VmaAllocator 등을 하나의 객체로 관리
  • 프레임 시작/종료, 이미지·버퍼 생성, 바인드리스 디스크립터 관리 담당

셰이더 관리

  • GLSL 사용, 빌드 시점에 glslc로 SPIR-V 사전 컴파일
  • CMake DEPFILE을 이용해 셰이더 변경 시 자동 재빌드

파이프라인 패턴

  • 각 렌더링 단계를 클래스 단위 파이프라인으로 분리 (init, cleanup, draw)
  • VK_KHR_dynamic_rendering 사용으로 렌더패스·서브패스 생략, 단순화된 구조 유지

Programmable Vertex Pulling + Buffer Device Address

  • 하나의 Vertex 구조체로 모든 메시 처리
  • 셰이더에서 버퍼 참조(buffer_reference) 로 직접 접근, VAO 불필요

Bindless Descriptor

  • 전역 텍스처 배열(textures[], samplers[])을 사용해 텍스처 ID 기반 샘플링
  • 머티리얼 구조체에 텍스처 ID 저장, 푸시 상수로 전달

동적 데이터 업로드

  • 프레임별로 GPU 버퍼를 교체하거나 CPU 스테이징 버퍼를 이용해 데이터 전송
  • NBuffer 클래스로 프레임 인플라이트 구조 관리

리소스 정리와 동기화

  • 명시적 cleanup 함수 사용, 소멸자 자동 정리 대신 수동 관리
  • vkCmdPipelineBarrier2패스 간 메모리 동기화 수행
  • Render Graph는 향후 구현 예정

구현 세부 사례

스프라이트 렌더링

  • 바인드리스 텍스처인스턴싱으로 수천 개 스프라이트를 한 번에 렌더
  • SpriteDrawCommand 구조체를 GPU 버퍼로 업로드, vkCmdDraw(6, N) 호출
  • 1만 개 스프라이트를 315μs에 렌더링

Compute 스키닝

  • 컴퓨트 셰이더에서 본 행렬과 가중치 기반 버텍스 변형 수행
  • 각 인스턴스별로 출력 버퍼를 별도 생성, 이후 렌더링 단계에서 동일 처리

게임/렌더러 분리

  • 게임 로직은 entt ECS 사용, 렌더러는 DrawCommand 벡터만 처리
  • drawMesh, drawSkinnedMesh 호출로 렌더 명령 생성

씬 로딩과 프리팹

  • Blender에서 glTF로 레벨 구성, 노드 이름 규칙으로 프리팹 자동 스폰
  • 프리팹은 JSON으로 정의, 외부 glTF 참조

MSAA, UI, ImGui

  • Forward 렌더링 기반 MSAA x8 적용
  • Roblox UI API에서 영감받은 자동 레이아웃 시스템 구현
  • Dear ImGui sRGB 문제를 해결하기 위해 자체 Vulkan 백엔드 작성

기타 구성 요소

  • Jolt Physics로 물리 처리, entt ECS, OpenAL-soft 오디오, Tracy 프로파일러 사용

Vulkan 전환의 이점

  • 글로벌 상태 제거로 명시적·모듈형 코드 구조 확보
  • 검증 계층과 RenderDoc 디버깅으로 문제 추적 용이
  • GPU·OS 간 일관성 향상, OpenGL 대비 예측 가능한 동작
  • 새 셰이딩 언어(slang, shady) 등 확장 가능성 확보
  • 더 적은 추상화, 명확한 파이프라인 제어로 유지보수성 향상

향후 계획

  • SDF 폰트, 병렬 이미지 로딩 및 밉맵 생성, Bloom, 볼류메트릭 포그, 애니메이션 블렌딩, 렌더 그래프, AO 추가 예정
  • Vulkan 학습은 어렵지만, 현대 그래픽스 API 이해와 엔진 설계 역량 강화에 큰 도움이 되었음
Hacker News 의견
  • 1년 전 올린 내 글 이후로도 Vulkan에 대한 내 생각은 크게 바뀌지 않았음
    저수준 그래픽스 제어를 원하는 사람에게는 흥미롭겠지만, 나에게는 정말 사용하기 괴로운 API였음
    게임 엔진을 직접 만들어보고 싶다는 생각은 여전하지만, Vulkan의 초기 설정조차 여전히 두려움
    내가 원하는 건 SDL이 2D 그래픽을 다루는 방식의 3D 버전 같은 것임
    SDL에서 3D를 하려면 결국 OpenGL로 내려가야 하는데, 그건 내가 바라는 수준이 아님
    어쩌면 WebGPU가 내가 즐겁게 다룰 수 있는 대안일지도 모름

    • SDL 3.0이 1년쯤 전에 GPU API를 도입했음. Vulkan 등 여러 백엔드를 감싸는 추상화 레이어라서 확인해볼 만함
      나도 그걸로 엔진을 하나 만들었지만, 결국 더 많은 제어와 성능을 원해서 Vulkan 기반 엔진으로 돌아갔음
      그래도 SDL GPU 코드에서 동기화 패턴을 배워서 Vulkan 엔진에서 큰 도움이 되었음
    • Rust의 wgpu는 WebGPU 수준의 추상화를 제공하는 중간 지점
      OpenGL보다 강력하지만, 리소스 배리어나 레이아웃 전환 같은 세부 사항을 직접 다룰 필요가 없음
      런타임에서 일부 bookkeeping을 대신 해주고, 단일 큐만 지원하는 등의 제약이 있음
      Vulkan은 힘들지만, 주요 벤더들이 지원하는 확장 기능을 쓰면 꽤 개선됨
      다만 드라이버들이 무시하는 세부 설정을 요구하는 등, 여전히 불필요한 복잡성이 존재함
    • 오래된 OpenGL 프로그래머로서 완전히 공감함
      지금은 고수준 게임 엔진과 저수준 Vulkan/Metal 사이의 중간 API가 사라진 상태임
      초보자가 3D 그래픽을 배우려면 셰이더나 버퍼 같은 개념을 몰라도 되는, 단순한 “삼각형 그리기” 수준의 API가 필요함
      Vulkan의 세세한 제어는 극소수의 엔진 개발자에게만 필요하고, 대부분은 OpenGL 수준이면 충분함
    • “SDL 같은 3D”를 만들려는 시도는 금세 풀스택 엔진으로 커짐
      3D는 2D보다 조합 가능한 요소가 훨씬 많아서, 단순한 그래픽 API로는 감당이 어려움
      OpenGL도 원래 그걸 목표로 했지만, 결국 복잡해졌음
  • ‘bike shedding’은 사소한 문제에 집착하면서 중요한 부분을 놓치는 행위를 뜻함
    원문에서 묘사한 건 오히려 feature creep이나 over-engineering에 가까움

    • 저자라면 “hobby horsing”이라는 표현도 쓸 수 있었을 것임
      프로젝트 진전을 막고 개인적 즐거움에만 집중하는 행위를 뜻함
      bike shedding은 흔히 “집 완성 전 자전거 창고 색깔부터 정하는 것”으로 설명됨
    • “bike shedding”이라는 단어 자체를 두고 bike shedding하고 있는 셈임
  • “Minecraft 멀티플레이어 클론으로 엔진 개발을 시작하는 건 좋지 않다”는 말이 있었지만,
    사실 많은 사람들이 첫 엔진 프로젝트로 Minecraft류 게임을 만듦
    복셀 엔진에서는 그게 일종의 “Hello, world”임

  • (2024) 당시 게시물은 625포인트, 260댓글을 기록했음 — 원문 링크

  • Vulkan은 내가 배운 것 중 가장 어려운 기술이었음
    너무 비직관적이고 반복 작업이 많아서 프로그래밍의 즐거움을 앗아감

    • 네가 머리가 작은 게 아님. Vulkan은 저수준 칩 추상화 API라서 USB API만큼 재미없음
      더 간단하게 시작하려면 OpenGL(특히 셰이더 도입 전 버전)을 추천함
      하지만 업계는 OpenGL을 점점 밀어내는 중임
    • 나도 처음 Vulkan을 배울 때 완전히 같은 느낌이었음
      튜토리얼을 따라가며 코드를 베끼기만 했지 개념을 이해하지 못했음
      그래서 WebGPU(Google Dawn) 로 전환했는데, Vulkan보다 훨씬 단순했음
      WebGPU의 제약 덕분에 개념을 익히고 나서 다시 Vulkan을 배우니 훨씬 수월했음
      WebGPU는 push constant가 없고 pipeline 폭발 문제가 있지만, Vulkan은 동기화와 메모리 관리가 더 어려움
      SDL_GPU도 비슷한 수준의 API라 입문용으로 좋음
    • 내가 아직 OpenGL에서 Vulkan으로 넘어가지 않은 이유도 같음
      Vulkan은 과도하게 설계된 API
      CUDA에서는 한 줄로 가능한 GPU 메모리 할당이 Vulkan에서는 수많은 보일러플레이트를 요구함
      최신 Vulkan이 많이 개선됐지만 여전히 갈 길이 멂
    • 일반적인 Vulkan 코드 예시를 보면, 이건 게임 개발자용이 아님을 바로 알 수 있음
      SDL3나 wgpu가 이 복잡성을 덜어주는 추상화 계층이 되길 바람
      Valve가 SDL3를 지원하니 그쪽이 유력하다고 생각함
    • Vulkan/DX12 프로그래밍은 정말 고통스러움
      “그래픽을 멀티스레드로 처리해야 하는가?”라는 질문을 먼저 해야 함
      아니라면 Vulkan/DX12를 쓸 이유가 없음
      성능 문제가 생기기 전까지는 OpenGL, DX11, 혹은 게임 엔진을 쓰는 게 훨씬 나음
  • 나는 3D/게임 프로그래밍에 매료되어 있고, 몇몇 유튜버들이 게임을 만드는 과정을 자주 봄
    하지만 웹앱이나 DevOps에 비해 훨씬 복잡한 세계
    픽셀 셰이더, 계산 셰이더, 기하학, 선형대수, PDE까지 등장함
    TokyoSpliff 유튜브 채널

  • 요즘 취미로 게임 엔진을 만드는 게 멋진 일로 여겨지는 게 좋음
    나도 10년째 개인 엔진을 개발 중인데, 매우 보람찬 경험이었음

  • 그래픽 프로그래밍을 처음 한다면 OpenGL부터 시작하는 게 좋음
    23년 전 NeHe의 OpenGL 튜토리얼을 읽었는데, 지금도 가장 잘 구성된 학습 자료 중 하나라고 생각함

  • 참고로, 나는 원글 작성자가 아니며 제목만 유지했음