1 คะแนน โดย GN⁺ 2026-02-09 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • โปรเจ็กต์ที่ทำ การแรเงา 3D แบบเรียลไทม์ บน Game Boy Color โดยผู้เล่นสามารถควบคุมวงโคจรของแสงและหมุนวัตถุได้
  • อิงจากการคำนวณ เวกเตอร์นอร์มัลไลซ์และการแรเงาแบบ Lambert (dot product) โดยใช้พิกัดทรงกลมเพื่อลดความซับซ้อนของการคำนวณ
  • เพื่อเอาชนะข้อจำกัดของ CPU SM83 ที่ไม่มีคำสั่งคูณ จึงใช้การแปลงลอการิทึมและตารางค้นหา ทำการคำนวณด้วยความแม่นยำ 8 บิต
  • ใช้ self-modifying code เพื่อเพิ่มประสิทธิภาพได้ราว 10% และเรนเดอร์ได้ 15 ไทล์ต่อเฟรม
  • การใช้ AI เพื่อสร้างโค้ดส่วนใหญ่ล้มเหลว และอัลกอริทึมหลักกับเชดเดอร์ถูกทำเสร็จด้วย โค้ดที่เขียนด้วยมือ

ภาพรวมของโปรเจ็กต์

  • สร้าง เกมที่เรนเดอร์ภาพแบบเรียลไทม์ บน Game Boy Color
    • ผู้เล่นควบคุมแสงในลักษณะวงโคจรและหมุนวัตถุ
  • โค้ดทั้งหมดเผยแพร่ไว้ใน GitHub repository (nukep/gbshader)

กระบวนการสร้าง 3D

  • ใช้ Blender ทำ lookdev เบื้องต้น และเมื่อผลลัพธ์น่าพอใจในเชิงภาพจึงเดินหน้าโปรเจ็กต์ต่อ
  • ใช้ Cryptomatte และเชดเดอร์แบบกำหนดเองเพื่อสร้าง normal map
    • โมเดลกาน้ำชา (teapot) ส่งออก normal map เป็นลำดับภาพ PNG โดยหมุนกล้อง
    • ส่วนหน้าจอของโมเดล Game Boy Color เรนเดอร์ในซีนแยกแล้วจึงนำมาคอมโพสิต

พื้นฐานทางคณิตศาสตร์

  • normal map ถูกใช้เป็น เวกเตอร์ฟิลด์ ที่เข้ารหัส เวกเตอร์นอร์มัล ของแต่ละพิกเซล
  • การแรเงาแบบ Lambert คำนวณด้วย dot product ในรูป v = N·L
  • แปลงเป็นพิกัดทรงกลมเพื่อให้ย่อรูปได้เป็น v = sinNθ sinLθ cos(Nφ−Lφ) + cosNθ cosLθ
    • สมมติให้เวกเตอร์ทั้งหมดมีรัศมี r=1 เพื่อลดปริมาณการคำนวณ

การนำไปใช้บน Game Boy

  • กำหนด Lθ (มุมแนวตั้งของแสง) เป็นค่าคงที่ และให้ผู้เล่นควบคุมเฉพาะ Lφ (มุมหมุนของแสง)
  • ใน ROM จะเก็บแต่ละพิกเซลในรูป (Nφ, log(m), b)
  • เพื่อแก้ปัญหา การไม่มีคำสั่งคูณ จึงใช้การแปลงลอการิทึมและตารางค้นหา (log, pow)
    • เก็บบิตเครื่องหมาย (sign) ไว้ในบิตบนสุดเพื่อรองรับการคำนวณค่าติดลบ
  • ค่าสเกลาร์ทั้งหมดแสดงเป็น เศษส่วน 8 บิตในช่วง -1.0 ถึง +1.0
    • การบวกทำใน linear space ส่วนการคูณทำใน log space
    • ใช้ 127 เป็นตัวส่วนเพื่อให้แทนค่า ±1 ได้ครบ

cos_log และการคำนวณหลัก

  • cos_log คือการ lookup แบบรวมในรูป log(cos x) เพื่อแทนการคูณด้วยการบวกใน log
  • ปริมาณการคำนวณต่อพิกเซล
    • ลบ 1 ครั้ง, lookup cos_log 1 ครั้ง, บวก 1 ครั้ง, lookup pow 1 ครั้ง, บวก 1 ครั้ง
    • รวมเป็นการบวก/ลบ 3 ครั้ง และการ lookup 2 ครั้ง

ประสิทธิภาพ

  • ประมวลผลได้ 15 ไทล์ต่อเฟรม และบางแถวที่ว่างสามารถคำนวณได้เร็วกว่า
  • ใช้เวลาประมาณ 130 ไซเคิลต่อพิกเซล และแถวว่างใช้ 3 ไซเคิล
  • ประมาณ 89% ของ CPU ถูกใช้กับการคำนวณเชดเดอร์ ที่เหลือใช้กับการรับอินพุตและ I/O

Self-Modifying Code

  • เพื่อเพิ่มประสิทธิภาพลูปหลักที่ประมวลผลราว 960 พิกเซลต่อเฟรม จึงมีการ แก้ไขคำสั่งด้วยตัวมันเอง
    • ฝังค่า constant ลงในโค้ดโดยตรงเพื่อให้คำนวณได้เร็วกว่าการโหลดตัวแปร
    • ตัวอย่าง: sub a, 8 เร็วกว่า sub a, variable อยู่ 12 ไซเคิล
    • โดยรวมช่วยลดได้ราว 11,520 ไซเคิล (10%)

ความพยายามในการใช้ AI

  • 95% ของทั้งโปรเจ็กต์ เขียนด้วยมือ
  • AI มีปัญหาในการเขียน Game Boy assembly (SM83)
  • สิ่งที่ใช้ AI ช่วย
    • Python: อ่านเลเยอร์ OpenEXR
    • Blender: สคริปต์อัตโนมัติสำหรับจัดการซีน
    • SM83: สนิปเพ็ตฟังก์ชันบางส่วน (เช่น VRAM DMA)
  • ความพยายามที่ล้มเหลว
    • พยายามให้ AI สร้างโค้ด assembly ของเชดเดอร์ → ไม่มีประสิทธิภาพและมีข้อผิดพลาดจำนวนมาก
  • มีการใช้โมเดล Claude Sonnet 4 เพื่อสร้าง assembly จาก pseudocode
    • บางส่วนใช้งานได้ แต่ช้า และเกิดข้อผิดพลาดอย่างการสับสนระหว่าง Z80 กับ SM83
    • โค้ดสุดท้ายจึงถูกเขียนใหม่ด้วยมือทั้งหมด

บทสรุปและบทเรียน

  • AI มีประโยชน์กับสคริปต์ง่าย ๆ แต่ ความถูกต้องและการตรวจสอบยังเป็นสิ่งจำเป็น
  • ในโค้ดจัดการ OpenEXR นั้น AI ทำให้เกิด ข้อผิดพลาดเรื่องการจัดเรียงแชนเนล (BGR vs RGB) จนกลายเป็นบั๊กที่กินเวลาหลายสัปดาห์
  • จากประสบการณ์นี้จึงเน้นย้ำบทเรียนว่า “เมื่อใช้ AI สิ่งสำคัญที่สุดคือการตรวจสอบ”
  • โปรเจ็กต์นี้ถูกประเมินว่าเป็น กรณีศึกษาการทำเชดเดอร์เชิงทดลองที่ฝ่าข้อจำกัดของฮาร์ดแวร์ยุคเก่า

1 ความคิดเห็น

 
GN⁺ 2026-02-09
ความคิดเห็นจาก Hacker News
  • ดีใจที่ได้เห็นบทความที่มีอารมณ์แบบ แฮ็กเกอร์ของแท้ บน HN

    • ตอนแรกสงสัยว่าแค่งานที่ทำด้วย AI prompt หรือเปล่า อยากรู้ว่าทำออกมายังไง 😉
  • ผลลัพธ์ออกมายอดเยี่ยมมาก เท่าที่ผมเข้าใจ นี่คือ “shader ที่ทำให้ดูเหมือน 3D แต่จริง ๆ แล้วใส่เอฟเฟกต์แสงลงบน 2D normal map ที่เรนเดอร์ไว้ล่วงหน้า”
    เฟรมต่าง ๆ อยู่ที่ลิงก์ GitHub นี้

    • ที่จริงแล้วมันแทบไม่ต่างจากเรนเดอร์แบบ “3D แท้” มากนัก ใน deferred rendering pipeline shader ก็ทำงานบนบัฟเฟอร์ 2D อย่าง depth map, normal map และ color buffer เช่นกัน
      ส่วนการจัดการสามเหลี่ยม 3D จะคงไว้แบบเรียบง่าย และเพราะรัน lighting shader ราคาแพงเพียงครั้งเดียวบนภาพ 2D จึงมีประสิทธิภาพ
      ถ้าจากมุมมองของ shader แล้วอินพุตเป็นเวกเตอร์ 3D มันก็คือ 3D shader การมีหรือไม่มี 3D rasterizer เป็นอีกประเด็นหนึ่ง
      เกม 3D สมัยใหม่ก็ใช้แนวทางนี้ในหลายรูปแบบเช่นกัน แม้แต่ เทคนิค imposter ที่ใช้โมเดลซึ่งเรนเดอร์ไว้ล่วงหน้าจากหลายมุมมอง ก็เป็นเทคนิคที่ใช้ใน 3D engine อย่างเป็นทางการ
    • คล้ายกับวิธีที่ เกมบน Mac สมัยก่อนใส่แสงให้กับ texture 2D โดยไม่มีฮาร์ดแวร์เร่ง 3D
      แต่ครั้งนี้ที่น่าทึ่งคือมันรันบน Game Boy Color ได้
  • สวัสดีครับ ผมคือผู้เขียนเอง ได้ยินว่ามีคนเอาโพสต์นี้มาลงที่นี่เลยสมัครบัญชีมา ขอบคุณที่แชร์ครับ
    ตอนนี้กำลังทดลองทำให้เรียบง่ายขึ้นอีกด้วยการใช้ environment map อยู่ และดูได้จากลิงก์ที่แชร์ไว้บน Bsky

  • เป็นโปรเจกต์ที่น่าสนใจมาก ทำให้นึกถึงสมัยที่เคยเขียน แอสเซมบลีบน C64
    ตอนนั้นก็ไม่มีคำสั่งคูณเหมือนกัน เลยต้องหาวิธีสร้างสรรค์เพื่ออ้อมข้อจำกัดของฮาร์ดแวร์

  • เดิมทีเป็นความพยายามจะลองใช้ AI แต่สุดท้ายก็กลายเป็นการทดลองที่ล้มเหลว
    วงการกำลังพูดถึง AI กันอึกทึก เลยอยากลองสัมผัสด้วยตัวเอง และคิดว่าการ เปิดเผยอย่างโปร่งใสว่าใช้ generative AI หรือไม่ เป็นเรื่องสำคัญ
    ถ้าปิดบังไว้ก็จะบ่อนทำลายความน่าเชื่อถือ แต่ถ้าเปิดเผยก็จะคุยกันอย่างเปิดกว้างกับคนที่มีความเห็นต่างได้

    • เดิมทีใช้โทนเป็นกลาง แต่คนกลับเข้าใจผิดว่าผมกำลังสรรเสริญ AI เลยปรับให้ฟังดูเคลือบแคลงขึ้นเล็กน้อย
      ผมแค่อยากบันทึกกระบวนการนี้ไว้เท่านั้น
  • GBC shader ตัวนี้แสดงให้เห็นความจริงที่ว่า “การคำนวณทั้งหมดภายใต้ข้อจำกัดคือ ค่าประมาณ
    การคูณถูกแทนที่ด้วยการ lookup ตารางและการบวก ส่วนความแม่นยำก็ถูกปรับให้พอดีกับผลลัพธ์ที่ตาเห็น

  • น่าทึ่งจริง ๆ โดยเฉพาะตรงที่มันรันบน ฮาร์ดแวร์ Game Boy Color จริง ได้
    หลายครั้งเรามักเห็นการยัดโปรเซสเซอร์แรง ๆ ไว้ในตลับแล้วใช้ GBC เป็นแค่เทอร์มินัลธรรมดา แต่นี่ไม่ใช่การแฮ็กแบบนั้น

  • พูดตรง ๆ คืออยากให้ Nintendo นำ GBC หรือ GBA กลับมาวางขายอีกครั้ง
    ถ้าขายเป็นตลับที่มีเกมติดมาสักไม่กี่เกม ผมพร้อมซื้อทันที

    • ในตลาดมือสองหาซื้อได้ค่อนข้างถูกอยู่แล้ว เพิ่มแฟลชคาร์ทริดจ์ก็จบ
      แต่ทุกวันนี้ เครื่องพกพา Android ที่มีฟอร์มแฟกเตอร์คล้ายกันใช้งานได้จริงมากกว่า
      ผมเองก็มีคอลเลกชัน Game Boy แต่เดี๋ยวนี้ emulator สะดวกกว่ามาก
    • ไปซื้อ ModRetro Chromatic ที่ผู้ก่อตั้ง Oculus VR ทำไว้ก็ได้
      ต่อให้ Nintendo ทำใหม่ขึ้นมา ก็คงไม่ดีได้เท่านี้
  • โพสต์แบบนี้แหละคือเหตุผลที่ HN มีอยู่
    มันทำให้รู้สึกสนุกแบบเดียวกับตอนเคยนั่งพลิกอ่าน นิตยสารเทคนิค สมัยก่อนอีกครั้ง

  • ผู้เขียนคนนี้เป็น อัจฉริยะสายบ้าระห่ำ ในความหมายที่ดี