HardWare.fr


Comprendre le rendu 3D étape par étape avec 3DMark11
Cartes Graphiques
Publié le Lundi 28 Novembre 2011 par Damien Triolet

URL: /articles/845-1/comprendre-rendu-3d-etape-par-etape-avec-3dmark11.html


Page 1 - Introduction


Un dessin vaut parfois mieux qu'un long discours… Un adage en général difficile à suivre lorsqu'il s'agit de représenter le rendu 3D en temps réel des jeux vidéo modernes, tant il est devenu complexe. S'il est relativement aisé d'illustrer la plupart des effets graphiques par des cas particuliers qui les mettent en avant, les représenter en tant qu'étapes dans un rendu complet l'est beaucoup moins. C'est pourtant cette mise en scène qui permet de comprendre comment est construite une image dans les jeux récents.

Si nous ne vous épargnerons pas quelques chiffres et autres détails techniques dans ce dossier, nous sommes par contre tombés sur un exemple idéal qui nous permet d'illustrer en pratique le rendu 3D et ainsi de le démystifier quelque peu.

3DMark 11
Dès la sortie de 3DMark 11, il y a près d'un an, nous nous sommes plongés dans ses entrailles afin d'observer s'il représente bien une utilisation intéressante de DirectX 11, utile pour juger des capacités des GPUs actuels dans les jeux à venir. Cela a pris du temps, compte tenu des milliers de commandes de rendu à observer ainsi que des bugs et autres limitations dont souffrent les outils d'analyse proposés par AMD et Nvidia, ce qui nous a poussés à mettre en pause ce dossier à plusieurs reprises.

Si ces observations nous permettent de formuler plusieurs critiques par rapport à l'utilisation faite par 3DMark 11 des nouveautés de DirectX11, nous y viendront dans un prochain dossier, elles ont également mis en avant une rare opportunité de vous aider à comprendre, à travers des visuels clairs, les différentes étapes nécessaires à la construction d'un rendu 3D temps-réel moderne tel qu'utilisé dans les jeux vidéo récents : le rendu différé. Il consiste à préparer au préalable tous les ingrédients nécessaires à la construction de l'image, à les stocker dans des mémoires tampons intermédiaires et à les combiner pour calculer l'éclairage seulement une fois que toute la scène a été passée en revue, de manière à éviter le calcul des pixels cachés.

S'ils font leur travail correctement, les développeurs s'efforcent d'optimiser les moindres détails du rendu 3D pour lequel ils ont opté, ce qui a pour conséquence, au niveau auquel nous pouvons l'observer, de rendre floues voire de faire disparaître complètement la séparation entre les différentes étapes qui le composent. Pour Futuremark, qui met au point 3DMark 11, la donne est différente puisque l'objectif est de comparer les performances de différentes cartes graphiques avec des techniques de rendu modernes, d'une manière aussi objective que possible, et non de chercher à mettre en place un maximum de petites optimisations. C'est ce qui nous permet de prendre des "clichés" de la construction de l'image.


Nous y avons ajouté quelques chiffres qui permettent de prendre la mesure de la complexité des rendus modernes, ainsi que quelques explications sur les techniques utilisées. Afin que les visuels puissent permettre à un plus grand nombre de comprendre comment fonctionne la 3D, nous avons d'une part déporté les explications plus détaillées dans des encadrés, et d'autre part intégré un récapitulatif des différentes étapes dans la dernière page de ce dossier. Il permettra à celui pour qui "normal map" ou "R11G11B10_FLOAT" représentent des gros mots de visualiser simplement et rapidement comment se construit une image 3D.


Page 2 - Le rendu différé, nos observations

Le rendu différé
Avant de rentrer dans le vif du sujet, il convient de décrire le type de rendu observé. 3DMark 11 et de plus en plus de jeux à l'aspect graphique évolué, font appel au rendu différé, Battlefield 3 en étant probablement l'évolution la plus avancée. Un rendu classique, ou rendu direct, consiste à calculer l'éclairage triangle par triangle, au fur et à mesure que les objets sont traités. Etant donné que certains triangles ou des morceaux de ceux-ci vont finalement être masqués par d'autres, l'éclairage est calculé inutilement pour de nombreux pixels. Un gaspillage de puissance de calcul qui peut être très important.

Le rendu différé s'attaque à ce problème. Pour cela, seules des composantes basiques (ce qui inclut les textures), nécessaires à l'éclairage, sont calculées dans un premier temps, lors du passage en revue de tous les objets de la scène. Toutes ces données sont stockées dans des mémoires tampons temporaires appelées Render Targets (RT) (dont l'ensemble se nomme g-buffer) et combinées ultérieurement pour le calcul final de l'éclairage, qui peut alors être vu comme un filtre de post-traitement et ne sera effectué qu'une seule fois par pixel affiché à l'écran. Une partie de la puissance de calcul nécessaire est ainsi économisée et il est plus simple de gérer des éclairages complexes avec de nombreuses sources de lumière.


En contrepartie, la consommation mémoire peut augmenter et la bande passante nécessaire au stockage de toutes les données intermédiaires peut engorger le GPU lors des premières étapes de rendu. Les désavantages incluent également une difficulté pour gérer l'antialiasing de type multi-sample et les surfaces transparentes. Futuremark a mis en place une solution pour la première mais a décidé de se simplifier la vie en ignorant la seconde : vous ne trouverez ainsi pas de pare-brise sur le 4x4 aperçu dans certaines scènes.

Nos observations
Pour expliquer le fonctionnement du rendu 3D, nous avons opté pour la scène 3 proposée par 3DMark 11, en mode Extreme, soit en 1920x1080 avec antialiasing 4x. Une scène qui a l'avantage d'être moins sombre que les autres.

Nous avons segmenté le rendu en étapes qui correspondent grossièrement aux passes qui structurent un rendu 3D. Si les GPUs modernes sont capables de faire énormément de choses en une seule passe, soit avant d'écrire un résultat en mémoire, il est plus simple, plus efficace et parfois obligatoire d'avoir recours à plusieurs passes de rendu. Il s'agit d'ailleurs d'un aspect fondamental lié au rendu différé et aux effets de post processing.

Pour chaque étape nous avons extrait des visuels qui la représentent aussi clairement que possible. Etant donné que certains Render Targets sont au format HDR, non-directement affichable, nous avons dû les modifier légèrement pour qu'ils soient plus représentatifs.

Enfin, pour les amateurs de détails, nous avons ajouté des explications plus techniques ainsi qu'un certain nombre d'informations liées à chaque passe, chiffres que nous avons obtenus dans GPU Perf Studio :

Temps de rendu :le temps (en ms) mis par le GPU de la Radeon HD 6970 pour traiter la totalité de la passe, avec une petite surévaluation liée aux outils de mesures (+ % du temps total pour le rendu de l'image).

Vertices avant tessellation : nombre de vertices qui rentrent dans le GPU, ce qui exclu les triangles générés par la tessellation.

Vertices après tessellation : nombre de vertices qui sortent de la tessellation, ce qui inclus les triangles générés par la tessellation.

Primitives : nombre de primitives (triangles, lignes ou points) qui rentrent dans le setup engine.

Primitives éjectées du rendu : nombre de primitives éjectées du rendu par le setup engine, soit parce qu'elles tournent le dos à la caméra et ne sont donc pas visible (face cachée des objets), soit parce qu'elles sont hors du champ de vision.

Pixels : nombre de pixels générés par le rasterizer (2.1 millions de pixel pour une surface de 1920x1080).

Eléments exportés par les PS : nombre d'éléments écrits en mémoire par les pixels shaders, il peut y en avoir plusieurs par pixel généré par le rasterizer, c'est le cas lors de la construction du g-buffer.

Texels : nombre de texels (éléments de texture) lus par les unités de texturing, plus le filtrage est complexe, plus il y en a.

Instructions exécutées : nombre d'instructions exécutées par une Radeon HD 6970 pour le traitement de l'ensemble des shaders, quels qu'ils soient.

Quantité de données lues : quantité totale des données lues à partir des textures et des RTs en cas de mélange (à l'exception des données de profondeur et géométriques).

Quantité de données écrites : quantité totale des données écrites dans les RTs (à l'exception des données de profondeur)

Notez que ces quantités de données sont différentes de celles qui transitent vers la mémoire vidéo puisque les GPUs intègrent de nombreuses optimisations qui s'attachent à réduire leur volume.


Page 3 - Etape 1 : la remise à zéro des mémoires tampons

Etape 1 : la remise à zéro des mémoires tampons
La première étape de tout rendu 3D est la moins intéressante et consiste à effacer les zones tampons de la mémoire, appelées Render Targets (RT) dans lesquelles le GPU écrit les données, sans quoi celles qui ont défini l'image précédente vont corrompre la nouvelle image à calculer.

Des RT peuvent dans certains types de rendu être partagés par plusieurs images successives, par exemple pour y accumuler des informations. Dans ce cas ils ne seraient bien entendu pas effacés. 3DMark 11 ne partage cependant aucunes données entre images successives, ce qui est nécessaire pour une efficacité maximale du multi-GPU.


Grossièrement, effacer tous ces buffers revient à remettre à 0 toutes les valeurs qu'ils contiennent, ce qui correspond à une image noire. Les GPU récents effectuent cet effacement très rapidement, suivant la taille des mémoires tampons à traiter.

Lors de l'initialisation du rendu, 3DMark 11 efface 7 RT très rapidement : 0.1ms soit 0.1% du temps de rendu. Plus tard 5 très gros RT dédiés aux ombres devront également être effacés, ce qui portera le temps total passé à cette tâche ingrate à 1.4ms soit 1.1% du temps de rendu global.


Page 4 - Etape 2 : le remplissage du g-buffer

Etape 2 : le remplissage du g-buffer
Après avoir préparé les RT, le moteur initie une première passe géométrique : le remplissage du g-buffer. Lors de cette étape, relativement lourde, l'ensemble des objets qui composent la scène sont passés en revue et traités pour remplir le g-buffer. Cela inclut la tessellation ainsi que l'application des différentes textures.


Les objets peuvent être présentés au GPU sous différents formats.

3DMark 11 fait une utilisation de l'instancing aussi souvent que possible, un mode qui permet d'envoyer une série d'objets identiques (par exemples toutes les feuilles, toutes les têtes qui décorent les colonnes, etc.) lors d'une seule commande de rendu (draw call). Limiter leur nombre permet de réduire la consommation CPU. Il y en a 91 en tout dans cette passe principale de rendu, dont 42 font appel à la tessellation. En voici quelques exemples :


Commandes de rendu : [ 1 ][ 6 ][ 24 ][ 35 ][ 86 ]


Le g-buffer est constitué de 4 RT en 1920x1080 avec antialiasing de type multisample (MSAA) 4x. Notez que si vous êtes attentifs vous pourrez observer un petit bug de rendu :


[ Le tampon Z ]
[ Les normales ]
[ Les couleurs diffuses ]
[ Les couleurs spéculaires ]

Le Depth Buffer, ou tampon Z, est au format D32 (32 bits). Il continent l'information de profondeur de chaque élément par rapport à la caméra, plus l'objet est foncé, plus il est proche.

Les normales (= perpendiculaires à chaque point) sont au format R10G10B10A2_UNORM (32 bits, 10 bits entier par composante). Elles vont notamment permettre d'ajouter des détails aux objets via une technique de bump mapping évoluée.

Les composantes diffuses de la couleur des pixels sont au format R8G8B8A8_UNORM (32 bits classique, 8 bits entier par composante), elles représentent un éclairage uniforme, qui prend en compte l'inclinaison avec laquelle la lumière atteint l'objet, mais ignore la direction du rayon réfléchi.

Les composantes spéculaires de la couleur des pixels sont au format R8G8B8A8_UNORM (32 bits classique, 8 bits entier par composante), elles prennent cette fois en compte la direction du rayon réfléchi, ce qui permet de donner un aspect brillant aux objets et d'intégrer le léger reflet de la lumière sur les bords.

La dernière des commandes de rendu met en place le ciel, représenté par une demi-sphère qui englobe la scène. Etant donné que le ciel n'est pas un élément éclairé comme les autres, mais bien une surface lumineuse, il est rendu d'une manière directe et non différée, ce qui inaugure la construction de l'image finale :


Quelques chiffres :

Temps de rendu : 18.2 ms (14.5 %)
Vertices avant tessellation : 0.91 million
Vertices après tessellation : 1.95 millions
Primitives : 1.90 millions
Primitives éjectées du rendu : 1.02 million
Pixels : 8.96 millions
Eléments exportés par les PS : 30.00 millions
Texels : 861.31 millions
Instructions exécutées : 609.53 millions
Quantité de données lues : 130.2 Mo
Quantité de données écrites : 158.9 Mo


Page 5 - Etape 3 : l'occlusion ambiante

Etape 3 : l'occlusion ambiante
L'éclairage de 3DMark 11 s'attache à essayer de se rapprocher du principe de l'illumination globale (radiosité, ray-tracing...), très lourd mais qui prend en compte d'une manière naturelle les réfractions et les réflexions et donc l'illumination indirecte : la part de lumière renvoyée par tous les objets de la scène. Pour imiter ce type de rendu, Futuremark fait appel à plusieurs artifices :
- Une source de lumière directionnelle en provenance du sol et de nombreuses sources de lumière ponctuelles pour simuler la lumière issue de soleil mais transmise indirectement par le sol et les objets environnants. Nous en parlerons dans les passes d'éclairage.

- Une texture d'occlusion ambiante qui simule les ombres douces générées par le déficit d'éclairage indirect, ce qui ne peut pas être représenté par le premier artifice, pas assez précis. Voici à quoi elle ressemble :


L'occlusion ambiante, enregistrée dans un RT au format R8_UNORM (8 bits entier) est calculée à partir du Depth Buffer et des normales de manière à prendre en compte tous les détails géométriques, mêmes ceux simulés à partir du bump mapping comme le fait le HDAO proposé par AMD et utilisé dans plusieurs jeux. Avec le preset Extreme ce sont 5x6 samples sélectionnés avec une composante aléatoire qui seront utilisés pour déterminer l'occlusion ambiante. Vous pourrez retrouver plus de détails à ce sujet dans le dossier que nous avions consacré à l'occlusion ambiante.
Quelques chiffres :

Temps de rendu : 2.3 ms (1.8 %)
Vertices avant tessellation : 6
Vertices après tessellation : -
Primitives : 2
Primitives éjectées du rendu : 0
Pixels : 2.59 millions
Eléments exportés par les PS : 2.59 millions
Texels : 78.80 millions
Instructions exécutées : 626.23 millions
Quantité de données lues : 73.3 Mo
Quantité de données écrites : 3.0 Mo


Page 6 - Etape 4 : l'antialiasing

Etape 4 : la gestion de l'antialiasing
Le rendu différé n'étant pas directement compatible avec l'antialiasing classique de type MSAA, notamment parce que l'éclairage n'est pas calculé lors du traitement de la géométrie, Futuremark a dû mettre en place une technique particulière. Elle consiste en la création d'une carte des arrêtes qui sera utilisée lors du calcul de l'éclairage pour les filtrer, tout comme l'aurait fait le MSAA :


Jusqu'ici, tous les RT ont été rendus avec antialiasing 4x de type MSAA, Futuremark ayant préféré ne pas faire appel à un antialiasing de type post processing tels que les FXAA et MLAA proposés aux développeurs de jeux vidéo par Nvidia et AMD.

Le MSAA n'est cependant pas nativement compatible avec le rendu différé qui est conçu pour ne calculer l'éclairage qu'une seule fois par pixel et ignore ainsi les samples qui le composent. Une méthode brute pourrait être, à partir de ce moment, de passer dans un mode similaire au super sampling, ce qui est facilité par DirectX 10.1 et 11. Cela reviendrait cependant à calculer l'éclairage en 3840x2160, gaspillerait beaucoup de ressources et irait à l'encontre du sens même du rendu différé.

Futuremark a opté pour une autre approche, hybride entre le MSAA et le post processing. Elle consiste comme pour ce dernier à exploiter un algorithme capable, à partir des données du g-buffer, de détecter les arrêtes qui devront être lissées. Sans être parfait, il serait alors trop gourmand, cet algorithme fait un plutôt bon travail pour détecter uniquement les arrêtes extérieures aux objets, le filtrage des arrêtes internes n'étant pas utile.

Ce RT, au format R8_UNORM (8 bits entier), qui contient les arrêtes détectées sera utilisé lors de toutes les passes d'éclairage à venir pour leur indiquer les pixels complexes, qui doivent recevoir une attention particulière. Un branchement dynamique dans les pixels shaders permettra de calculer directement la valeur du mélange des 4 samples, comme cela aurait été le cas lors d'une utilisation classique du MSAA.

Parallèlement à cela, le RT dans lequel est construit l'image et qui jusqu'ici ne contient que le ciel, ainsi que le Depth Buffer, au départ au format MSAA 4x, peuvent être directement filtrés puisque les informations supplémentaires qu'ils contiennent ne seront plus utiles par la suite. Les RTs qui contiennent les composantes diffuses et spéculaires de la couleur des pixels doivent cependant être conservés au format MSAA 4x, puisque les samples supplémentaires qu'ils contiennent seront nécessaires pour calculer les pixels complexes.

Quelques chiffres :

Temps de rendu : 1.4 ms (1.1 %)
Vertices avant tessellation : 3
Vertices après tessellation : -
Primitives : 1
Primitives éjectées du rendu : 0
Pixels : 2.07 millions
Eléments exportés par les PS : 6.22 millions
Texels : 39.43 millions
Instructions exécutées : 185.44 millions
Quantité de données lues : 182.3 Mo
Quantité de données écrites : 9.9 Mo


Page 7 - Etape 5 : les ombres

Etape 5 : les ombres
3DMark 11 peut générer des ombres liées aux sources de lumière directionnelles (le soleil ou la lune) et de type spot (non présentes dans le test 3). Dans les deux cas il s'agit de la technique du shadow mapping qui consiste à projeter l'ensemble des objets de la scène du point de vue de la source lumière et d'en retenir uniquement un tampon Z qui porte alors le nom de shadow map. Contrairement à ce que son nom pourrait laisser penser, il ne s'agit pas d'une texture d'ombre qui serait appliquée sur l'image.

Une shadow map indique pour chacun de ses points la distance par rapport à la source de lumière à partir de laquelle les objets se trouvent dans l'ombre. Il suffira par la suite de croiser la position du pixel avec les informations contenues dans les shadow maps pour savoir s'il doit être éclairé ou s'il se trouve dans l'ombre.

Pour les sources de lumière directionnelles, 3DMark 11 utilise une petite variante : les shadow maps en cascade (CSM). Etant donné la surface immense éclairée par le soleil, il est difficile, même en très haute résolution (4096x4096) d'obtenir une précision suffisante pour les ombres, qui risquent de pixéliser. Les CSM évitent cela en utilisant plusieurs niveaux de shadows maps qui se focalisent progressivement sur une plus petite zone située à l'avant plan dans le champ de vision, de manière à y conserver une qualité optimale.

3DMark 11 en mode Extreme crée 5 shadow maps d'une taille de 4096x4096 qui sont générées à travers 339 commandes de rendu dont 142 font appel à la tessellation, ce qui représente l'une des charges les plus lourdes de la scène. Plus un objet est foncé, plus il est proche de la source de lumière :


La scène vue depuis le soleil : [ CSM 1 ][ CSM 2 ][ CSM 3 ][ CSM 4 ][ CSM 5 ]


Bien qu'il soit possible de calculer au préalable toutes ces shadow maps et seulement ensuite l'éclairage, Futuremark a décidé d'entrelacer les deux, ce qui rend probablement le calcul de l'éclairage un petit peu moins efficace mais permet d'éviter de faire exploser l'espace mémoire nécessaire. A un moment donné il n'y a ainsi jamais qu'une seule shadow map en mémoire, c'est la raison pour laquelle 3DMark 11 se satisfait plutôt bien des cartes graphiques équipées de seulement 768 Mo, voire 512 Mo.

Tout comme pour la création du g-buffer, il s'agit ici de passes géométriques étant donné que l'ensemble de la scène doit être projetée, ou tout du moins un subset de celle-ci pour les CSMs de niveaux inférieurs. La tessellation est également de la partie puisqu'il faut que les ombres correspondent aux objets qui les projettent, ce qui peut représenter une charge énorme. Par contre, contrairement à la passe de création du g-buffer, aucune donnée de couleur n'est calculée, seule la profondeur est utile. Depuis Doom 3 et les GeForce FX, les GPUs sont capables d'augmenter fortement leur débit dans ce mode de rendu simplifié.

Notez une exception : les objets tels que le végétation, générés à partir de fausse géométrie, soit d'alpha tests, sortent de ce mode rapide puisque des pixels doivent alors être générés pour pouvoir les placer dans la scène.

Quelques chiffres :

Temps de rendu : 22.6 ms (17.9 %)
Vertices avant tessellation : 3.35 millions
Vertices après tessellation : 8.91 millions
Primitives : 8.50 millions
Primitives éjectées du rendu : 5.17 millions
Pixels : 83.67 millions
Eléments exportés par les PS : 24.03 millions
Texels : 416.66 millions
Instructions exécutées : 725.13 millions
Quantité de données lues : 50.5 Mo
Quantité de données écrites : 0.0 Mo (les données de profondeur ne sont pas prises en compte)


Page 8 - Etape 6 : les sources de lumière principales

Etape 6 : les sources de lumière principales
Après avoir préparé les données nécessaires à la création des ombres, 3DMark 11 s'attaque au rendu des sources de lumières principales, qui vont les prendre en compte. Ces sources de lumières peuvent être de type directionnel (soleil, lune…) ou spot. Il n'y a pas de spot dans la scène observée ici, mais bien un soleil. Pour couvrir les ombres qu'il génère sur l'ensemble de la scène, 5 shadow maps en cascade sont nécessaires. Pour ne pas qu'elles monopolisent trop de mémoire vidéo, leur calcul et le rendu de l'éclairage dans la zone du champ de vision qu'elles couvrent est entrelacé.

Cela implique que 3DMark 11 a besoin de 5 passes pour calculer l'éclairage directionnel qui simule celui du soleil (LD2a/b/c/d/e). Une passe supplémentaire est utilisée pour simuler l'illumination globale et plus particulièrement la lumière du soleil réfléchie par le sol, ce dernier devenant ainsi lui-même une source de lumière directionnelle de faible intensité (LD1). La lumière s'accumule ainsi petit à petit dans l'image en préparation :


[ Ciel ] + [ LD 1 ] + [ LD2a ] + [ LD2b ] + [ LD2c ] + [ LD2d ] + [ LD2e ]

Cette image en préparation, au format R11G11B10_FLOAT (HDR rapide en 32 bits) représente l'éclairage de surface dont le modèle est une combinaison de réflectance diffuse Oren-Nayar et de réflectance spéculaire Cook-Torrance sans oublier une atténuation atmosphérique de type Rayleigh-Mie. En plus des shadow maps, il prend en compte l'occlusion ambiante qui a été calculée précédemment.

Parallèlement à l'éclairage de surface, un éclairage volumétrique est calculé, voir la page dédiée pour plus de détails. Son coût en terme de performances est cependant intégré dans les chiffres donnés ci-dessous puisqu'il est traité dans le même pixel shader que l'éclairage de surface.

Quelques chiffres :

Temps de rendu : 24.7 ms (19.6 %)
Vertices avant tessellation : 18
Vertices après tessellation : -
Primitives : 6
Primitives éjectées du rendu : 0
Pixels : 8.13 millions
Eléments exportés par les PS : 14.18 millions
Texels : 390.91 millions
Instructions exécutées : 2567.59 millions
Quantité de données lues : 1979.2 Mo
Quantité de données écrites : 54.6 Mo


Page 9 - Etape 7 : les sources de lumière secondaires

Etape 7 : les sources de lumière secondaires
Pour simuler une illumination globale, 3DMark 11 fait appel à de nombreuses sources de lumières secondaires de type ponctuelles. Elles représentent un point qui envoie de la lumière dans toutes les directions. Dans l'utilisation qui en est faite par 3DMark 11, il s'agit de sources de lumière de remplissage (fill lights), qui vont "remplir" l'espace de lumière et font ainsi partie des artifices destinés à simuler une illumination globale. Plus précisément, chacune de ces sources de lumière va éclairer légèrement tout ce qui se trouve dans la zone qu'elle couvre, définie par un cube :



Pas moins de 84 de ces sources de lumières ponctuelles sont rendues dans notre scène de test :


[ Source de lumière directionnelles ] + [ Sources de lumière de remplissage ]

Les sources de lumière ponctuelles ne génèrent pas d'ombre, l'occlusion ambiante les simulant à moindre coût. Elles sont traitées en 2 passes par 3DMark 11 pour prendre en compte le cas particulier de celles dont leur volume d'influence coupe le plan de la caméra.

Parallèlement à l'éclairage de surface complet, un éclairage volumétrique peut être calculé, mais ce n'est pas le cas dans notre scène de test.

Compte tenu du nombre de sources de lumière ponctuelles, elles représentent une large part du temps de rendu.

Quelques chiffres :

Temps de rendu : 33.7 ms (26.8 %)
Vertices avant tessellation : 688
Vertices après tessellation : -
Primitives : 1008
Primitives éjectées du rendu : 853
Pixels : 45.87 millions
Eléments exportés par les PS : 45.87 millions
Texels : 369.86 millions
Instructions exécutées : 9073.06 millions
Quantité de données lues : 1494.2 Mo
Quantité de données écrites : 177.6 Mo


Page 10 - Etape 8 : l'éclairage volumétrique

Etape 8 : l'éclairage volumétrique
3DMark 11 fait appel à un éclairage volumétrique pour simuler les rayons de soleils qui traversent l'atmosphère ou l'eau dans le cas des scènes sous-marines. Une approximation qui fait appel à une technique de lancé de rayons et qui est générée progressivement lors des passes d'éclairage précédentes qui représentent pour rappel le sol (LD1) et le soleil (LD2a/b/c/d/e) :


[ LD1 ] + [ LD2a ] + [ LD2b ] + [ LD2c ] + [ LD2d ] + [ LD2e ]


La dernière passe d'éclairage se contente ainsi d'intégrer cette composante volumétrique dans l'image finale, toujours en construction :


[ Sans éclairage volumétrique ]  [ Avec éclairage volumétrique ]

L'éclairage volumétrique est obtenu par une approximation pour chaque pixel de la lumière dispersée par l'atmosphère (ou l'eau) entre l'objet et la surface observée et la caméra. Un rayon est lancé par pixel et par source de lumière avec un échantillonnage effectué à plusieurs niveaux de profondeurs.

Notez que si la densité optique est fixe dans le cas de l'atmosphère, elle est précalculée dans des textures array 2D pour chaque image dans le cas de l'eau (ainsi que la transmittance accumulée qui en découle). Une étape qui a alors lieu au tout début du rendu, mais qui n'est pas nécessaire dans la scène que nous observons.

Quelques chiffres :

Temps de rendu : 0.7 ms (0.6 %)
Vertices avant tessellation : 3
Vertices après tessellation : -
Primitives : 1
Primitives éjectées du rendu : 0
Pixels : 2.07 millions
Eléments exportés par les PS : 2.07 millions
Texels : 33.18 millions
Instructions exécutées : 232.24 millions
Quantité de données lues : 15.9 Mo
Quantité de données écrites : 7.9 Mo


Page 11 - Etape 9 : l'effet de profondeur de champ

Etape 9 : l'effet de profondeur de champ
Pour l'effet de profondeur de champ, ou Depth of Field (DoF), 3DMark ne se contente pas d'un "simple" filtre de post-traitement, mais utilise une technique plus complexe, similaire au "Sprite-based Bokeh Depth of Field" rencontré dans Crysis 2. Grossièrement, cette technique consiste à étendre chaque pixel qui ne se trouve pas dans la zone nette de l'image grâce aux geometry shaders introduis par DirectX 10, dans des proportions qui dépendent de son niveau de flou. Voici ce que cela donne sur une portion de l'image (cliquez sur les liens pour obtenir l'image complète) :


[ Sans DoF ]  [ Avec DoF ]

Ce type d'effet de profondeur de champ consiste à générer, via les geometry shaders, un sprite (2 triangles qui font face à la caméra) pour chaque pixel qui ne doit pas rester net. La taille de ce sprite dépend du cercle de confusion, calculé au préalable dans un flottant de 16 bits, et un bokeh hexagonal y est plaqué pour simuler un diaphragme à 6 lames.

Cette opération est réalisée dans un format HDR 64 bits, R16G16B16A16_FLOAT, en pleine résolution, mais également dans une résolution divisée par 2 et par 4. Chaque pixel à traiter est dirigé vers l'une de ces résolutions suivant la taille de son cercle de confusion et elles sont ensuite combinées entre elles pour finaliser l'effet de profondeur de champ qui peut alors être ajouté dans l'image finale.


Plus un pixel est foncé, plus son cercle de confusion est petit. Les pixels blancs représentent ici les pixels dont le cercle de confusion dépasse la valeur au-delà de laquelle ils ne sont plus nets.


Plus de 2 millions de petits triangles sont générés, en fushia.

Quelques chiffres :

Temps de rendu : 9.7 ms (7.7 %)
Vertices avant tessellation : 1.10 millions
Vertices après tessellation : -
Primitives : 2.20 millions
Primitives éjectées du rendu : 0
Pixels : 22.41 millions
Eléments exportés par les PS : 22.70 millions
Texels : 93.12 millions
Instructions exécutées : 217.96 millions
Quantité de données lues : 87.1 Mo
Quantité de données écrites : 49.8 Mo


Page 12 - Etape 10 : le post-traitement

Etape 10 : le post-traitement
La dernière étape lourde du rendu de 3DMark est le post-traitement, qui englobe différents filtres et effets optiques : éblouissement (bloom), halos (lens flares) et réflexions formés dans l'objectif, grain, tone mapping et redimensionnement. Les effets optiques sont calculés via les compute shaders et représentent le plus gros de la charge du post-traitement. Le tone mapping permet d'interpréter l'image HDR alors que le redimensionnement simule un format large anamorphosé :


[ Avant post-traitement ]  [ Après post-traitement ]

Le post-traitement est segmenté en 3 étapes : le bloom + les lens flares, les réflexions internes à l'objectif et le tone mapping + le grain. Cette dernière étape est la plus simple : un pixel shader relativement simple combine les deux effets.

Les deux autres étapes, qui nécessitent un format HDR 128 bits (R32G32B32A32_FLOAT), sont plus complexes et font appel à 4 reprises à une transformée de Fourrier rapide (FFT), exécutée via une succession de compute shaders. L'image à traiter est tout d'abord réduite dans une résolution qui correspond à la puissance de deux directement supérieure au quart des dimensions originales (1920 -> 480 -> 512). Elle est ensuite transposée dans le domaine fréquentiel à partir duquel le bloom ainsi que les lens flares d'une part, et les réflexions internes d'autre part, vont prendre forme grâce à des filtres dédiés. Dans le premier cas, le filtre doit être calculé au préalable, ce qui représente une des 4 utilisations de la transformée de Fourrier rapide.


[ Filtre ] + [ Image dans le domaine fréquentiel ] ->[ Filtre appliqué ]
->[ Reconstruction – FFT inverse ] = [ Bloom + lens flares ]
[ Lens reflections ]

Quelques chiffres :

Temps de rendu : 10.7 ms (8.5 %) dont 10.3 ms via compute shader (8.2 %)
Vertices avant tessellation : 22
Vertices après tessellation : -
Primitives : 24
Primitives éjectées du rendu : 0
Pixels : 3.44 millions
Eléments exportés par les PS : 3.44 millions
Texels : 104.99 millions dont 72.48 via compute shader
Instructions exécutées : 165.20 millions dont 126.48 millions via compute shader
Quantité de données lues : 819.1 Mo dont 590.0 Mo via compute shader
Quantité de données écrites : 615.1 Mo dont 448.9 Mo via compute shader


Page 13 - Etape 11 : l'interface

Etape 11 : l'interface
La dernière étape est également la plus simple : il s'agit de dessiner l'interface par-dessus l'image qui vient d'être calculée. Pour cela, chacun des éléments qui la composent est plaqué sous forme de texture sur un rectangle formé par 2 triangles :


Quelques chiffres :

Temps de rendu : 0.04 ms (0.03 %)
Vertices avant tessellation : 96
Vertices après tessellation : -
Primitives : 46
Primitives éjectées du rendu : 0
Pixels : 82972
Eléments exportés par les PS : 76096
Texels : 86112
Instructions exécutées : 168113
Quantité de données lues : 0.6 Mo
Quantité de données écrites : 0.3 Mo


Page 14 - L'image finale

L'image finale

Préparation : [ Objets ] ->[ G-buffer ] + [ Ombres ]
Eclairage : [ Ciel ] + [ Principal ] + [ Secondaire ] + [ Volumétrique ]
Post-traitement + interface : [ Image finale ]

Pour créer une image telle que celle-ci, 3DMark 11 n'a pas ménagé ses efforts et a traité 564 commandes de rendu, 12 millions de triangles, 150 millions de pixels, 85 sources de lumière et 14 milliards d'instructions. Rien que ça !

De quoi mettre à genoux n'importe quel GPU DirectX 11 actuel avec de la tessellation, des geometry shaders, des compute shader, des ombres de qualité, des effets de profondeur de champ et de caméra complexes, sans oublier un éclairage extrêmement lourd.

Un niveau de complexité qui, à terme, se retrouvera inévitablement dans les jeux vidéo, sous des formes probablement plus efficaces. Crysis 2 et Battlefield 3, pour ne citer qu'eux, exploitent déjà des moteurs graphiques similaires avec quelques compromis au niveau de la charge géométrique et des algorithmes d'éclairage qui sont calibrés de manière à pouvoir tourner d'une manière décente sur le matériel d'aujourd'hui.

Nous espérons que ce dossier vous aura donné une idée un peu plus claire sur la manière dont un moteur graphique moderne fonctionne. Pour terminer voici les chiffres complets qui représentent la charge à traiter par le GPU :
Temps de rendu : 125.9 ms (= 8 fps)
Vertices avant tessellation : 5.36 millions
Vertices après tessellation : 11.97 millions
Primitives : 12.61 millions
Primitives éjectées du rendu : 6.19 millions
Pixels : 179.29 millions
Eléments exportés par les PS : 151.18 millions
Texels : 2.39 milliards
Instructions exécutées : 14.40 milliards
Quantité de données lues : 4.73 Go
Quantité de données écrites : 1.08 Go


Copyright © 1997-2022 HardWare.fr. Tous droits réservés.