1P by GN⁺ | ★ favorite | 댓글 1개
  • OpenGL·Vulkan·Metal·DirectX의 내부 작동 원리를 이해하기 위해 외부 그래픽 라이브러리 없이 소프트웨어 렌더러를 처음부터 구현함
  • 삼각형 메시와 텍스처로 구성된 3D 모델을 이미지로 변환하며, GUI나 GPU 애플리케이션 구현은 다루지 않음
  • 완성 코드는 약 500줄이고, 학생들은 일반적으로 10~20시간을 들여 작동하는 렌더러를 만들기 시작함
  • RGB·RGBA·회색조를 지원하는 TGA 처리 클래스와 단일 픽셀 설정 기능만 주어지며, 선분과 삼각형 그리기는 직접 구현해야 함
  • 완성 코드를 복사하기보다 직접 작성해야 렌더링 개념을 이해하고, 3D 라이브러리의 내부 동작도 파악할 수 있음

렌더링 파이프라인을 직접 만드는 과정

  • 최신 3D 그래픽 라이브러리의 구조를 느슨하게 따라가며 렌더링 파이프라인의 작동 원리를 학습함
    • GPU 애플리케이션 작성법 대신 소프트웨어 렌더러로 내부 동작을 재현함
    • 입력은 삼각형 메시와 텍스처로 구성된 3D 모델이며, 출력은 렌더링된 이미지임
    • 그래픽 인터페이스 없이 프로그램이 이미지 파일을 생성함
  • 외부 의존성을 줄이기 위해 단순한 이미지 형식인 TGA를 사용함
    • 처음 제공되는 기능은 이미지 불러오기·저장하기와 픽셀 하나의 색상 설정뿐임
    • 선분이나 삼각형을 그리는 내장 함수가 없어 모두 직접 작성해야 함
  • 시작 예제는 64x64 RGB 프레임버퍼를 만들고 세 좌표의 픽셀을 흰색으로 설정한 뒤 framebuffer.tga로 저장함
    • 색상 값은 BGRA 순서로 지정함

코드 빌드와 실행

git clone https://github.com/ssloy/tinyrenderer.git &&
cd tinyrenderer &&
cmake -Bbuild &&
cmake --build build -j &&
build/tinyrenderer obj/diablo3_pose/diablo3_pose.obj obj/floor.obj
  • 실행 결과는 framebuffer.tga 에 저장됨
  • 완성 코드는 약 500줄이지만, 직접 구현하는 과정이 개념 이해에 필수이므로 제공 코드를 그대로 사용하는 방식은 권장하지 않음

댓글과 토론

Hacker News 의견들
  • 몇 달 전 Rust로 소프트웨어 렌더러를 LLM 없이 직접 구현하고, 간단한 게임과 픽셀화 셰이더·손전등 가장자리의 색수차 효과까지 추가했음
    https://github.com/kshitijl/tinyrenderer-rs
    저장소에는 개발 과정과 우스운 시각적 버그를 담은 스크린샷이 많음. 렌더링 원리뿐 아니라 현대 CPU가 매우 빠르며, 단일 스레드 CPU 렌더러로도 화려한 특수 효과가 있는 대화형 3D 게임을 실행할 수 있다는 점을 크게 배움
    • 소프트웨어 렌더러인데 왜 wgpu에 의존하는지 궁금함
    • Rust로 게임 로직을 작성할 때 ECS까지 추가해야 할 정도인지 궁금함
  • 이 자료와 John Vince의 Mathematics for Computer Graphics는 내 소프트웨어 렌더러를 만드는 데 필수적이었음
    LLM 이전이라 최소 두 달이 걸렸고, 대부분 컴퓨터 그래픽스 수학을 이해하고 C 세그멘테이션 오류를 추적하는 데 썼음
    • 몇 달 동안 하루에 몇 시간씩 작업했는지 궁금함
  • Foley와 Van Dam의 책이 여전히 이 분야의 대표 참고서인지 궁금함. 2013년에 개정됐지만 나는 2D 중심의 1982년판에 더 익숙하며, 당시에는 컴퓨터 그래픽스의 정석 같은 책이었음
    • 오랫동안 다시 펼쳐보지 않았으며, 내게는 역사적 가치가 있는 독특한 백과사전에 가까움
      이 GitHub의 강의 노트가 개념을 복습하기에는 더 좋았음. 저장소의 코드 스타일은 마음에 들지 않고 구식 래스터라이저도 지나치게 단순하고 비효율적이지만, 그래도 Foley의 책보다는 읽기 좋다고 봄
    • 나도 2판으로 배웠고 2013년 최신판도 갖고 있는데 무난한 편임
      판본이 바뀌며 사용 언어도 Pascal에서 C, C와 C++로 발전했고 최신판에는 C#도 조금 들어감. 새로운 개념이 여럿 빠졌지만 여전히 가치 있는 내용이 많다고 봄
  • 소프트웨어 렌더러 튜토리얼 하나쯤은 삼각형 클리핑을 제대로 다뤘으면 함. 실용적인 렌더러라면 기본 장면에서도 기하가 뷰 절두체와 교차할 때 반드시 처리해야 하지만, 개인적으로 가장 어려운 부분임
    • 이 주제를 한 장 전체에서 다룸: https://gabrielgambetta.com/computer-graphics-from-scratch/11-clipping.html
    • 아주 큰 삼각형의 속성 보간이 중요할 때만 삼각형 클리핑이 필요하며, 빠르게 폐기하거나 프리미티브를 합성하는 두 방법이 있음
      절두체 클리핑은 로컬 타일의 점 선택으로 처리할 수 있고, 프리미티브 합성은 역변환된 클리핑 사각형을 무게중심 좌표계에서 다루는 편이 쉬움. 배정밀도나 고정소수점으로 반올림 오차를 제어할 수 있으며, 핵심 난점은 새 정점의 Z와 1/Z 값을 재생성하는 것임. 지연 속성 합성 래스터라이저라면 나머지는 자연스럽게 파이프라인을 통과하며, OpenSWR.org의 오픈소스 구현에서 예제를 볼 수 있음
    • 나도 늘 “클리핑을 구현해야 한다”는 단계에서 막혔지만, 결국 큰 어려움 없이 작동하는 코드를 만들고 나중에야 그것이 Sutherland–Hodgman 알고리즘을 독립적으로 재발견한 것임을 알게 됨
      가장 큰 심리적 장벽은 사영 공간과 동차좌표의 낯섦임. 클립 공간의 여섯 평면은 x = ±w, y = ±w, z = ±w로 단순하며, 각 다각형 변을 순회하면서 양 끝점의 안팎을 판정하고 경계 교차점의 위치와 정점 속성을 선형 보간하면 됨. 이 과정을 모든 평면에 차례로 적용하면 삼각형은 최대 9개 정점의 볼록 다각형이 되고 쉽게 다시 삼각분할할 수 있음. 아웃코드(outcode) 를 미리 계산하면 완전히 내부나 외부에 있는 삼각형의 클리핑을 건너뛸 수 있음
      논문: https://dl.acm.org/doi/10.1145/360767.360802
  • 현대 환경에는 사실상 순수 C++ 이라는 것이 없음. 1980년대 컴퓨터처럼 레지스터와 VRAM에 직접 써서 영상을 출력할 수 없고, 결국 두꺼운 API·드라이버·펌웨어 계층 위에서 수많은 코드에 의존하게 됨
  • 1990년대 향수로 소프트웨어 렌더링을 다시 시도 중이며, 2D식 CLUT 뱅크와 현대적인 구간 분류 삼각형·무게중심 좌표 기법을 혼합하고 있음
    고정 파이프라인 형태를 유지하면 꽤 단순한 그리기 함수로도 놀랄 만큼 많은 삼각형을 처리할 수 있음
  • macOS의 OpenMP 처리 버그를 발견해 아주 오랜만에 이 저장소에 첫 PR을 제출했음