Skip to content

Construire un monde ouvert dans le navigateur, partie 11 : un mode piloté par des règles, pas codé en dur

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 renvoie vers toutes les parties.

Après le chapitre consacré au chaos des raccords, nous devions cesser de réagir au cas par cas et commencer à piloter le système.

Le spike 23 a remplacé les comportements ponctuels par des règles explicites. Au lieu de laisser chaque chunk agir selon ce que suggérait son état local, un système centralisé prenait désormais les décisions. Quel niveau de LOD attribuer à ce chunk ? Doit-il être rendu sous forme de heightmap ou avec marching cubes ? A-t-il besoin de cellules de transition, et sur quelles faces ? Les réponses venaient d'une fonction de règles qui évaluait la distance à la caméra, l'historique des modifications et les états de résolution des voisins.

Ouvrir le spike 23 dans un nouvel onglet ↗ · Voir le code source

L'attribution du LOD selon la distance utilisait des anneaux concentriques autour de la caméra, sur un principe proche de celui des clipmaps, mais appliqué à la grille de chunks. Les chunks de l'anneau 0 utilisent MC à pleine résolution. Ceux de l'anneau 1 utilisent MC à demi-résolution. Ceux de l'anneau 2 et au-delà utilisent le mode heightmap. La contrainte d'adjacence était essentielle : pour deux chunks voisins quelconques, nous imposons |LiLj|1. Le rapport de résolution le long d'une face est 2|LiLj|, et les tables de transition Transvoxel ne sont définies que pour le cas 2:1 (|LiLj|=1). Un écart de 2 niveaux nécessiterait une transition 4:1 que les tables ne peuvent pas représenter ; les règles forcent donc le chunk le moins détaillé à augmenter sa résolution jusqu'à ce que la contrainte soit respectée.

La logique de basculement HM/MC vérifiait le bitmap de modifications de chaque chunk. Si un chunk comportait la moindre modification volumétrique — grotte, tunnel ou sculpture du terrain —, il restait en mode MC quelle que soit sa distance. Les chunks non modifiés pouvaient passer en mode heightmap lorsqu'ils s'éloignaient suffisamment. Cette approche hybride nous offrait une liberté volumétrique là où elle comptait et de l'efficacité partout ailleurs.

Vu de l'extérieur, ce spike paraissait plus modeste que certains des précédents. En pratique, il a considérablement amélioré le confort de développement.

Lorsque votre système peut expliquer pourquoi un chunk a changé de mode, vous passez moins de temps à deviner. Nous avons ajouté des surcouches avec un code couleur : vert pour les chunks en heightmap, bleu pour les chunks en MC et orange pour les faces dont les transitions étaient actives. Lorsque la visibilité des raccords dispose de contrôles de rendu dédiés, l'ambiguïté du débogage visuel diminue. Et lorsque les plages de dessin sont explicitement liées au nombre de sommets actifs fourni par le système de règles, les fantômes de géométrie obsolète cessent de vous faire perdre tout un après-midi.

Nous avons également remanié le comportement de la caméra dans ce spike. Les spikes précédents utilisaient de simples contrôles orbitaux, adaptés aux captures d'écran mais inutiles pour reproduire les bugs. Le spike 23 a ajouté une caméra volante contrôlée avec WASD, dotée d'une vitesse configurable, d'un verrouillage optionnel de l'altitude et d'un affichage de la position. Cela peut sembler anodin. Pourtant, c'est ce qui fait la différence entre « J'ai vu un bug quelque part près de cette crête » et « Le bug apparaît à la position (142, 12, -67), en regardant vers le nord-ouest ».

L'idée essentielle de ce chapitre est que les règles n'ont pas réduit la complexité. Elles l'ont organisée. Le nombre de cas limites n'avait pas changé. Mais chacun d'eux avait désormais un nom, une condition de déclenchement et un emplacement dans le code où poser un point d'arrêt. C'est une autre forme de victoire, et c'est ce qui détermine si un système peut continuer à évoluer ou s'effondre sous son propre poids.

À la fin du spike 23, nous disposions d'une couche de comportement en champ proche suffisamment prévisible pour être reliée à une stratégie d'anneaux clipmap en champ lointain, sans craindre constamment des bugs d'interaction.

Dans la partie 12, nous abordons le spike 24, où les transitions entre anneaux, le brouillard de la skybox et l'intégration des shaders propre à la version de Three.js concluent ce chapitre du projet.

Technologies mentionnées dans ce chapitre

Règles de LOD fondées sur la distance. Une fonction centrale attribue à chaque chunk un niveau de LOD et un mode de rendu selon sa distance à la caméra, son historique de modifications et l'état de ses voisins. Des anneaux concentriques de distance déterminent le LOD de base : anneau 0 = MC à pleine résolution, anneau 1 = MC à demi-résolution, anneau 2 et au-delà = mode heightmap. La fonction de règles s'exécute à chaque frame pendant les déplacements de la caméra et déclenche les transitions des chunks. Elle remplace les décisions ponctuelles prises par chaque chunk par un système de règles prévisible et facile à déboguer. Consultez la section sur la sélection du LOD pilotée par le GPU pour découvrir l'équivalent en compute shader.

Contraintes d'adjacence. L'algorithme Transvoxel ne gère que les rapports de résolution 2:1. Si deux chunks voisins diffèrent de plus d'un niveau de LOD — par exemple, un LOD 0 à côté d'un LOD 2 —, les tables de transition ne peuvent pas produire une géométrie de raccord valide. Le système de règles impose cette contrainte en augmentant la résolution du chunk le moins détaillé lorsque l'écart de LOD dépasse 1. Cette propagation de contraintes peut se répercuter en cascade : augmenter la résolution d'un chunk peut obliger ses voisins à faire de même. L'implémentation repose sur une simple passe itérative qui converge en 2 à 3 itérations pour les configurations de grille habituelles.

Bitmap de modifications pour la sélection du mode. Chaque chunk conserve un bitmap indiquant s'il contient des modifications SDF volumétriques — grottes, tunnels ou sculptures. Les chunks comportant la moindre modification restent en mode marching cubes quelle que soit leur distance, afin de préserver les changements du créateur. Les chunks non modifiés passent en mode heightmap lorsqu'ils sont suffisamment éloignés de la caméra, ce qui économise des ressources de calcul et de la mémoire. Le bitmap se résume à un indicateur par chunk, mais peut être étendu pour suivre la densité des modifications et permettre des décisions de mode plus précises.

Surcouches de visualisation pour le débogage. Un rendu des chunks avec code couleur, où vert = mode heightmap, bleu = mode MC et orange = faces dont les transitions sont actives. Des surcouches propres à chaque chunk affichent le niveau de LOD et le libellé du mode, avec des options de rendu en fil de fer. Ce sont des outils de développement, pas des fonctionnalités livrées aux utilisateurs, mais ils sont rentabilisés à maintes reprises lors du débogage des transitions de LOD et des artefacts de raccord. Associés à une caméra volante contrôlée avec WASD qui indique la position exacte dans le monde, ils transforment « J'ai vu un bug quelque part » en « Le bug apparaît à la position (142, 12, -67) avec cette configuration de LOD ».


Partie 11 sur 12.
Précédente : Partie 10 — Le chaos des raccords et le boss final des coins
Suivante : Partie 12 — Anneaux, brouillard céleste et ce que nous referions
Guide de la série : /fr/blog/2026-02-25-open-world-browser-series-guide