URL:
https://linuxfr.org/news/les-graphes-de-scene
Title: Les graphes de scène
Authors: small_duck
Julien Jorge
Date: 2022-11-23T18:31:39+01:00
License: CC By-SA
Tags: graphisme et graphes
Score: 4
Deuxième partie de mon triptyque qui prend pour prétexte la sortie du graphe de scène VulkanSceneGraph pour parler un peu 3D. Dans le volet précédent, nous avons évoqué les bonds technologiques qui ont permis le rendu 3D raster, tel que nous le connaissons aujourd'hui, basé sur OpenGL et Vulkan. Aujourd'hui, parlons de [graphes de scènes](
https://fr.wikipedia.org/wiki/Graphe_de_sc%C3%A8ne).
Considérant qu'une scène, c'est la définition graphique d'un monde à représenter à l'écran, un graphe de scène, c'est une structure qui hiérarchise les différents éléments de la scène au sein d'un graphe, car cette représentation est particulièrement pertinente.
----
----
En pratique, il existe de nombreuses manières de construire un graphe de scène, qui seront adaptées à l'utilisation que l'on en fait. Le graphe de scène sous-jacent à [Blender](
https://fr.wikipedia.org/wiki/Blender) n'a par exemple rien à voir avec celui du dernier Call of Duty.
Un graphe de scène commence souvent par un nœud racine, sur lequel sont attachés une hiérarchie de nœuds pouvant représenter des transformations dans l'espace (translations, rotations...), des changements d'état (couleurs, shader courant...), de la géométrie (formes géométriques simples, amas de triangles) et autres types de nœuds plus exotiques, nous y reviendrons.
Rendre la scène à l'écran, c'est donc [traverser le graphe](
https://fr.wikipedia.org/wiki/Parcours_de_graphe) en profondeur, et appliquer à chaque visite de nœud la transformation à effectuer.

Par exemple, en visitant ce graphe, l'on va indiquer à l'API 3D d'effectuer les actions suivantes:
- Appliquer la matrice m1
- Mettre l'attribut couleur à rouge
- Afficher une sphère
- Enlever l'attribut couleur
- Appliquer la matrice m2
- Mettre l'attribut couleur à vert
- Afficher un cube
- Enlever l'attribut couleur
- Enlever la transformation m2
- Enlever la transformation m1
- Afficher un tore
Voyons maintenant plus en détail les avantages liés à l'utilisation du graphe de scènes
# Hiérarchiser la géométrie #
En structurant sa scène avec des nœuds de transformation auxquels sont ajoutés les géométries, il est bien plus aisé de gérer des transformations complexes d'objets liés les uns aux autres. Prenons par exemple un bras robotique: la position de la main dépend de la position du coude, qui elle même dépend de la position de l'épaule. Plutôt que d'appliquer une transformation complexe à la main qui prendrait en compte tous les paramètres du coude et de l'épaule, il est bien plus simple d'avoir une série de matrices de transformations d'un objet relatif à son parent: le coude est rattaché à l'épaule, et la main au coude. En contrôlant la rotation au niveau de l'épaule, les transformations vont s'appliquer en combinant chaque matrice et la main va suivre le mouvement.
# Élimination des géométries non visibles #
Vous connaissez peut-être l'aphorisme qui dit que le code le plus rapide est celui que l'on exécute pas. De la même manière, la géométrie la plus rapide est celle que l'on affiche pas, et il est donc très utile de déterminer très tôt quels sont les objets que l'on aura pas besoin d'afficher à l'écran. Les graphes de scène sont particulièrement utiles pour cela.
L'approche générale est, pour chaque nœud, de déterminer [un volume simple qui l'engloble](
https://fr.wikipedia.org/wiki/Volume_englobant) ainsi que tous ses enfants. On peut utiliser des sphères ou des boites alignés sur les axes, et on les calcule à l'avance. On visite ensuite le graphe : pour chaque nœud enfant de la racine, on calcule l'intersection du volume englobant du nœud avec le [frustum](
https://en.wikipedia.org/wiki/Viewing_frustum), la pyramide tronquée représentant ce que la caméra peut voir. Si le volume englobant est complètement à l'extérieur, le nœud (et par extension tous ses enfants) peut être éliminé. Si le volume englobant est complètement à l'intérieur du frustum, le nœud et tous ses enfants doivent être affichés. S'il est à cheval sur le frustum, alors on visite chaque enfant et on applique récursivement la même opération.
# Optimisation du rendu #
L'optimisation du rendu d'une scène peut certainement faire l'objet d'un livre entier, mais notons cependant qu'à chaque rendu, il est important de réduire au maximum le nombre d'appels vers la carte graphique. Ainsi, il est plus efficace de charger à l'avance les géométries dans les tampons de la carte graphique, et il est plus efficace de changer le moins possible les états comme la position des lumières, le shader courant, et ainsi de suite.
On peut donc analyser le graphe afin de le transformer pour combiner les nœuds qui peuvent l'être. Par exemple, plutôt que de sélectionner le shader approprié pour chaque géométrie, l'on peut grouper les géométries utilisant le même shader, et ne le sélectionner qu'une fois.

De même, si l'on permet au graphe d'être un graphe acyclique plutôt qu'un arbre, l'on peut atteindre le même nœud à travers des chemins différents, et donc représenter le même objet avec des transformations différentes (pensez à une forêt qui contient de nombreuses fois le même arbre) permettant par exemple d'économiser de la place dans les tampons de géométrie, voire de permettre certaines formes de cache.

# Et bien d'autres #
Mentionnons encore quelques opérations où un graphe de scène est bien utile.
- Gestion des niveaux de détail : un nœud [LOD](
https://fr.wikipedia.org/wiki/Level_of_detail) peut avoir une série d'enfants correspondant au même objet plus ou moins détaillé, et afficher l'objet approprié selon la distance à la caméra : inutile d'utiliser des milliers de polygones pour afficher un objet qui fait 2 pixels sur l'horizon !
- Le picking : à partir d'un point à l'écran, on peut appliquer les transformations inverses et trouver la liste d'objets situés sous le point, ce qui permet à l'utilisateur de sélectionner un objet
# Utilisation avancée des graphes de scènes #
Une scène d'un moteur graphique moderne est extraordinairement complexe et nécessite de nombreuses passes : souvent, le moteur va rendre une partie de la scène dans une texture en ayant appliqué des calques ou des shaders, et utiliser ensuite cette texture dans le rendu final, par exemple pour gérer les ombres ou encore les réflexions (pensez à un objet qui se reflète dans de l'eau, par exemple). Le rendu final lui-même est parfois rendu dans une texture avant d'être affiché à l'écran afin d'appliquer des shaders sur l'ensemble de l'écran, par exemple pour émuler une vue à travers des lunettes de vision nocturne, ou encore un affichage flou si le personnage est ivre. Par l'utilisation judicieuse de nœuds spécialisés, comme de nœuds caméra par exemple, ou carrément de nœuds d'effets qui gèrent les ombres automatiquement, il est possible de fournir au développeur une série d'outils de haut niveau, optimisés, et prêts à l'emploi. C'est exactement le but suivi par [OpenSceneGraph](
http://www.openscenegraph.com/), et c'est là dessus que nous finirons cette série.