Construire un monde ouvert dans le navigateur, partie 10 : le chaos des raccords et le combat de boss dans les coins
Par Oleg Sidorkin, CTO et cofondateur de Cinevva
Vous découvrez la série ? Consultez le guide de la série. Il explique ce qu'est un spike et contient des liens vers toutes les parties.
Si les parties précédentes semblaient méthodiques, ce chapitre a plutôt ressemblé à un combat.
Les spikes 17 à 22 ont marqué notre période consacrée aux cas limites. Marching cubes à double LOD, raccords entre heightmaps et MC, chunks de coin à résolutions mixtes où trois ou quatre niveaux de LOD se rencontrent, génération des raccords sur le GPU et comportement du mode de repli. Chaque spike traitait un scénario d'échec précis que nous avions rencontré ou anticipé.
Le spike 17 testait le marching cubes double avec deux niveaux de LOD actifs simultanément. La difficulté venait du fait que les voisins d'un même chunk pouvaient avoir des résolutions différentes sur chacune de ses faces. La logique des cellules de transition du spike 16 fonctionnait pour une face à la fois, mais lorsqu'un chunk avait besoin de cellules de transition sur plusieurs faces, la gestion du tampon de sommets devenait complexe. Les cellules de transition de chaque face devaient être générées et ajoutées à la suite sans écraser celles des autres.
Ouvrir le spike 19 dans un nouvel onglet ↗ · Voir le code source
Le premier adversaire récurrent était l'ordre des sommets. À plusieurs reprises, nous pensions avoir des problèmes de topologie avant de découvrir qu'il s'agissait de problèmes d'orientation. L'élimination des faces arrière supprimait des triangles de raccord valides, car leur ordre était inversé par rapport au maillage principal. Même cause profonde, mais symptôme visuel différent selon l'angle de la caméra. La solution a consisté à imposer une convention d'ordre cohérente dans le code d'émission des cellules de transition, puis à la vérifier en activant et désactivant un matériau à double face.
Le deuxième adversaire était la fausse assurance procurée par une correction partielle. Un raccord pouvait sembler parfait sous un angle de caméra, puis se briser lorsque les rôles de LOD s'inversaient entre les chunks de haute et de basse résolution. La cellule de transition est asymétrique. Elle échantillonne différemment le côté haute résolution et le côté basse résolution. Si la logique déterminant « quel côté est en haute résolution » est inversée dans une configuration, le bug n'apparaît que lorsque la caméra atteint une position précise.
Puis est venu l'un de nos retournements de situation préférés. Nous traquions un artefact de coupure de raccord sur des tuiles de heightmap et accusions la logique de transition. Nous y avons passé deux jours. Le véritable coupable était du surdessin résiduel. La géométrie haute résolution d'une frame précédente restait dans la fin du tampon après le passage du chunk à un LOD inférieur. La plage de dessin utilisait toujours l'ancien nombre de sommets, plus élevé. Dès que nous avons limité la plage de dessin au nombre de sommets actifs indiqué par le compteur atomique du compute shader, le « mystérieux problème de raccord » a disparu.
Ce fut un excellent rappel : les bugs de rendu se font souvent passer pour des bugs de génération de maillage. La géométrie avait toujours été correcte. L'appel de dessin lisait simplement au-delà de la fin des données valides.
Au spike 22, nous testions un repli hybride permettant aux chunks de passer du marching cubes au mode heightmap dans certaines conditions, par exemple lorsqu'un chunk ne contient aucune modification volumétrique et se trouve suffisamment loin de la caméra. Cette approche nous offrait une voie plus pragmatique qu'une politique du tout ou rien. Les chunks modifiés proches de la caméra utilisent MC pour offrir une liberté volumétrique. Les chunks éloignés et non modifiés utilisent des heightmaps pour gagner en efficacité.
Ouvrir le spike 22 dans un nouvel onglet ↗ · Voir le code source
Ce chapitre a été la chute vertigineuse des montagnes russes. Frustrante et productive à la fois. Bon nombre des corrections étaient minimes, parfois une seule ligne modifiant un opérateur de comparaison ou un décalage. Mais la compréhension qu'elles nous ont apportée sur l'interaction entre les transitions de LOD, la gestion des tampons et les plages de dessin était loin d'être insignifiante.
Dans la partie 11, nous abordons la couche de stabilisation qui a suivi le chaos : les modes de chunk basés sur des règles et le passage d'une correction réactive des bugs à des règles système explicites.
Technologies abordées dans ce chapitre
Marching cubes à double LOD. Exécution simultanée du marching cubes à deux niveaux de résolution, avec des cellules de transition reliant leur frontière. La difficulté vient du fait que les voisins d'un même chunk peuvent avoir des résolutions différentes sur chacune de ses faces, ce qui nécessite une génération indépendante des cellules de transition pour chaque face. Les cellules de transition de chaque face sont ajoutées au tampon de sommets sans écraser celles des autres. Des compteurs atomiques suivent le nombre total de sommets actifs sur l'ensemble des faces.
Ordre des sommets. L'ordre des sommets de chaque triangle détermine quel côté constitue sa face « avant ». Un ordre cohérent — généralement dans le sens antihoraire vu depuis l'extérieur — est nécessaire pour l'élimination des faces arrière. Lorsque les cellules de transition émettent des triangles, leur ordre doit respecter la convention du maillage principal. Un ordre inversé amène l'élimination des faces arrière à supprimer des triangles de raccord valides, ce qui donne l'impression que des surfaces manquent sous certains angles de caméra. Une technique de débogage courante consiste à activer side: THREE.DoubleSide sur le matériau pour déterminer si les artefacts proviennent de l'ordre des sommets ou de véritables trous topologiques.
Repli d'une heightmap vers MC. Mode de chunk hybride dans lequel les chunks éloignés ou non modifiés utilisent un terrain en heightmap — peu coûteux, avec une surface plane — tandis que les chunks proches ou modifiés utilisent le marching cubes — volumétrique et compatible avec les grottes. La décision de repli dépend de la distance à la caméra et de la présence de modifications SDF dans le chunk. Le raccord entre un chunk de heightmap et un chunk MC nécessite sa propre géométrie de transition, similaire à Transvoxel, mais reliant deux représentations différentes plutôt que deux niveaux de LOD. Consultez la base hybride en heightmap et les couches volumétriques.
Plage de dessin et compteurs atomiques. Dans une génération de maillage pilotée par le GPU, le compute shader écrit les sommets dans un tampon et incrémente un compteur atomique pour suivre le nombre de sommets émis. L'appel de dessin doit utiliser ce compteur comme nombre de sommets, et non la capacité du tampon. Si la plage de dessin n'est pas limitée au nombre de sommets actifs, des sommets résiduels des frames précédentes — toujours présents à la fin du tampon — produisent une géométrie fantôme : de fines lamelles et des triangles qui scintillent, ressemblant à des erreurs topologiques alors qu'il s'agit en réalité d'artefacts de rendu causés par une lecture au-delà des données valides.
Partie 10 sur 12.
Précédent : Partie 9 — Transvoxel a commencé par une structure de base
Suivant : Partie 11 — Un mode défini par des règles, pas codé en dur
Guide de la série : /fr/blog/2026-02-25-open-world-browser-series-guide