게임보이 컬러에 실시간 3D 셰이더를 구현하다

3 hours ago 3

  • 게임보이 컬러에서 실시간 3D 셰이딩을 구현한 프로젝트로, 플레이어가 빛의 궤도를 조작하며 물체를 회전시킬 수 있음
  • 정규화 벡터와 램버트 셰이딩(dot product) 계산을 기반으로, 구면좌표계를 이용해 연산을 단순화함
  • 곱셈 명령이 없는 SM83 CPU의 제약을 극복하기 위해 로그 변환과 룩업 테이블을 활용, 8비트 정밀도로 연산 수행
  • 자기 수정 코드(self-modifying code) 를 사용해 약 10%의 성능 향상을 달성하고, 프레임당 15개의 타일을 렌더링함
  • AI를 활용한 코드 생성은 대부분 실패했으며, 핵심 알고리듬과 셰이더는 직접 작성한 수작업 코드로 완성됨

프로젝트 개요

  • 게임보이 컬러에서 실시간으로 이미지를 렌더링하는 게임을 제작
    • 플레이어는 궤도 형태의 빛을 조작하며 물체를 회전시킴
  • 전체 코드는 GitHub 저장소(nukep/gbshader)에서 공개됨

3D 제작 과정

  • Blender를 사용해 초기 룩 개발(lookdev)을 진행, 결과가 시각적으로 만족스러워 프로젝트를 진행함
  • Cryptomatte와 커스텀 셰이더를 이용해 노멀맵(normal map) 을 생성
    • 찻주전자(teapot) 모델은 카메라를 회전시켜 PNG 시퀀스로 노멀맵을 출력
    • 게임보이 컬러 모델의 화면 부분은 별도 장면으로 렌더링 후 합성

수학적 기반

  • 노멀맵은 각 픽셀의 법선 벡터를 인코딩하는 벡터 필드로 사용
  • 램버트 셰이딩은 v = N·L 형태의 내적(dot product)으로 계산
  • 구면좌표계로 변환해 v = sinNθ sinLθ cos(Nφ−Lφ) + cosNθ cosLθ 형태로 단순화
    • 모든 벡터의 반지름 r=1로 가정해 연산량을 줄임

게임보이에서의 구현

  • Lθ(빛의 세로각) 을 상수로 고정하고, Lφ(빛의 회전각) 만 플레이어가 조작
  • ROM에는 각 픽셀을 (Nφ, log(m), b) 형태로 저장
  • 곱셈 명령 부재를 해결하기 위해 로그 변환과 룩업 테이블(log, pow)을 사용
    • 부호(sign) 비트를 상위 비트에 저장해 음수 연산 지원
  • 모든 스칼라 값은 -1.0~+1.0 범위의 8비트 분수로 표현
    • 덧셈은 선형 공간에서, 곱셈은 로그 공간에서 수행
    • 127을 분모로 사용해 ±1을 모두 표현 가능하게 함

cos_log와 핵심 연산

  • cos_log는 log(cos x) 형태의 결합 룩업으로, 곱셈을 로그 덧셈으로 대체
  • 픽셀당 연산량
    • 뺄셈 1회, cos_log 조회 1회, 덧셈 1회, pow 조회 1회, 덧셈 1회
    • 총 3회 덧셈/뺄셈, 2회 룩업 수행

성능

  • 프레임당 15개의 타일을 처리, 일부 빈 행은 더 빠르게 계산
  • 픽셀당 약 130 사이클, 빈 행은 3 사이클 소요
  • CPU의 약 89% 가 셰이더 연산에 사용되며, 나머지는 입력 및 I/O 처리에 사용

자기 수정 코드(Self-Modifying Code)

  • 프레임당 약 960픽셀을 처리하는 핵심 루프를 최적화하기 위해 명령어 자체를 수정
    • 상수를 직접 코드에 삽입해 변수 로드보다 빠른 연산 수행
    • 예: sub a, 8이 sub a, variable보다 12사이클 빠름
    • 전체적으로 약 11,520 사이클(10%) 절감

AI 활용 시도

  • 전체 프로젝트의 95%는 수작업으로 작성
  • AI는 Game Boy 어셈블리(SM83) 작성에 어려움을 겪음
  • AI 사용 내역
    • Python: OpenEXR 레이어 읽기
    • Blender: 장면 자동화 스크립트
    • SM83: 일부 기능 스니펫 (예: VRAM DMA)
  • 실패한 시도
    • AI로 셰이더 어셈블리 코드 생성 시도 → 비효율적이고 오류 다수
  • Claude Sonnet 4 모델을 이용해 의사코드에서 어셈블리 생성 시도
    • 일부 작동했으나 느리고, Z80과 SM83 혼동 등의 오류 발생
    • 최종 코드는 수동으로 완전 재작성

결론 및 교훈

  • AI는 단순 스크립트에는 유용하지만, 정확성과 검증이 필수
  • OpenEXR 처리 코드에서 AI가 채널 정렬 오류(BGR vs RGB) 를 일으켜 수주간 버그 발생
  • 경험을 통해 “AI 사용 시 검증이 가장 중요하다”는 교훈을 강조
  • 프로젝트는 레거시 하드웨어의 한계를 극복한 실험적 셰이더 구현 사례로 평가됨

Read Entire Article