1 điểm bởi GN⁺ 2026-02-09 | 1 bình luận | Chia sẻ qua WhatsApp
  • Đây là một dự án triển khai đổ bóng 3D thời gian thực trên Game Boy Color, trong đó người chơi có thể điều khiển quỹ đạo ánh sáng và xoay vật thể
  • Dựa trên phép tính vector chuẩn hóa và đổ bóng Lambert (dot product), dự án đơn giản hóa phép toán bằng cách sử dụng hệ tọa độ cầu
  • Để vượt qua giới hạn của CPU SM83 không có lệnh nhân, dự án tận dụng biến đổi log và bảng tra cứu để thực hiện phép toán với độ chính xác 8 bit
  • Sử dụng mã tự sửa đổi (self-modifying code) để đạt mức tăng hiệu năng khoảng 10%, và render 15 tile mỗi khung hình
  • Việc dùng AI để sinh mã hầu hết đều thất bại, và thuật toán cốt lõi cùng shader được hoàn thiện bằng mã viết tay trực tiếp

Tổng quan dự án

  • Tạo ra một trò chơi render hình ảnh theo thời gian thực trên Game Boy Color
    • Người chơi điều khiển ánh sáng theo quỹ đạo để xoay vật thể
  • Toàn bộ mã nguồn được công khai trên kho GitHub(nukep/gbshader)

Quy trình tạo nội dung 3D

  • Sử dụng Blender để phát triển lookdev ban đầu; sau khi kết quả đạt yêu cầu về mặt thị giác thì tiếp tục dự án
  • Dùng Cryptomatte và shader tùy chỉnh để tạo normal map
    • Với mô hình ấm trà (teapot), xoay camera và xuất normal map dưới dạng chuỗi PNG
    • Phần màn hình của mô hình Game Boy Color được render ở một cảnh riêng rồi compositing lại

Nền tảng toán học

  • Normal map được dùng như một trường vector mã hóa vector pháp tuyến của từng pixel
  • Đổ bóng Lambert được tính bằng tích vô hướng dạng v = N·L
  • Chuyển sang hệ tọa độ cầu để đơn giản hóa thành v = sinNθ sinLθ cos(Nφ−Lφ) + cosNθ cosLθ
    • Giả sử bán kính của mọi vector đều là r=1 để giảm lượng tính toán

Triển khai trên Game Boy

  • Cố định Lθ (góc dọc của ánh sáng) như một hằng số, còn Lφ (góc quay của ánh sáng) do người chơi điều khiển
  • Trong ROM, mỗi pixel được lưu dưới dạng (Nφ, log(m), b)
  • Để giải quyết việc không có lệnh nhân, dự án dùng biến đổi log và bảng tra cứu (log, pow)
    • Bit dấu (sign) được lưu ở bit cao để hỗ trợ phép toán số âm
  • Mọi giá trị vô hướng được biểu diễn dưới dạng phân số 8 bit trong khoảng -1.0~+1.0
    • Phép cộng được thực hiện trong không gian tuyến tính, còn phép nhân trong không gian log
    • Dùng 127 làm mẫu số để biểu diễn được cả ±1

cos_log và phép toán cốt lõi

  • cos_log là bảng tra cứu kết hợp dạng log(cos x), thay thế phép nhân bằng phép cộng trong không gian log
  • Khối lượng tính toán cho mỗi pixel
    • 1 phép trừ, 1 lần tra cos_log, 1 phép cộng, 1 lần tra pow, 1 phép cộng
    • Tổng cộng 3 phép cộng/trừ và 2 lần tra cứu

Hiệu năng

  • Xử lý 15 tile mỗi khung hình, một số hàng trống được tính nhanh hơn
  • Khoảng 130 chu kỳ cho mỗi pixel, còn hàng trống chỉ mất 3 chu kỳ
  • Khoảng 89% CPU được dùng cho phép toán shader, phần còn lại dành cho xử lý input và I/O

Mã tự sửa đổi (Self-Modifying Code)

  • Để tối ưu vòng lặp lõi xử lý khoảng 960 pixel mỗi khung hình, dự án sửa trực tiếp chính lệnh máy
    • Chèn hằng số trực tiếp vào mã để tính toán nhanh hơn so với tải biến
    • Ví dụ: sub a, 8 nhanh hơn sub a, variable 12 chu kỳ
    • Tổng thể tiết kiệm khoảng 11.520 chu kỳ (10%)

Thử nghiệm sử dụng AI

  • 95% toàn bộ dự án được viết thủ công
  • AI gặp khó khăn khi viết assembly Game Boy (SM83)
  • Các phần đã dùng AI
    • Python: đọc layer OpenEXR
    • Blender: script tự động hóa cảnh
    • SM83: một số snippet chức năng (ví dụ: VRAM DMA)
  • Các thử nghiệm thất bại
    • Thử để AI sinh mã assembly shader → kém hiệu quả và nhiều lỗi
  • Thử dùng mô hình Claude Sonnet 4 để sinh assembly từ pseudocode
    • Có một phần hoạt động nhưng chậm, và xuất hiện lỗi như nhầm lẫn giữa Z80 và SM83
    • Mã cuối cùng đã được viết lại hoàn toàn bằng tay

Kết luận và bài học

  • AI hữu ích cho các script đơn giản, nhưng độ chính xác và khâu kiểm chứng là bắt buộc
  • Trong mã xử lý OpenEXR, AI gây ra lỗi sắp xếp kênh (BGR vs RGB) khiến bug kéo dài nhiều tuần
  • Qua trải nghiệm này, tác giả nhấn mạnh bài học rằng “điều quan trọng nhất khi dùng AI là kiểm chứng”
  • Dự án được đánh giá là một ví dụ thử nghiệm về triển khai shader vượt qua giới hạn của phần cứng legacy

1 bình luận

 
GN⁺ 2026-02-09
Ý kiến trên Hacker News
  • Thật vui khi được thấy một bài viết đúng chất tinh thần hacker trên HN

    • Ban đầu tôi còn tự hỏi liệu có phải chỉ là thứ được làm bằng prompt AI hay không. Tôi muốn biết họ đã triển khai nó như thế nào 😉
  • Thành phẩm thật sự rất ấn tượng. Theo cách tôi hiểu thì đây là kiểu “trông giống 3D nhưng thực ra là một shader áp hiệu ứng ánh sáng lên normal map 2D đã được render sẵn”
    Các frame nằm ở liên kết GitHub này

    • Thực chất nó cũng không khác mấy so với một bộ render “3D thật”. Trong deferred rendering pipeline, shader cũng hoạt động trên các buffer 2D như depth map, normal map và color buffer.
      Phần xử lý tam giác 3D được giữ đơn giản, còn shader ánh sáng tốn kém chỉ cần chạy một lần trên ảnh 2D nên rất hiệu quả
      Xét từ góc độ shader, nếu đầu vào là vector 3D thì đó là shader 3D. Việc có rasterizer 3D hay không lại là chuyện khác
      Các game 3D hiện đại cũng dùng kiểu này theo nhiều cách khác nhau. Kỹ thuật imposter dùng model render sẵn từ nhiều góc nhìn cũng là công nghệ được sử dụng trong các engine 3D chính thống
    • Nó khá giống cách các game Mac ngày xưa thêm ánh sáng lên texture 2D khi chưa có phần cứng tăng tốc 3D.
      Nhưng điều đáng kinh ngạc ở đây là lần này nó chạy được trên Game Boy Color
  • Xin chào, tôi là tác giả. Tôi nghe nói bài này được đăng ở đây nên đã tạo tài khoản. Cảm ơn vì đã chia sẻ
    Tôi cũng đang thử nghiệm để đơn giản hóa hơn nữa bằng environment map, có thể xem tại liên kết tôi chia sẻ trên Bsky

  • Dự án này thật sự rất thú vị. Nó làm tôi nhớ lại thời mình từng code assembly cho C64.
    Hồi đó cũng không có lệnh nhân, nên phải tìm những cách sáng tạo để lách qua các giới hạn phần cứng

  • Đây từng là một nỗ lực thử dùng AI, nhưng rốt cuộc lại là một thử nghiệm thất bại.
    Cả ngành đang ồn ào chuyện AI nên tôi muốn tự mình trải nghiệm, và tôi nghĩ việc công khai minh bạch chuyện có dùng generative AI hay không là rất quan trọng.
    Nếu giấu đi thì sẽ làm tổn hại niềm tin, còn nếu công khai thì có thể trò chuyện cởi mở với cả những người có quan điểm khác

    • Ban đầu giọng văn của tôi khá trung tính, nhưng vì mọi người hiểu lầm rằng tôi đang ca ngợi AI nên tôi đã chỉnh lại theo hướng hơi hoài nghi.
      Tôi chỉ đơn giản muốn ghi lại quá trình này thôi
  • Shader GBC này cho thấy một chân lý rằng “mọi phép tính đều là xấp xỉ trong khuôn khổ ràng buộc”.
    Phép nhân được thay bằng tra bảng và cộng, còn độ chính xác thì được điều chỉnh theo kết quả nhìn thấy bằng mắt

  • Thật sự đáng khâm phục. Đặc biệt, điều gây kinh ngạc là nó chạy trên phần cứng Game Boy Color thật.
    Nhiều khi người ta nhét một bộ xử lý mạnh vào cartridge rồi dùng GBC như một thiết bị đầu cuối đơn thuần, nhưng đây không phải kiểu hack đó

  • Thành thật mà nói, tôi ước Nintendo sẽ phát hành lại GBC hoặc GBA.
    Nếu họ bán dưới dạng cartridge có sẵn vài game tích hợp thì tôi sẵn sàng mua ngay.

    • Hàng second-hand cũng khá rẻ. Chỉ cần thêm một flash cartridge là xong.
      Tuy vậy, hiện nay các máy chơi game cầm tay Android cùng form factor lại thực dụng hơn.
      Tôi cũng có một bộ sưu tập Game Boy, nhưng dạo này emulator tiện hơn nhiều
    • Chỉ cần mua ModRetro Chromatic do nhà sáng lập Oculus VR làm ra là được.
      Kể cả Nintendo có làm mới thì tôi cũng không nghĩ sẽ tốt được đến mức đó
  • Chính những bài như thế này mới là lý do HN tồn tại.
    Nó gợi lại niềm vui ngày xưa khi lật giở các tạp chí công nghệ

  • Tác giả này đúng là một thiên tài điên rồ, theo nghĩa tích cực