Le premier jeu à utiliser de la "vraie" 3D fût le jeu Quake, premier du nom. Et depuis sa sortie, presque tous les jeux vidéos un tant soit peu crédibles utilisent de la 3D. Face à la prolifération de ces jeux vidéos en 3D, les fabricants de cartes graphiques se sont adaptés et ont inventé des cartes capables d'accélérer les calculs effectués pour rendre une scène en 3D : les cartes accélératrices 3D.
Pipeline graphique
Une scène 3D est composée d'un espace en trois dimensions, dans laquelle le moteur physique du jeu vidéo place des objets et les fait bouger. Cette scène est, en première approche, un simple parallélogramme. Un des coins de ce parallélogramme sert de système de coordonnées : il est à la position (0, 0, 0), et les axes partent de ce point en suivant les arêtes. Les objets seront placés à des coordonnées bien précises dans ce parallélogramme.
Dans notre scène 3D, on trouve un objet spécial : la caméra, qui représente les yeux du joueur. Cette caméra est définie par :
- une position ;
- par la direction du regard (un vecteur) ;
- le champ de vision (un angle) ;
- un plan qui représente l'écran du joueur ;
- et un plan au-delà duquel on ne voit plus les objets.
Ces autres objets sont composés de formes géométriques, combinées les unes aux autres pour former des objets complexes. Ces formes géométriques peuvent être des triangles, des carrés, des courbes de Béziers, etc. Dans la majorité des jeux vidéos actuels, nos objets sont modélisés par un assemblage de triangles collés les uns aux autres. Ces triangles sont définis par leurs sommets, qui sont appelés des vertices. Chaque vertice possède trois coordonnées, qui indiquent où se situe le sommet dans la scène 3D : abscisse, ordonnée, profondeur.
Pour rajouter de la couleur, ces objets sont recouverts par des textures, des images qui servent de papier peint à un objet. Un objet géométrique est recouvert par une ou plusieurs textures, qui permettent de le colorier ou de lui appliquer du relief.
Pipeline graphique
Depuis un bon moment, les jeux vidéos utilisent une technique de rendu spécifique : la rasterization. Celle-ci calcule une scène 3D intégralement, avant de faire des transformations pour n'afficher que ce qu'il faut à l'écran. Le calcul de l'image finale passe par diverses étapes bien séparées, le cas le plus simple ne demandant que trois étapes :
- une étape de traitement des vertices ;
- une étape de rasterization, qui va déterminer quelle partie de l'image 3D s'affiche à l'écran, et qui attribue chaque vertice à un pixel donné de l'écran ;
- une étape de texturing et de traitement des pixels.
Chacune de ces étapes est elle-même découpée en plusieurs sous-étapes. Toutes ces sous-étapes doivent s’exécuter dans un ordre bien précis. L'ensemble de ces étapes et sous-étapes forme ce qu'on appelle le pipeline graphique.
Traitement des vertices
La première étape de traitement de la géométrie consiste à placer les objets au bon endroit dans la scène 3D. Lors de la modélisation d'un objet, celui-ci est encastré dans un cube : un sommet du cube possède la coordonnée (0, 0, 0), et les vertices de l'objet sont définies à partir de celui-ci. Pour placer l'objet dans la scène, il faut tenir compte de sa localisation, calculée par le moteur physique : si le moteur physique a décrété que l'objet est à l'endroit de coordonnées (50, 250, 500), toutes les coordonnées des vertices de l'objet doivent être modifiées. Pendant cette étape, l'objet peut subir une translation, une rotation, ou un gonflement/dégonflement (on peut augmenter ou diminuer sa taille). C'est la première étape de calcul : l'étape de transformation.
Ensuite, les vertices sont éclairées dans une phase de lightning. Chaque vertice se voit attribuer une couleur, qui définit son niveau de luminosité : est-ce que la vertice est fortement éclairée ou est-elle dans l'ombre ?
Vient ensuite une phase de traitement de la géométrie, où les vertices sont assemblées en triangles, points, ou lignes, voire en polygones. Ces formes géométriques de base sont ensuite traitées telles quelles par la carte graphique. Sur les cartes graphiques récentes, cette étape peut être gérée par le programmeur : il peut programmer les divers traitements à effectuer lui-même.
Rasterization
Vient ensuite la traduction des formes (triangles) rendues dans une scène 3D en un affichage à l'écran. Cette étape de rasterization va projeter l'image visible sur notre caméra. Et cela nécessite de faire quelques calculs.
Tout d'abord, la scène 3D va devoir passer par une phase de clipping : les triangles qui ne sont pas visibles depuis la caméras sont oubliés.
Ensuite, ils passent par une phase de culling : les triangles qui, du point de vue de la caméra, sont situés derrière une surface géométrique, sont oubliés. Ceux-ci ne sont simplement pas visibles depuis la caméra, donc autant les virer.
Enfin, chaque pixel de l'écran se voit attribuer un ou plusieurs triangle(s). Cela signifie que sur le pixel en question, c'est le triangle attribué au pixel qui s'affichera. C'est lors de cette phase que la perspective est gérée, en fonction de la position de la caméra.
Pixels et textures
À la suite de cela, les textures sont appliquées sur la géométrie. La carte graphique sait à quel triangle correspond chaque pixel et peut donc colorier le pixel en question en fonction de la couleur de la texture appliquée sur la géométrie. C'est la phase de Texturing. Sur les cartes graphiques récentes, cette étape peut être gérée par le programmeur : il peut programmer les divers traitements à effectuer lui-même.
En plus de cela, les pixels de l'écran peuvent subir des traitements divers et variés avant d'être enregistrés et affichés à l'écran. Un effet de brouillard peut être ajouté, des tests de visibilité sont effectués, l'antialiasing est ajouté, etc.
Bilan
Dans certains cas, des traitements supplémentaires sont ajoutés. Par exemple, les cartes graphiques modernes supportent une étape en plus, qui permet de rajouter de la géométrie : l'étape de tesselation. Cela permet de déformer les objets ou d'augmenter leur réalisme.
Architecture d'une carte 3D
Avant l'invention des cartes graphiques, toutes ces étapes étaient réalisées par le processeur : il calculait l'image à afficher, et l’envoyait à une carte d'affichage 2D. Les toute premières cartes graphiques contenaient des circuits pour accélérer une partie des étapes vues au-dessus. Au fil du temps, de nombreux circuits furent ajoutés, afin de déporter un maximum de calculs du CPU vers la carte graphique.
Architecture de base
Néanmoins, toute carte graphique contient obligatoirement certains circuits :
- la mémoire vidéo ;
- les circuits de communication avec le bus ;
- le command buffer.
La carte graphique a besoin d'une mémoire RAM : la mémoire vidéo. Cette mémoire vidéo, est très proche des mémoires RAM qu'on trouve sous forme de barrettes dans nos PC, à quelques différences près : la mémoire vidéo peut supporter un grand nombre d'accès mémoire simultanés, et elle est optimisée pour accéder à des données proches en mémoire. Dans le cas le plus simple, elle sert simplement de Framebuffer : elle stocke l'image à afficher à l'écran. Au fil du temps, elle s'est vu ajouter d'autres fonctions : stocker les textures et les vertices de l'image à calculer, ainsi que divers résultats temporaires.
La carte graphique communique via un bus, un vulgaire tas de fils qui connectent la carte graphique à la carte mère. Les premières cartes graphiques utilisaient un bus nommé ISA, qui fût rapidement remplacé par le bus PCI, plus rapide. Viennent ensuite le bus AGP, puis le bus PCI-Express.
Ce bus est géré par un contrôleur de bus, un circuit qui se charge d'envoyer ou de réceptionner les données sur le bus. Il contient quelques registres dans lesquels le processeur pourra écrire ou lire, afin de lui envoyer des ordres du style : j'envoie une donnée, transmission terminée, je ne suis pas prêt à recevoir les données que tu veux m'envoyer, etc.
Les anciennes cartes graphique pouvaient lire ou écrire directement dans la mémoire RAM, grâce à certaines fonctionnalités du bus AGP. Mais généralement, les données sont copiées depuis la mémoire RAM vers la mémoire vidéo, en passant par le bus. Cette copie est effectuée par un circuit spécialisé : le contrôleur DMA, qui permet d'échanger des données entre mémoire vidéo et mémoire RAM sans devoir utiliser le processeur. Il est souvent intégré dans le contrôleur de bus.
Tout les traitements que la carte graphique doit effectuer sont envoyés par un programme, le pilote de la carte graphique, sous la forme de commandes. Ces commandes sont des ordres, que la carte graphique doit exécuter. Elles sont stockées temporairement dans une zone de mémoire, le command buffer, avant d'être interprétées par un circuit spécialisé : le command processor. Celui-ci est chargé de piloter les circuits de la carte graphique.
Première génération
Les toutes premières cartes graphiques contenaient simplement des circuits pour gérer les textures, ainsi qu'un framebuffer. Seules l'étape de texturing, quelques effets graphiques (brouillard) et l'étape d'enregistrement des pixels en mémoire étaient prises en charge par la carte graphique.
Par la suite, ces cartes s’améliorèrent en ajoutant plusieurs circuits de gestion des textures, pour colorier plusieurs pixels à la fois. Cela permettait aussi d'utiliser plusieurs textures pour colorier un seul pixel : c'est ce qu'on appelle du multitexturing. Les cartes graphiques construites sur cette architecture sont très anciennes. On parle des cartes graphiques ATI rage, 3DFX Voodoo, Nvidia TNT, etc.
Les cartes suivantes ajoutèrent une gestion des étapes de rasterization directement en matériel. Les cartes ATI rage 2, les Invention de chez Rendition, et d'autres cartes graphiques supportaient ces étapes en hardware. De nos jours, ce genre d'architecture est commune chez certaines cartes graphiques intégrées dans les processeurs ou les cartes mères.
Seconde génération
La première carte graphique capable de gérer la géométrie fût la Geforce 256, la toute première Geforce. Elle dispose :
- d'un circuit pour manipuler les vertices et la géométrie ;
- d'un circuit pour appliquer des textures ;
- d'un circuit pour effectuer la rasterization, le clipping et le culling ;
- d'un circuit pour les opérations finales, comme le brouillard, la gestion de la transparence, de la profondeur, etc : le raster operation pipeline, ou ROP.
Les données circulent d'un circuit à l'autre dans un ordre bien précis. Cela permet d’enchaîner les sous-étapes de traitement du pipeline graphique dans l'ordre voulu. Entre ces différentes unités, on trouve souvent des mémoires pour mettre en attente les vertices ou les pixels, au cas où une unité est trop occupée : les unités précédentes peuvent continuer à faire leurs calculs et accumulent leurs résultats dans ces mémoires tampons, résultats utilisables quand l'unité sera libre.
Nous verrons ces circuits en détail dans la suite du tutoriel. Dans les grandes lignes, une carte graphique ressemble à ceci :
Pour plus d'efficacité, ces cartes graphiques possédaient parfois plusieurs unités de traitement des vertices et des pixels, ou plusieurs ROP. Dans ce cas, ces unités multiples sont précédées par un circuit qui se charge de répartir les vertex ou pixels sur chaque unités. Généralement, ces unités sont alimentées en vertex/pixels les unes après les autres (principe du round-robin).
Troisième génération
Enfin, les circuits qui gèrent les calculs sur les pixels et sur les vertices sont devenus des processeurs programmables. Au tout début, seuls les traitements sur les vertices étaient programmables. C'était le cas sur les NVIDIA's GeForce 3, GeForce4 Ti, Microsoft's Xbox, et les ATI's Radeon 8500. Puis, les cartes suivantes ont permis de programmer les traitements sur les pixels : certains processeurs s'occupaient des vertices, et d'autres des pixels. Mais sur les cartes graphiques récentes, les processeurs peuvent traiter indifféremment pixels et vertices.
Pour l'avenir, on suppose que certains autres circuits deviendront programmables. Les circuits chargés de la rasterization, ainsi que les ROP sont de bons candidats. Par contre, les circuits de textures ne changeront pas avant un moment.