1 points par GN⁺ 2026-02-09 | Aucun commentaire pour le moment. | 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

Aucun commentaire pour le moment.

Aucun commentaire pour le moment.