1 points par GN⁺ 2026-02-09 | 1 commentaires | Partager sur WhatsApp
  • Projet ayant implémenté un shading 3D en temps réel sur Game Boy Color, où le joueur peut manipuler la trajectoire de la lumière et faire pivoter l’objet
  • Basé sur le calcul de vecteurs normalisés et du shading de Lambert (dot product), avec une simplification des opérations grâce aux coordonnées sphériques
  • Pour contourner les limites du CPU SM83 dépourvu d’instruction de multiplication, utilisation d’une transformation logarithmique et de tables de correspondance afin d’effectuer les calculs en précision 8 bits
  • L’usage de code auto-modifiant (self-modifying code) permet un gain de performances d’environ 10 %, avec le rendu de 15 tuiles par image
  • La génération de code avec l’IA a échoué dans la plupart des cas, et l’algorithme central comme le shader ont été finalisés à la main

Vue d’ensemble du projet

  • Création d’un jeu qui rend des images en temps réel sur Game Boy Color
    • Le joueur contrôle une lumière en orbite et fait pivoter l’objet
  • L’intégralité du code est publiée dans le dépôt GitHub (nukep/gbshader)

Processus de création 3D

  • Développement du look initial avec Blender, puis poursuite du projet après un résultat visuellement satisfaisant
  • Génération de normal maps à l’aide de Cryptomatte et de shaders personnalisés
    • Pour le modèle de théière, rotation de la caméra afin d’exporter les normal maps en séquence PNG
    • Pour l’écran du modèle Game Boy Color, rendu dans une scène séparée puis composition

Fondements mathématiques

  • La normal map sert de champ de vecteurs encodant le vecteur normal de chaque pixel
  • Le shading de Lambert se calcule sous la forme du produit scalaire v = N·L
  • En passant aux coordonnées sphériques, on simplifie en v = sinNθ sinLθ cos(Nφ−Lφ) + cosNθ cosLθ
    • Le rayon de tous les vecteurs est supposé valoir r=1 afin de réduire la quantité de calculs

Implémentation sur Game Boy

  • Lθ (angle vertical de la lumière) est fixé comme constante, et seul Lφ (angle de rotation de la lumière) est contrôlé par le joueur
  • La ROM stocke chaque pixel sous la forme (Nφ, log(m), b)
  • Pour résoudre l’absence d’instruction de multiplication, le projet utilise une transformation logarithmique et des tables de correspondance (log, pow)
    • Le bit de signe est stocké dans le bit de poids fort afin de gérer les valeurs négatives
  • Toutes les valeurs scalaires sont représentées comme des fractions 8 bits dans l’intervalle -1.0 à +1.0
    • Les additions sont faites dans l’espace linéaire, les multiplications dans l’espace logarithmique
    • Le dénominateur 127 est utilisé afin de pouvoir représenter à la fois +1 et -1

cos_log et opérations clés

  • cos_log est une table combinée sous la forme log(cos x), qui remplace la multiplication par une addition logarithmique
  • Coût des opérations par pixel
    • 1 soustraction, 1 accès à cos_log, 1 addition, 1 accès à pow, 1 addition
    • Soit un total de 3 additions/soustractions et 2 consultations de table

Performances

  • Traitement de 15 tuiles par image, certaines lignes vides étant calculées plus rapidement
  • Environ 130 cycles par pixel, contre 3 cycles pour une ligne vide
  • Environ 89 % du CPU est utilisé pour les calculs du shader, le reste pour les entrées et les E/S

Code auto-modifiant (Self-Modifying Code)

  • Pour optimiser la boucle principale qui traite environ 960 pixels par image, le projet modifie directement les instructions
    • Les constantes sont injectées directement dans le code pour être plus rapides qu’un chargement de variable
    • Exemple : sub a, 8 est 12 cycles plus rapide que sub a, variable
    • Gain global d’environ 11 520 cycles (10 %)

Tentatives d’usage de l’IA

  • 95 % du projet ont été écrits manuellement
  • L’IA a rencontré des difficultés pour écrire de l’assembleur Game Boy (SM83)
  • Usages de l’IA
    • Python : lecture des couches OpenEXR
    • Blender : scripts d’automatisation de scène
    • SM83 : quelques snippets fonctionnels (ex. : VRAM DMA)
  • Tentatives infructueuses
    • Génération du code assembleur du shader avec l’IA → code inefficace et nombreuses erreurs
  • Tentative de génération d’assembleur à partir de pseudocode avec le modèle Claude Sonnet 4
    • Quelques parties fonctionnaient, mais c’était lent et sujet à des erreurs comme la confusion entre Z80 et SM83
    • Le code final a été entièrement réécrit manuellement

Conclusion et enseignements

  • L’IA est utile pour les scripts simples, mais la précision et la vérification restent indispensables
  • Dans le code de traitement OpenEXR, l’IA a provoqué une erreur d’ordre des canaux (BGR vs RGB) ayant entraîné un bug pendant plusieurs semaines
  • L’expérience souligne la leçon suivante : « avec l’IA, la vérification est ce qu’il y a de plus important »
  • Le projet est considéré comme un exemple expérimental d’implémentation de shader repoussant les limites d’un matériel legacy

1 commentaires

 
GN⁺ 2026-02-09
Avis sur Hacker News
  • Ça fait plaisir de voir sur HN un article avec un vrai esprit hacker

    • Je me demandais si ce n’était pas simplement quelque chose fait avec un prompt d’IA. J’aimerais bien savoir comment ça a été implémenté 😉
  • Le résultat est vraiment impressionnant. Si je comprends bien, c’est « un shader qui donne l’illusion de la 3D, mais qui applique en réalité des effets d’éclairage à une normal map 2D pré-rendue »
    Les frames sont sur ce lien GitHub

    • En pratique, ce n’est pas si différent d’un vrai moteur de rendu « 3D ». Même dans un pipeline de rendu différé, les shaders travaillent sur des buffers 2D comme une depth map, une normal map ou un color buffer.
      La partie traitement des triangles 3D reste simple, et les shaders d’éclairage coûteux ne s’exécutent qu’une seule fois sur l’image 2D, ce qui est efficace
      Du point de vue du shader, si l’entrée est un vecteur 3D, alors c’est un shader 3D. La présence ou non d’un rasterizer 3D est une autre question
      Les jeux 3D modernes utilisent aussi ce genre d’approche de différentes façons. La technique des impostors, qui consiste à utiliser des modèles pré-rendus depuis plusieurs angles, est également employée dans de vrais moteurs 3D
    • Ça ressemble à la manière dont les anciens jeux sur Mac appliquaient de l’éclairage sur des textures 2D sans matériel d’accélération 3D.
      Sauf qu’ici, ce qui est étonnant, c’est que ça tourne sur une Game Boy Color
  • Bonjour, je suis l’auteur. J’ai entendu dire que le billet avait été posté ici, alors j’ai créé un compte. Merci pour le partage
    Je fais aussi des essais pour simplifier encore plus avec des environment maps, visibles via ce lien partagé sur Bsky

  • Projet vraiment fascinant. Ça me rappelle l’époque où je faisais du code assembleur sur C64.
    À l’époque aussi, il n’y avait pas d’instruction de multiplication, donc il fallait trouver des moyens créatifs de contourner les limites du matériel

  • C’était une tentative d’utiliser l’IA, mais au final ça a été une expérience ratée.
    Comme tout le secteur ne parle que d’IA, je voulais l’essayer moi-même, et je pense qu’il est important de déclarer de façon transparente l’usage de l’IA générative.
    Le cacher nuit à la confiance, alors que le dire ouvertement permet d’avoir une discussion franche, même avec des gens qui ne partagent pas le même avis

    • Au départ, le ton était neutre, mais comme des gens ont cru que j’étais en train de faire l’éloge de l’IA, je l’ai rendu un peu plus sceptique.
      Je voulais simplement documenter le processus
  • Ce shader GBC montre bien une vérité fondamentale : « tous les calculs, sous contrainte, ne sont que des approximations ».
    Les multiplications sont remplacées par des consultations de table et des additions, et la précision est ajustée en fonction du résultat visuel recherché

  • Franchement impressionnant. Le plus étonnant, c’est surtout que ça tourne sur le vrai matériel Game Boy Color.
    Souvent, on voit des cartouches avec un processeur puissant qui utilisent la GBC comme simple terminal, mais là, ce n’est pas ce genre de bidouille

  • Honnêtement, j’aimerais bien que Nintendo ressorte la GBC ou la GBA.
    S’ils vendaient ça sous forme de cartouche avec quelques jeux intégrés, je l’achèterais tout de suite

    • On peut encore en trouver d’occasion à des prix assez bas. Il suffit d’ajouter une flash cart.
      Cela dit, aujourd’hui, un appareil portable Android au même format est plus pratique.
      J’ai moi aussi une collection de Game Boy, mais maintenant les émulateurs sont bien plus confortables
    • Il suffit d’acheter la ModRetro Chromatic créée par le fondateur d’Oculus VR.
      Même si Nintendo en refaisait une, j’ai du mal à imaginer que ce serait aussi bien
  • C’est exactement pour ce genre d’articles que HN existe.
    Ça redonne la sensation qu’on avait autrefois en feuilletant les vieux magazines techniques

  • Cet auteur est un génie complètement barré, dans le bon sens du terme