11 points par GN⁺ 2025-11-24 | 1 commentaires | Partager sur WhatsApp
  • Retour d’expérience sur l’apprentissage de Vulkan pendant 3 mois et l’implémentation d’un petit moteur de jeu incluant deux jeux de démonstration
  • En s’appuyant sur une expérience préalable avec OpenGL, l’auteur a surmonté progressivement la complexité de Vulkan, en implémentant des fonctions clés comme le chargement glTF, le skinning et le shadow mapping
  • Le moteur, nommé EDBR (Elias Daler’s Bikeshed Engine), compte environ 19 000 lignes de code et utilise des techniques graphiques modernes comme les bindless descriptors, PVP et BDA
  • L’article partage aussi des détails d’implémentation concrets sur des bibliothèques essentielles comme vk-bootstrap, VMA, volk, ainsi que sur le pattern pipeline, l’automatisation de la compilation des shaders et la gestion de la synchronisation
  • Le passage à Vulkan a permis d’obtenir la suppression de l’état global, un contrôle explicite, un meilleur environnement de débogage et une meilleure cohérence entre GPU, avec l’ajout prévu à l’avenir de render graph, polices SDF et effets volumétriques

Vue d’ensemble de l’apprentissage de Vulkan et du développement du moteur

  • L’auteur a commencé la programmation graphique en autodidacte et avait déjà écrit un moteur 3D en OpenGL il y a un an et demi
  • Le moteur basé sur Vulkan convient à des jeux de petite taille structurés en niveaux, avec un objectif centré davantage sur l’apprentissage et l’expérimentation que sur l’efficacité
  • Au départ, l’approche consistait à créer un jeu 3D simple, puis à isoler les parties réutilisables pour en faire un moteur
  • Si le projet a pu être terminé en 3 mois, c’est parce qu’il s’agissait d’un moteur conçu pour un objectif précis, et non d’un moteur générique

Parcours d’apprentissage de la programmation graphique

  • Pour les débutants, il est recommandé de commencer par OpenGL afin d’apprendre à afficher des modèles texturés, l’éclairage Blinn-Phong, le shadow mapping, etc.
  • Parmi les ressources conseillées figurent learnopengl.com, Anton’s OpenGL 4 Tutorials et les cours de Thorsten Thormählen
  • L’auteur souligne aussi l’importance de comprendre l’algèbre linéaire (vecteurs, matrices, quaternions) en complément de supports pratiques récents sur OpenGL 4.6

Conseils pour éviter le bike-shedding

  • Éviter la surconception et les abstractions excessives inutiles, et conserver le principe : « n’implémenter que ce qui est nécessaire maintenant »
  • Adopter l’approche « faire d’abord quelque chose qui fonctionne, puis l’améliorer ensuite »
  • Il est plus efficace de terminer d’abord un petit jeu plutôt que de viser immédiatement un moteur généraliste
  • Ne pas copier tel quel du code ou des structures complexes conçus par d’autres, mais partir d’une structure simple

Pourquoi avoir choisi Vulkan

  • Les jeux AAA utilisent surtout DirectX, Metal domine sur macOS/iOS, et le web s’appuie principalement sur WebGPU/WebGL
  • L’auteur a choisi Vulkan pour sa préférence pour l’open source et les standards, ainsi que pour son adéquation au développement de petits jeux 3D sur desktop
  • OpenGL n’évolue plus et a été abandonné sur macOS
  • WebGPU est plus concis, mais présente encore des limites comme un manque de maturité, des restrictions fonctionnelles et l’absence de prise en charge des bindless et des push constants

Processus d’apprentissage de Vulkan

  • Au début, Vulkan donnait l’impression d’être « au niveau de l’écriture directe d’un pilote graphique »,
    mais l’arrivée du dynamic rendering, de vk-bootstrap et de vkguide a amélioré son accessibilité
  • Principales ressources d’apprentissage :
    • vkguide.dev (approche pratique à partir des bases)
    • TU Wien Vulkan Lecture Series
    • 3D Graphics Rendering Cookbook, Mastering Graphics Programming with Vulkan
  • Dès le premier mois, l’auteur avait terminé l’implémentation du chargement glTF, du compute skinning, du frustum culling et du shadow mapping

Structure du moteur EDBR et traitement d’une frame

  • Le code du moteur compte environ 19 000 lignes, contre 4 600 lignes pour le jeu 3D et 1 200 lignes pour le jeu de plateforme 2D
  • Principales étapes de rendu :
    • Compute skinningCascaded Shadow Mapping (4096×4096)geometry shading basé sur le PBR
    • Depth ResolvePost FX (brouillard basé sur la profondeur)rendu de l’UI
  • Tous les systèmes graphiques ont été réécrits exclusivement pour Vulkan, sans mélange avec l’ancien code OpenGL

Conseils pratiques pour le développement avec Vulkan

Bibliothèques recommandées

  • vk-bootstrap : simplifie l’initialisation et la configuration de la swapchain
  • Vulkan Memory Allocator (VMA) : automatise la gestion mémoire
  • volk : simplifie le chargement des fonctions d’extension

Abstraction GfxDevice

  • Gère dans un seul objet VkDevice, VkQueue, VmaAllocator, etc.
  • Prend en charge le début/la fin de frame, la création d’images et de buffers, ainsi que la gestion des bindless descriptors

Gestion des shaders

  • Utilisation de GLSL, précompilé en SPIR-V au moment du build avec glslc
  • Utilisation de DEPFILE de CMake pour reconstruire automatiquement en cas de modification des shaders

Pattern pipeline

  • Chaque étape de rendu est séparée en pipeline au niveau d’une classe (init, cleanup, draw)
  • L’utilisation de VK_KHR_dynamic_rendering permet d’omettre render pass et subpass, ce qui simplifie la structure

Programmable Vertex Pulling + Buffer Device Address

  • Un seul struct Vertex est utilisé pour tous les meshes
  • Le shader accède directement aux données via buffer_reference, sans besoin de VAO

Bindless Descriptor

  • Utilisation de tableaux globaux de textures (textures[], samplers[]) pour un échantillonnage basé sur l’ID de texture
  • L’ID de texture est stocké dans la structure de matériau et transmis via les push constants

Upload des données dynamiques

  • Les données sont transférées en remplaçant les buffers GPU à chaque frame ou en utilisant un buffer de staging côté CPU
  • La structure en frames in flight est gérée via la classe NBuffer

Nettoyage des ressources et synchronisation

  • Utilisation de fonctions de cleanup explicites, avec gestion manuelle plutôt que via nettoyage automatique dans les destructeurs
  • La synchronisation mémoire entre passes est assurée avec vkCmdPipelineBarrier2
  • Le Render Graph est prévu pour une implémentation ultérieure

Exemples concrets d’implémentation

Rendu de sprites

  • Grâce aux textures bindless et à l’instancing, des milliers de sprites sont rendus en un seul passage
  • La structure SpriteDrawCommand est uploadée dans un buffer GPU, puis vkCmdDraw(6, N) est appelé
  • 10 000 sprites sont rendus en 315 μs

Compute skinning

  • Un compute shader effectue la déformation des vertex à partir des matrices d’os et des poids
  • Un buffer de sortie distinct est créé pour chaque instance, puis traité de la même manière lors du rendu

Séparation jeu/rendu

  • La logique de jeu utilise entt ECS, tandis que le renderer ne traite que des vecteurs de DrawCommand
  • Les commandes de rendu sont générées via drawMesh et drawSkinnedMesh

Chargement de scène et prefabs

  • Les niveaux sont composés dans Blender puis exportés en glTF, et les prefabs sont instanciés automatiquement selon des conventions de nommage des nœuds
  • Les prefabs sont définis en JSON et référencent des glTF externes

MSAA, UI, ImGui

  • Application de MSAA x8 sur une base de forward rendering
  • Mise en place d’un système de layout automatique inspiré de la Roblox UI API
  • Écriture d’un backend Vulkan maison pour résoudre les problèmes sRGB de Dear ImGui

Autres composants

  • Utilisation de Jolt Physics pour la physique, entt pour l’ECS, OpenAL-soft pour l’audio et Tracy comme profiler

Avantages du passage à Vulkan

  • La suppression de l’état global permet une structure de code explicite et modulaire
  • Les validation layers et le débogage avec RenderDoc facilitent le diagnostic des problèmes
  • La cohérence entre GPU et OS est améliorée, avec un comportement plus prévisible qu’en OpenGL
  • Ouverture vers des possibilités d’extension comme de nouveaux langages de shading (slang, shady)
  • Moins d’abstractions et un contrôle plus clair du pipeline améliorent la maintenabilité

Suite prévue

  • Ajout prévu de polices SDF, chargement d’images en parallèle et génération de mipmaps, Bloom, brouillard volumétrique, animation blending, render graph et AO
  • L’apprentissage de Vulkan est difficile, mais il aide énormément à mieux comprendre les API graphiques modernes et à renforcer ses compétences de conception de moteur

1 commentaires

 
GN⁺ 2025-11-24
Avis Hacker News
  • Depuis mon billet publié il y a un an, mon opinion sur Vulkan n’a pas beaucoup changé
    C’est intéressant pour ceux qui veulent un contrôle graphique bas niveau, mais pour moi c’était vraiment une API pénible à utiliser
    J’ai toujours envie d’essayer de créer mon propre moteur de jeu, mais même l’initialisation de Vulkan me fait encore peur
    Ce que je veux, c’est une sorte de version 3D de la manière dont SDL gère les graphismes 2D
    Pour faire de la 3D avec SDL, il faut finalement descendre jusqu’à OpenGL, et ce n’est pas le niveau d’abstraction que je recherche
    Peut-être que WebGPU est une alternative avec laquelle je pourrais prendre du plaisir

    • SDL 3.0 a introduit une API GPU il y a environ un an. C’est une couche d’abstraction qui encapsule plusieurs backends, dont Vulkan, donc ça vaut le coup d’y jeter un œil
      J’ai aussi construit un moteur avec, mais je suis finalement revenu à un moteur basé sur Vulkan parce que je voulais plus de contrôle et de performances
      Cela dit, j’ai appris des schémas de synchronisation dans le code GPU de SDL qui m’ont beaucoup aidé dans mon moteur Vulkan
    • Le wgpu de Rust est un compromis intermédiaire qui offre un niveau d’abstraction proche de WebGPU
      C’est plus puissant qu’OpenGL, mais sans avoir à gérer soi-même des détails comme les barrières de ressources ou les transitions de layout
      Une partie du bookkeeping est prise en charge à l’exécution, avec aussi certaines limitations comme la prise en charge d’une seule file
      Vulkan reste difficile, mais l’usage des extensions supportées par les principaux constructeurs l’améliore nettement
      Malgré tout, il y a encore une complexité inutile, comme l’exigence de réglages détaillés que les pilotes ignorent ensuite
    • En tant que vieux programmeur OpenGL, je suis totalement d’accord
      Aujourd’hui, il n’existe plus vraiment d’API intermédiaire entre les moteurs de jeu haut niveau et Vulkan/Metal bas niveau
      Pour qu’un débutant apprenne la 3D, il faudrait une API simple au niveau de « dessiner un triangle », sans devoir connaître des notions comme les shaders ou les buffers
      Le contrôle très fin de Vulkan n’est utile qu’à une infime minorité de développeurs de moteurs, et pour la plupart, un niveau OpenGL suffit largement
    • Les tentatives de faire une « 3D façon SDL » deviennent vite un moteur full stack
      La 3D a bien plus d’éléments combinables que la 2D, donc une simple API graphique a du mal à suffire
      OpenGL visait initialement cela aussi, mais a fini par devenir complexe
  • « bike shedding » désigne le fait de s’obséder sur des détails mineurs en ratant l’essentiel
    Ce qui est décrit dans le texte original se rapproche plutôt du feature creep ou de l’over-engineering

    • À la place, l’auteur aurait aussi pu employer l’expression « hobby horsing »
      Elle désigne le fait de se concentrer sur son plaisir personnel au point de bloquer l’avancement du projet
      Le bike shedding est souvent expliqué par l’image de « choisir la couleur de l’abri à vélos avant même d’avoir terminé la maison »
    • Ce fil est en train de faire du bike shedding sur le mot même « bike shedding »
  • Certains ont dit que « commencer à développer un moteur avec un clone multijoueur de Minecraft n’est pas une bonne idée »,
    mais en réalité, beaucoup de gens font un jeu de type Minecraft comme premier projet de moteur
    Dans le monde des moteurs voxel, c’est une sorte de « Hello, world »

  • Le billet publié à l’époque en (2024) a atteint 625 points et 260 commentaires — lien vers l’original

  • Vulkan a été la technologie la plus difficile que j’aie jamais apprise
    C’est tellement peu intuitif et répétitif que cela enlève tout le plaisir de programmer

    • Ce n’est pas que tu sois limité. Vulkan est une API d’abstraction de puce bas niveau, aussi amusante qu’une API USB
      Pour commencer plus simplement, je recommande OpenGL, surtout les versions d’avant l’introduction des shaders
      Mais l’industrie pousse OpenGL de plus en plus vers la sortie
    • J’ai eu exactement le même ressenti quand j’ai commencé à apprendre Vulkan
      Je suivais les tutoriels en recopiant le code sans vraiment comprendre les concepts
      Je suis donc passé à WebGPU (Google Dawn), qui était bien plus simple que Vulkan
      Une fois les concepts assimilés grâce aux contraintes de WebGPU, revenir à Vulkan a été beaucoup plus facile
      WebGPU n’a pas de push constants et souffre du problème d’explosion des pipelines, mais Vulkan est plus difficile sur la synchronisation et la gestion mémoire
      SDL_GPU propose aussi une API d’un niveau similaire, donc c’est bien pour débuter
    • C’est aussi pour cela que je ne suis pas encore passé d’OpenGL à Vulkan
      Vulkan est une API excessivement conçue
      Là où CUDA permet une allocation mémoire GPU en une ligne, Vulkan exige une énorme quantité de boilerplate
      Vulkan moderne s’est beaucoup amélioré, mais il reste encore du chemin à faire
    • Quand on voit des exemples de code Vulkan typiques, on comprend tout de suite que ce n’est pas fait pour les développeurs de jeux
      J’espère que SDL3 ou wgpu deviendront la couche d’abstraction qui atténuera cette complexité
      Comme Valve soutient SDL3, je pense que c’est l’option la plus probable
    • Programmer avec Vulkan/DX12 est vraiment douloureux
      La première question à se poser, c’est : « faut-il vraiment faire du graphisme multithread ? »
      Si la réponse est non, il n’y a pas de raison d’utiliser Vulkan/DX12
      Tant qu’il n’y a pas de problème de performances, il vaut largement mieux utiliser OpenGL, DX11, ou un moteur de jeu
  • Je suis fasciné par la programmation 3D/de jeux, et je regarde souvent des YouTubeurs qui montrent leur processus de création de jeux
    Mais c’est un univers bien plus complexe que les web apps ou le DevOps
    On y croise des pixel shaders, des compute shaders, de la géométrie, de l’algèbre linéaire, et même des EDP
    Chaîne YouTube de TokyoSpliff

  • J’aime qu’aujourd’hui, créer un moteur de jeu comme hobby soit considéré comme quelque chose de cool
    Moi aussi, je développe mon moteur personnel depuis 10 ans, et cela a été une expérience très enrichissante

  • Si vous débutez en programmation graphique, il vaut mieux commencer par OpenGL
    J’ai lu les tutoriels OpenGL de NeHe il y a 23 ans, et je pense toujours qu’ils font partie des ressources pédagogiques les mieux structurées

  • Pour information, je ne suis pas l’auteur du billet original ; j’ai seulement conservé le titre