1 points par GN⁺ 2024-09-06 | 1 commentaires | Partager sur WhatsApp
  • Nanite WebGPU est un projet qui implémente dans le navigateur, via WebGPU, un rendu de type Nanite d’UE5, avec une hiérarchie de LOD par meshlet, un rasterizer logiciel, des billboard impostors et du culling au niveau des instances et des meshlets
  • L’implémentation vise principalement la simplicité d’un prétraitement des entrées OBJ dans le navigateur, ainsi que l’expérimentation des variations de performances en modifiant les paramètres via des cases à cocher et des curseurs
  • La démo propose la scène Jinx à 640M triangles, ainsi que Lucy/Dragons et d’autres scènes allant jusqu’à 1.7B triangles ; les triangles blancs de Jinx sont le résultat du rasterizer logiciel, compressés et traités en 32 bits à cause des limitations de WebGPU
  • Comme WebGPU ne dispose pas de atomic<u64>, il est difficile d’implémenter tel quel un rasterizer logiciel efficace basé sur un visibility buffer ; l’implémentation actuelle accepte donc des artefacts de précision en stockant une profondeur u16 et une normale octaédrique 2*u8 sur 32 bits
  • Dans une implémentation réellement inspirée de Nanite, la difficulté centrale n’est pas simplement le nombre de triangles, mais la simplification de mesh et l’error metric ; l’auteur précise que son implémentation ne dispose pas, contrairement à UE5, de simplification, de streaming, de compression, de visibility buffer ni d’occlusion culling en deux passes

Aperçu du projet

  • Nanite WebGPU est un projet qui implémente un rendu de type Nanite dans le navigateur web à l’aide de WebGPU
  • Les principaux éléments inclus sont une hiérarchie de LOD par meshlet, un rasterizer logiciel, des billboard impostors et du culling au niveau des instances et des meshlets
  • Le projet prend en charge les modèles texturés et les normales par sommet, avec des curseurs et des cases à cocher pour chaque réglage
  • WebGPU n’est utilisable que dans Chrome
  • L’application complète peut aussi fonctionner hors ligne avec Deno, et les tests unitaires des shaders sont également écrits de cette façon

Scènes de démo et échelle

  • La démo Jinx utilise 120×120 instances, pour un total de 640M triangles
    • Un modèle Jinx unique est simplifié de 44k triangles à 3k triangles, avec 59 root meshlets
    • Les triangles blancs sont des triangles rasterisés en logiciel, situés entre la zone rasterisée par le matériel et les impostors de l’arrière-plan lointain
  • Lucy and dragons place deux objets en 70×70 instances chacun, pour former 1.7B triangles
    • Dans la scène d’exemple, près de 98 % des triangles sont rasterisés en logiciel, et l’auteur indique que ce chemin est bien plus rapide que le matériel
  • Lucy est une scène de 110×110 instances, soit 1.2B triangles
    • Une seule statue Lucy est simplifiée de 100k triangles à un unique root meshlet de 86 triangles
  • Dragons est une scène de 70×70 instances, soit 1.2B triangles
    • Un dragon unique est simplifié de 250k triangles à un unique root meshlet de 102 triangles
  • Bunnies est une scène de 500×500 instances, soit 1.2B triangles
    • Un bunny unique est simplifié de 5k triangles à un unique root meshlet de 96 triangles
    • Le bunny étant petit, la plupart sont éliminés par le frustum culling

Fonctionnalités implémentées

  • Hiérarchie de LOD par meshlet

    • Le prétraitement du mesh s’exécute dans le navigateur
    • meshoptimizer et METIS sont utilisés via WebAssembly
    • Un exporteur de fichiers est également fourni pour éviter d’attendre le prétraitement entre deux rechargements de page
  • Rasterizer logiciel

    • WebGPU ne dispose pas de atomic<u64>, nécessaire à une implémentation efficace
    • L’implémentation actuelle compacte une profondeur u16 et des normales encodées par octaèdre 2*u8 sur 32 bits
    • À cause de cette limite de 32 bits, la précision est fortement sacrifiée, l’objectif étant surtout de montrer que le rasterizer fonctionne
    • Cette contrainte affecte aussi la depth pyramid utilisée pour l’occlusion culling
  • Billboard impostors

    • 12 images autour de l’axe vertical sont utilisées, puis mélangées par dithering selon la position de la caméra
    • Les vues depuis le dessus ou le dessous ne sont pas gérées
    • Les données diffuse et normales sont toutes deux incluses afin d’effectuer le shading à l’exécution
    • Impostors preview est une démo avec une taille de texture d’impostor plus grande

Culling et chemins de rendu

  • Le culling se compose de plusieurs étapes
    • Par instance : frustum culling et occlusion culling
    • Par meshlet : frustum culling et occlusion culling
    • Par triangle : hardware backface culling et z-buffer
  • WebGPU ne dispose pas d’early-z
  • L’occlusion culling n’utilise qu’une depth pyramid construite à partir du depth buffer de la frame précédente
    • Il n’y a ni reprojection ni approche en deux passes
    • L’auteur considère que l’implémentation actuelle suffit déjà à éliminer de nombreux triangles et à évaluer les gains de performances
  • Il est possible de basculer entre un rendu piloté par le GPU et une implémentation CPU simple
    • La version CPU n’a pas reçu beaucoup d’optimisations, mais elle permet une exécution pas à pas dans le débogueur
  • La fonction « Freeze culling » permet, tout en déplaçant la caméra, d’inspecter uniquement ce qui a été dessiné à la dernière frame

Utilisabilité et débogage

  • Les déplacements utilisent [W, S, A, D], la montée/descente [Z, SPACEBAR], et le déplacement rapide [Shift]
  • En cas de résultat étrange, on peut vérifier en activant et désactivant les options de culling
    • L’implémentation contient quelques petits bugs
  • Les triangles blancs sont des triangles rasterisés en logiciel
    • En raison de l’absence de atomic<u64> dans WebGPU, la profondeur et la normale sont compressées sur 32 bits
    • Une profondeur 16 bits peut provoquer de nombreux artefacts, comme du z-fighting ou des fuites
    • Désactiver le rasterizer logiciel permet de voir plus facilement les meshlets Nanite bruts, mais peut entraîner une forte baisse de performances
  • Les FPS peuvent fluctuer à cause du VSync forcé du navigateur ; pour vérifier les timings, il faut utiliser le bouton « Profile »

Objectifs de conception

  • Le premier objectif du projet est la simplicité
    • Il part d’un fichier OBJ et effectue tout le traitement dans l’application
    • Il ne nécessite pas d’étape de prétraitement séparée, comme un export Blender
    • L’idée est d’avoir un flux que l’on peut suivre en plaçant un point d’arrêt dans loadObjFile() jusqu’à la fin de la première frame
  • Le deuxième objectif est son caractère expérimental
    • Comme il a été réalisé sous forme de page web plutôt qu’en Rust et Vulkan, on peut cliquer sur un lien, changer des cases à cocher ou des curseurs, et observer les variations de performances
    • On peut vérifier directement quelles options sont importantes, par exemple lorsqu’un simple changement de paramètre fait chuter fortement les FPS
  • Une grande partie du code pourrait être optimisée, mais tant que le problème de simplification n’est pas résolu, ces optimisations ne sont pas jugées prioritaires

Différences avec UE5 Nanite

  • La métrique d’erreur utilise un simple projected simplification error
  • La simplification des meshlets suit une approche simple
  • Il n’y a pas de two-pass occlusion culling
    • Ce ne serait pas difficile à ajouter, mais le débogage serait fastidieux et cela créerait des interactions avec les paramètres du GUI
    • Cela nuirait à la lisibilité du code, donc ce n’est pas cohérent avec l’objectif visé
  • Il n’y a pas de visibility buffer
    • Impossible à implémenter à cause de la limitation sur atomic<u64>
  • Il n’y a ni shadows intégrées ni multiview
  • Il n’y a pas de work queue dans les shaders
    • Pour le culling des meshlets et la sélection de LOD, un thread est dispatché par meshlet
  • Il n’y a ni eviction de la VRAM ni streaming pour les LOD non utilisées
  • Il n’y a pas de compression
  • La solution passe mal à l’échelle avec de nombreux objets différents
    • L’accent est mis sur une utilisation mémoire prévisible dans le cas de démonstration
    • Il faut connaître à l’avance la borne supérieure des meshlets dessinés afin d’allouer les buffers qui stockent les données entre les stages
  • Il n’y a pas de BVH ni de hiérarchie pour les instances
    • Le frustum culling et l’occlusion culling sont effectués sur toutes les instances

Ce qu’implique le nombre de triangles

  • Le seul chiffre des « dizaines de milliards de triangles » ne suffit pas pour juger les performances, qui dépendent de nombreux facteurs
  • Dense meshes

    • Une forte présence de dense meshes à courte distance peut nuire aux performances
    • Cela dit, si elles sont assez proches pour couvrir une grande partie de l’écran, l’occlusion culling entre en jeu
    • La géométrie dense a des meshlets petites, occupe peu d’espace à l’écran et se prête plus facilement à l’occlusion culling ou au cone culling
  • Instance count

    • Chaque instance embarque une matrice de transformation mat4x3, ce qui consomme de la VRAM
    • Pendant la frame, il faut aussi stocker la liste des éléments à rendre
    • Dans le pire des cas, chaque instance rend les meshlets les plus denses
    • L’implémentation alloue instanceCount * bottomLevelMeshletsCount * sizeof(vec2u) octets
    • La limite par défaut des storage buffers WebGPU dans Chrome est de 128 Mo, et la scène de démo a été ajustée en conséquence
  • Scene arrangement

    • Dans la scène de l’application, les objets sont disposés en carré
    • Les objets lointains ne sont visibles qu’en partie, mais les meshlets LOD grossières couvrent des zones plus larges, ce qui provoque de l’overdraw
    • Un placement dense en grille amène à rendre davantage de triangles proches, mais avec de faibles écarts de profondeur, ce qui favorise l’occlusion culling
    • Des objets très éloignés peuvent amener des pixels lointains aléatoires à polluer la depth pyramid

Pourquoi la scène Jinx est difficile

  • Le personnage de Jinx est mince et présente des espaces vides entre les bras et le torse, ce qui complique l’occlusion culling
  • Le modèle se simplifie mal, si bien que même le LOD le plus grossier compte encore 3k triangles
  • Cela crée des situations où de nombreux triangles d’un pixel s’accumulent
  • Le rasterizer logiciel aide beaucoup, mais à cause de l’agencement de la scène, la plupart des instances sont rendues en impostor
  • Dans les zones proches, c’est le rasterizer matériel qui prend le relais, et le rasterizer matériel, le rasterizer logiciel et l’impostor ont chacun des points forts différents

Ce qui surprend dans l’implémentation de Nanite

  • Le but du DAG n’est pas simplement d’utiliser moins de triangles pour les objets lointains, mais de maintenir une cohérence proche de 1 pixel == 1 triangle sur l’ensemble de l’écran
  • Avec des meshes LOD discrètes, chaque LOD est une géométrie distincte, ce qui rend difficile la gestion des étapes intermédiaires, d’où le besoin d’un LOD continu
  • La hiérarchie de meshlets permet d’échantillonner la géométrie au niveau de détail choisi
  • Le culling et le traitement des meshlets prennent plus de temps que Nanite lui-même
  • Il est facile de faire fonctionner une hiérarchie de meshlet LOD, mais difficile de la rendre efficace
  • Si un mesh ne se simplifie pas proprement, on obtient des cas comme Jinx, avec environ 3 000 triangles couvrant un seul pixel
  • Si l’on veut des triangles de taille pixel, un rasterizer logiciel est nécessaire, et un billboard impostor est aussi utile comme fallback axé sur la stabilité

Problème de mesh simplification

  • La simplification n’est pas le problème consistant à « prendre un mesh et le réduire à X % de triangles », mais un problème traité dans le contexte des meshlets et de METIS
  • UE5 utilise son propre code de mesh simplification comme première étape de la pipeline d’assets
    • Le coût réduit à ce stade apporte ensuite des gains en cascade à l’ensemble du système
    • Dans les documents SIGGRAPH de Brian Karis, le graphe de LOD aboutit à un unique cluster racine, et il est indiqué que n’importe quel modèle peut être simplifié à 128 triangles
  • Le modèle de Jinx rencontrait un problème où la simplification s’arrêtait à un certain point
    • On pouvait fournir X triangles en entrée et récupérer les mêmes X triangles en sortie
    • L’algorithme plantait sur une assertion
    • Ensuite, les parties du mesh qui ne se réduisaient pas assez ont conduit à autoriser plusieurs racines dans le DAG
  • Le modèle du lapin s’est d’abord simplifié en un unique meshlet de 128 tris, mais un changement de conditions a révélé qu’il ne convergerait pas vers une racine unique
    • Beaucoup de meshlets ne réduisaient pas assez leur nombre de triangles, et il y avait aussi beaucoup de meshlets « non pleines » à moins de 128 triangles
  • Discussions liées :

Métrique d’erreur

  • Lors du rendu d’un mesh de 20 000 000 triangles avec une hiérarchie de meshlets, il faut choisir quel meshlet est le meshlet « correct »
  • Ce problème de sélection est au cœur de Nanite, et la simplification, le DAG de meshlets et le rasterizer logiciel sont presque des prérequis pour le traiter
  • L’implémentation utilise le projected simplification error fourni par meshoptimizer
  • L’auteur estime que cette métrique n’est pas une bonne métrique pour Nanite et que d’autres attributs de vertex devraient aussi être inclus dans la fonction
    • Il devrait être possible d’attribuer un poids à chaque attribut
    • Les normales du visage de Jinx ont posé un gros problème
  • Références consultées :

Pourquoi le rasterizer logiciel ne produit pas de textures

  • Avec un hardware rasterizer, il est possible d’écrire ensemble la depth texture, la couleur et les normales selon le résultat du depth test
  • Dans un rasterizer logiciel, si plusieurs threads écrivent sur le même pixel, cela crée une race condition
  • La solution classique est le visibility buffer
    • Il écrit le sceneUniqueTriangleId du triangle le plus proche dans chaque pixel
    • Il le combine avec une profondeur 32 bits pour former une valeur 64 bits, puis utilise des opérations atomiques 64 bits
    • Dans un pass séparé, il rasterize à nouveau les triangles et calcule les coordonnées barycentriques pour faire le shading
  • WebGPU ne dispose pas d’atomiques 64 bits, donc cette approche ne peut pas être utilisée
  • L’objectif de ce projet est de montrer que le rasterize logiciel fonctionne ; c’est pourquoi le modèle rasterizé en logiciel à l’arrière-plan est blanc et ne fournit qu’un shading raisonnable

Avis sur une implémentation maison de Nanite

  • La réponse la plus simple est d’utiliser UE5
  • Pour intégrer cette technologie dans un moteur existant, il faut d’abord, selon l’auteur, passer par l’implémentation d’une graphics pipeline basée sur le compute et d’une pipeline de rendu pilotée par le GPU
  • Des problèmes comme le multi-step culling, la gestion des chunks de scène/monde et les meshes animés apparaissent d’abord
  • L’ordre proposé est de stabiliser d’abord ces étapes, puis d’essayer un rasterizer logiciel, et ensuite d’ajouter une technologie de type Nanite
  • Dans un toy renderer, une hiérarchie de meshlets de base peut être un projet de week-end, mais une implémentation réelle doit traiter les problèmes de simplification et de métrique d’erreur

Outils utilisés et références

  • meshoptimizer constitue la base essentielle de l’implémentation du projet
    • Les versions plus récentes de meshoptimizer incluent meshopt_SimplifySparse pour créer un clone de Nanite
    • Le projet n’a pas été mis à jour vers cette version afin de conserver l’état testé pendant le développement
  • METIS est utilisé
  • Emscripten sert à exécuter meshoptimizer et METIS dans le navigateur
  • Le modèle Jinx utilisé est Arcane - Jinx de Sketchfab, avec fusion des textures, ajustement des UV et suppression de l’arme

1 commentaires

 
GN⁺ 2024-09-06
Avis sur Hacker News
  • Oh, excellent. On a donc une implémentation tierce de la lecture de Nanite
    Nanite représente les maillages graphiques de façon très ingénieuse. Ce n’est pas un arbre, mais un graphe orienté acyclique : les répétitions deviennent donc des liens plutôt que des copies, un maillage peut partager des sous-maillages, et ces sous-maillages peuvent eux-mêmes être partagés. Il prend aussi en charge les niveaux de détail internes au maillage (LOD), de sorte que les sous-maillages sont éliminés lorsqu’ils deviennent suffisamment petits
    Cela permet de gérer de très grands contenus répétitifs avec une quantité finie de données et des temps de rendu rapides. L’intuition est que l’écran comporte un nombre limité de pixels, donc la quantité de travail de rendu réellement nécessaire a elle aussi une borne supérieure
    Il existe une excellente vidéo SIGGRAPH où quelqu’un d’Epic l’explique. Les GPU actuels ne sont pas très adaptés à Nanite ; pour déplacer davantage de traitement vers le GPU, il faudrait de nouvelles opérations matérielles. Avec Nvidia accaparé par le marché de l’IA, on peut se demander si ce genre d’évolution aura lieu
    Pour que cette approche soit efficace, il faut beaucoup d’instancing dans la scène. Elle convient bien aux jeux AAA qui créent de vastes contenus en réutilisant un nombre limité d’objets, comme le hall rempli de statues identiques dans la démo d’Unreal Engine. En regardant des vidéos de Cyberpunk 2077, si vous cherchez les rambardes et les tas de détritus, vous verrez les mêmes éléments se répéter sans cesse dans des contextes complètement différents
    La création de maillages Nanite est complexe à cause des nombreux offsets de liens internes et, jusqu’ici, seul l’éditeur d’Unreal Engine s’en chargeait. Maintenant que la partie lecture est open source, il y a de fortes chances que quelqu’un crée aussi des outils de production
    Cela dit, les offsets internes du format peuvent constituer une surface d’attaque, et on imagine assez bien des contenus spécialement manipulés être exploités, à la manière de fichiers Microsoft Word .doc malveillants

    • Ils construisent bien un graphe orienté acyclique pour la découpe du graphe, mais les données finales sur disque ne sont qu’une liste plate de clusters avec des critères d’inclusion/exclusion. Il semble y avoir un assez gros malentendu sur l’usage du DAG et sur la façon dont il est construit
      Le DAG est généré dynamiquement à partir des données de sommets et n’a rien à voir avec la manière dont l’artiste a structuré les sous-maillages. Ce n’est pas non plus que « les répétitions deviennent des liens »
      Par ailleurs, comme le résultat de la découpe du graphe varie pour chaque instance d’objet, on ne peut pas utiliser l’instancing traditionnel ; je ne comprends donc pas pourquoi il faudrait beaucoup d’instancing dans la scène pour que cela soit efficace
    • À l’époque, dans les années 2000, je développais sur PS3 et je cherchais un moyen d’exploiter correctement les importantes ressources de calcul du Cell, ainsi qu’une façon de contourner la bande passante mémoire limitée du RSX. On avait aussi largement de la place sur Blu-ray
      J’avais alors bien avancé sur quelque chose de similaire à Nanite, que j’appelais maillages compressés. C’était un exemple typique d’arrogance d’ingénierie mal placée
      Les premiers travaux semblaient prometteurs, mais plus je creusais le problème, plus l’ensemble devenait complexe. Il fallait construire toute une pipeline de génération d’assets, et c’était beaucoup trop ambitieux pour obtenir dans les délais des résultats visuellement satisfaisants sans exploser la mémoire
      J’étais allé jusqu’à quelque chose qui donnait l’impression de rendre de grands maillages avec des niveaux de détail en cascade, mais c’était très lent, et à moins de pousser le GPU à bout pour obtenir une précision subpixel, le résultat était affreux. C’était une expérience intéressante, mais le matériel était dépassé et la tâche était trop vaste pour une seule personne
      Quand Epic a présenté Nanite, j’ai été vraiment stupéfait. Ils avaient réussi ce que je n’avais pas su faire, et d’une manière bien meilleure que tout ce que j’avais pu imaginer. C’est l’une de ces technologies qui, à son arrivée, n’était pas du battage médiatique mais une vraie solution, et c’est un joyau technique du monde graphique moderne. Si Epic avait été cotée en Bourse, j’aurais sérieusement envisagé d’y investir une somme importante rien que pour la technologie Nanite
    • La présentation SIGGRAPH mentionnée est probablement « A Deep Dive into Nanite Virtualized Geometry » : https://www.youtube.com/watch?v=eviSykqSUUw
      Une courte vidéo d’introduction de haut niveau était également intéressante : « What is virtualized micropolygon geometry? An explainer on Nanite » : https://www.youtube.com/watch?v=-50MJf7hyOw
    • Ce n’est pas un moteur grand public, mais le petit moteur de jeu ECS en Rust Bevy prend lui aussi en charge quelque chose de similaire, sous le nom de fonctionnalité « Virtual Geometry » : https://bevyengine.org/news/bevy-0-14/#virtual-geometry-expe...
      Il existe aussi un article technique approfondi écrit par l’un des auteurs de cette fonctionnalité : https://jms55.github.io/posts/2024-06-09-virtual-geometry-be...
    • En lisant les articles, j’ai eu l’impression que les plus gros gains venaient des coordonnées quantifiées et du niveau de détail dynamique appliqué à de petits patchs plutôt qu’au maillage entier
      D’après ma compréhension, la logique de Nanite consiste à maintenir la précision du maillage autour d’une précision d’environ 1 pixel. Par exemple, si l’erreur après projection en perspective reste autour d’un demi-pixel, on peut utiliser un maillage peu détaillé dont les coordonnées ont été arrondies à environ 10 bits
      Il me semble me souvenir que la quantification jouait deux rôles. Elle réduisait la taille de stockage des données, mais aidait aussi à la génération des niveaux de détail en alignant les sommets sur les mêmes positions dans l’espace, ce qui permettait ensuite d’éliminer les doublons
  • Cela a été mentionné plusieurs fois dans ce fil, mais Bevy possède aussi une implémentation des idées de Nanite. On l’appelle parfois géométrie virtuelle. J’en suis l’auteur, donc je peux répondre aux questions :)
    Scthe a fait un excellent travail sur ce projet. Nous avons discuté ensemble de plusieurs aspects du processus, et cette expérience a aussi permis d’améliorer le code de Bevy : https://github.com/bevyengine/bevy/pull/15023
    C’est toujours réjouissant de voir davantage de personnes se lancer dans ce domaine. Nanite regorge vraiment d’idées brillantes

  • La démo utilise-t-elle la chaîne user-agent pour déterminer la compatibilité ? Ce n’est pas une bonne pratique. La compatibilité fonctionnelle doit être évaluée au cas par cas, en détectant directement une fonctionnalité donnée ou en essayant de l’utiliser
    J’utilise Chromium, pas Chrome, et j’utilise aussi WebGPU en permanence, mais la démo me dit d’utiliser Chrome. Éthiquement, je ne peux pas faire ça. J’aimerais vraiment essayer cette démo, qui semble être un projet ayant demandé beaucoup d’efforts

    • À titre de référence, elle ne fonctionne pas non plus dans Chrome sous Linux, ni sur Android. En pratique, j’utilise presque toujours Firefox pour naviguer. Il y a quelque chose d’assez étrange dans la logique de détection
    • Il ne semble pas que ce soit le cas. Dans Firefox avec la prise en charge expérimentale de WebGPU activée, elle échoue avec une erreur de compilation de shader au lieu d’un message distinct
    • Viser une détection par fonctionnalité est une bonne chose
      Quand je développais moi-même un framework de composants pour navigateur, la détection était souvent impossible, donc il fallait se rabattre sur le browser sniffing. Le code de Modernizr contient beaucoup de hacks très ingénieux pour la détection de fonctionnalités, parfois aussi des hacks franchement très sales. Un travail énorme a été nécessaire pour produire du code de détection fiable, et la détection se faisait généralement via des effets de bord
      À mon avis, la détection des fonctionnalités Web3D n’est pas simple. Une recherche rapide ne fait pas apparaître de bibliothèque évidente de détection de fonctionnalités Web3D
      Voici une partie du code de Modernizr pour détecter la prise en charge de :checked :
      Modernizr.addTest('checked', function(){
      return Modernizr.testStyles('#modernizr input {width:100px} #modernizr :checked {width:200px;display:block}', function(elem, rule){
    • Je ne sais pas quel build vous utilisez, mais j’utilise Ungoogled Chromium et la chaîne user-agent est exactement la même que celle de Google Chrome
      Avez-vous activé l’autorisation WebGL pour ce site dans les paramètres du site ? Dans mon cas, il me semble qu’elle était désactivée par défaut
    • La démo elle-même semble simplement cassée. J’obtiens cette erreur :
      WebGPU error [frame][validation]: Fill size (7160950) is not a multiple of 4 bytes.
      • While encoding [CommandEncoder "main-frame-cmd-buffer"].ClearBuffer([Buffer "rasterize-sw"], 0, 7160950).
  • Voici la thèse de doctorat de 2009, assez passée inaperçue, de Federico Ponchio, qui a inventé l’algorithme de simplification dynamique de maillages à la base de Nanite. Il y a aussi beaucoup d’illustrations
    https://vcg.isti.cnr.it/~ponchio/download/ponchio_phd.pdf C’est à la page 107

  • C’est impressionnant que cela fonctionne dans une certaine mesure, mais l’absence d’opérations atomiques 64 bits dans WebGPU oblige à faire des compromis assez grossiers
    J’espère qu’elles seront ajoutées un jour sous forme d’extension optionnelle. Au moins sur du matériel de classe desktop, la prise en charge matérielle est presque universelle. AMD et Nvidia l’ont depuis longtemps, et Apple la prend en charge depuis le M3

    • À quoi servent les opérations atomiques dans le rastériseur ? Je ne vois pas ce que font les opérations atomiques dans le pipeline de rendu. J’ai aussi regardé sur GitHub, mais je n’ai pas trouvé l’endroit où je m’attendais à voir des opérations atomiques
    • Depuis le M2
  • Sur iPhone 12 Pro Max, il est indiqué qu’il n’y a pas WebGPU, mais si je l’active dans les fonctionnalités expérimentales, un autre site de démos WebGPU[1] fonctionne. Quelqu’un a-t-il réussi à faire marcher celle-ci sur iPhone ? Ce serait bien que l’application web indique plus précisément ce qui échoue
    [1] https://webgpu.github.io/webgpu-samples/?sample=texturedCube

    • J’ai activé WebGPU dans Safari, mais je vois une foule d’erreurs de shader
      WebGPU error [init][validation]: 6 errors generated while compiling the shader: 50:22: unresolved call target 'pack4x8snorm' 50:9: cannot bitcast from '⊥' to 'f32' 54:10: unresolved call target 'unpack4x8snorm' 59:22: unresolved call target 'pack4x8unorm' 59:9: cannot bitcast from '⊥' to 'f32' 63:9: unresolved call target 'unpack4x8unorm'
    • La prise en charge de WebGPU dans Safari n’est pas encore terminée, c’est pourquoi elle reste une fonctionnalité expérimentale
  • Le nom et la description sont très déroutants, et il me semble même qu’il pourrait y avoir un risque de violation de marque. Contrairement à ce qui est affirmé, cela n’a absolument rien à voir avec le vrai Nanite d’UE5 ; on dirait plutôt une implémentation de quelque chose de similaire par une personne sans lien avec UE5
    Il existe aussi Virtual Geometry de Bevy, qui fournit une fonctionnalité similaire. C’est écrit en Rust et intégré dans un moteur de jeu, donc cela a de bonnes chances d’être bien plus utile : https://jms55.github.io/posts/2024-06-09-virtual-geometry-be...

    • Ça ne me semble pas être un gros problème. Le README indique clairement qu’il s’agit d’une implémentation
      Si je disais avoir « implémenté le GPT-3 d’OpenAI en JS », je comprendrais que cela signifie avoir repris l’architecture du livre blanc pour la réimplémenter
  • Ce n’est pas réellement UE5 Nanite tournant dans WebGPU. C’est une implémentation indépendante d’idées similaires à celles de Nanite
    Cette technique commence à apparaître à plusieurs endroits. Nanite a certes popularisé l’idée, mais Nanite n’est pas le nom de la technique : c’est le nom d’une implémentation particulière

  • Je me demande où en sont les autres moteurs en matière de niveaux de détail et de systèmes similaires.
    Godot propose une fonctionnalité automatique de niveau de détail, et elle a l’air plutôt bonne en soi : https://docs.godotengine.org/en/stable/tutorials/3d/mesh_lod...
    Unity dispose aussi d’un système de niveaux de détail, mais malgré la popularité du moteur, il faut créer manuellement les modèles de niveaux de détail : https://docs.unity3d.com/Manual/LevelOfDetail.html, sauf si vous cherchez un plugin sur l’Asset Store.
    J’ai aussi vu une approche intéressante dans un moteur moins connu appelé NeoAxis : https://www.neoaxis.com/docs/html/NeoAxis_Levels.htm ; cela dit, les performances étaient très mauvaises sur mon ancienne RX580, et je ne l’ai pas encore essayé sur mon A580 actuel.
    À mon avis, Unreal est nettement en avance sur ses concurrents pour ce qui est de la capacité à afficher beaucoup de choses à l’écran. L’inconvénient, c’est que les artistes ont alors envie d’intégrer des assets de meilleure qualité dans les jeux, ce qui peut faire fortement gonfler la taille d’installation.

    • En théorie, Nanite est supérieur aux niveaux de détail précalculés. En pratique, c’est plus difficile à affirmer aussi catégoriquement. Il a du mal à être aussi bon que des niveaux de détail créés à la main par un artiste, et il n’est pas raisonnable de s’y attendre.
      Le coût en performances est également élevé. Nanite, ou la géométrie virtuelle, ne s’accorde pas très bien avec les GPU modernes. De mémoire, le taux de remplissage maximal était d’environ un quart. C’est parce que la rastérisation GPU ne fonctionne pas au pixel comme les shaders, mais par quads de 2x2.
    • Les GPU Intel Arc sont mauvais pour le rendu Nanite. Ils ne prennent en charge matériellement ni les indirect draws, largement utilisés dans les renderers pilotés par le GPU, ni les opérations atomiques 64 bits nécessaires à Nanite. Intel émule les indirect draws en logiciel, ce qui est lent.
  • Chaque fois que je vois une scène de rendu avec autant de géométrie statique répétitive, j’entends dans ma tête la voix de cet agaçant personnage qui parlait de « détail illimité » dans une vieille vidéo de vaporware.
    Nanite semble vraiment avoir résolu ce problème, contrairement à cette vieille chose. Je me souviens qu’on disait qu’ils utilisaient quelque chose comme un octree.

    • Je crois que l’entreprise qui faisait cette affirmation s’appelait Euclidean. Il me semble qu’elle était australienne.
      Des rumeurs en ligne disaient qu’ils utilisaient un octree, mais les vidéos ultérieures d’Euclidean l’ont catégoriquement nié.