Le filtrage des textures (anisotropic filtering)

Le filtrage des textures

S’il est clair qu’il tient du rôle du développeur d’être capable de créer le gameplay le plus conforme à la vision de son jeu indépendamment du support matériel et des inévitables contraintes qui lui sont associés (qualité graphique, puissance de l’IA, taille du monde créé, etc.), il n’en demeure pas moins vrai que l’évolution de la puissance de nos machines donne de plus en plus de liberté aux créateurs de jeux vidéo. J’en veux pour preuve le nombre important de ces mêmes créateurs qui, renonçant à l’idée de devoir faire de grosses concessions sur le niveau de réalisme permis pour leur jeux au moment où ils eurent l’idée global de ce à quoi ils devraient ressembler, ont choisit d’attendre de nombreuses années afin de pouvoir bénéficier des progrès techniques prodigieux – je pense entre autres à Benoît Sokal avec les charmes oniriques de son Amerzone, ou encore à la fidélité incroyable qu’à réussit à atteindre Oleg Maddox avec IL-2 Sturmovik. De l’aveu même de ceux-ci, sans le niveau de performance de nos machines actuelles, leurs projets n’auraient tout simplement pas pu voir le jour.

D’ailleurs il est évident que notre manière de jouer, tout du moins le type de gameplay qui a pu nous être proposé, a largement évolué (à comprendre ici dans le sens de changer) au fil des années.

Une autre manière de se convaincre d’aller si régulièrement hypothéquer sa maison auprès de son banquier pour pouvoir racheter la dernière carte 3D du moment, peut-être…

Ceci m’amène à vous parler des astuces utilisées pour, à partir d’une forme géométrique simple à calculer et à manipuler pour la carte graphique, arriver à créer l’illusion d’être en face d’un objet 3D. Car la méthode qui a fait ses preuves jusqu’alors est simple et finalement très logique : elle consiste à coller sur les faces de l’objet 3D en question, des images en 2D. Vous voulez créer une maison ? Rien de plus simple, prenez un cube basique, et appliquez sur chacune de ses faces une image 2D adéquate, par exemple pour la face principale une image dessinant la porte, une fenêtre, etc. C’est ce qu’on appelle le ‘Texture Mapping’.

Avant d’aller plus loin, je dois expliciter ici une des bases nécessaires à la compréhension du mécanisme qui permet l’affichage de scènes 3D sur un écran : la différence entre pixel et texel. Un pixel (picture elements) ne désigne en fait rien d’autre que le point dont l’association avec d’autres compose l’image qui s’affiche sur un écran, la couleur finale de chaque pixel étant déterminée par sa composition par trois points rouge, vert et bleu (RGB).

Le filtrage des textures (suite)

Quant aux texels (texture elements), ils se définiraient donc ici comme les pixels de l’image 2D que l’on va accoler à la surface 3D.

Ce qu’il faut bien comprendre, c’est qu’en utilisant cette technique du Texture Mapping pour la création d’objets ou de surfaces à l’aspect répétitif (une route par exemple), nous avons tout intérêt à utiliser une texture bien plus petite que la surface à remplir, et à la répliquer un grand nombre de fois. Tout simplement parce que la taille de la texture à aller chercher en mémoire, puis à manipuler, sera beaucoup plus petite.

Pourtant, cela pose le problème des raccords entre tous les clones de cette même texture, puisqu’elle va donc être mise bout à bout. Prenons un exemple pour bien saisir les difficultés que cela peut amener : si vous avez déjà posé du papier peint dans une pièce, vous savez qu’un des aspects les moins facile à prendre en compte réside dans le respect des raccords entre les motifs du papier peint, puisque indépendamment des formes que peuvent prendre ceux-ci, tout papier peint est découpé en bandes verticales. Même si le problème est légèrement plus complexe dans le cas du Texture Mapping, l’idée générale est là : le but est de faire disparaître complètement les raccords entre les textures, de manière à créer l’illusion qu’il s’agit en fait d’une seule grosse texture.

Dès lors, le point clef de notre problématique va être de savoir quel(s) texel(s) va ou vont déterminer la couleur du pixel correspondant sur l’écran, et ce sont les différentes réponses possibles à cette question qui vont déterminer le type de filtrage de texture utilisé.

Pour bien comprendre ce problème, on peut imaginer une représentation dans laquelle on matérialiserait l’écran par un tamis, constitué d’une multitude de trous – chacun de ces trous constituant donc un pixel. Si l’on regarde derrière l’un de ces trous, on ne va pouvoir distinguer qu’une seule couleur (les trous étant très fins), qui va résulter de la scène 3D qui se déroule derrière l’écran. C’est l’ensemble de ces tout petits points qui va me permettre de visualiser la scène en question.

Remplaçons maintenant notre œil par une lampe. On peut facilement comprendre que si la face du polygone qui se présente derrière le trou à cet instant est parallèle au tamis, alors la lumière va passer par le trou et venir dessiner un cercle sur ce polygone.

Admettons maintenant que ce même polygone bouge, et que la face qui était visible par le trou ne soit plus parallèle par rapport au tamis. Le cercle de lumière qui illumine le polygone va alors prendre une forme elliptique, d’autant plus elliptique que le polygone formera un angle proche de 90° avec l’écran.

Voilà, vous avez la solution de l’énigme : la couleur de chaque pixel devra être déterminée par l’ensemble des polygones éclairés par ma lampe (et là si vous êtes sympa vous me faites : « D’accooooooord ! »…).

Plusieurs méthodes de filtrage

Dès lors, une multitude de méthodes de filtrage de texture ont été définies, chacune ne différant de l’autre que par la fidélité de l’algorithme utilisé pour prendre en compte tous les texels mis en jeu. Sauf que malheureusement, plus on prend de texels, et plus le procédé devient gourmant, aussi bien en bande passante qu’en calculs. Il s’agit donc de trouver le meilleur compromis possible en fonction de la puissance et de la bande passante disponible, et c’est dans cette optique que 4 techniques ont majoritairement été utilisées aujourd’hui dans les jeux (bon, comme j’en vois 2-3 qui commencent à fatiguer au fond on va simplifier).

En première approximation, on a d’abord défini le Point Sampling. Le principe est on ne peut plus simple puisqu’on se contente de prendre le pixel le plus au centre de la partie éclairée de l’image 2D. L’écart avec la réalité est important puisque plus d’un texel est à l’origine de la couleur d’un pixel, et de ce fait l’erreur devient de plus en plus visible quand le polygone se rapproche de la camera derrière laquelle la scène est vu, puisqu’il arrivera un moment ou l’on aura plus de pixels que de texels, ce qui donnera un résultat de piètre qualité. Cela dit, gardez en tête que le but initial du filtrage de texture n’est que l’amoindrissement de l’effet d’aliasing sur la profondeur.

Plus aucun jeu n’utilise aujourd’hui ce filtrage devenu trop basique.

Puis vient le filtrage bilinéaire. Son algorithme d’interpolation consiste à considérer que la partie éclairée par la lampe forme toujours un cercle, même quand le polygone n’est pas parallèle à l’écran. De ce cercle, l’algorithme ne va retenir que 4 texels de sa périphérie, disposés de manière à former un carré entre eux.

Le gain visuel est considérable, mais en fait cette technique reste inexacte dans la mesure où elle considère dans tous les cas que la forme dessinée par la lumière de la lampe sera un cercle parfait, or ceci n’est pratiquement jamais le cas.

L’autre problème vient du fait que cette technique est donc 4 fois plus gourmande en bande passante par rapport au ‘Point Sampling’.

Plusieurs méthodes de filtrage (suite)

Pour illustrer ceci, j’ai parcouru les niveaux de Jedi Knight 2 (mmh, conscience professionnelle oblige !), jusqu’à arriver dans un endroit ou l’effet du filtrage de texture pouvait être largement mis en évidence, ici par la présence de la grille sur le sol. Observez son aspect au loin.

Le filtrage trilinéaire permet quand a lui de recalculer l’aspect des textures en fonction de la distance depuis laquelle celles-ci sont observées. Il s’obtient en ajoutant au filtrage bilinéaire la notion de Mip Mapping, qui stock en mémoire plusieurs échantillons d’une même texture vu à des distances différentes (dans un soucis de gain de qualité et de vitesse, puisque ces textures sont pré-calculées). En fait, un filtrage bilinéaire est effectué sur 2 niveaux de Mip Mapping, ce qui porte à 8 le nombre de texels considéré. Et donc à un doublement de bande passante utilisée.

Enfin, le filtrage anisotropique constitue le procédé le plus abouti. Tout d’abord, la forme dessinée par la lumière projetée sur le polygone est enfin prise en compte par l’utilisation de différents filtres (donc plus ou moins elliptique). Puis, tous les texels ainsi déterminés sont utilisés pour faire l’interpolation : la couleur que prendra le pixel final. Il existe différents niveaux dans l’anisotropie, permettant de prendre plus ou moins de texels en compte (en moyenne 64) mais il est clair que le résultat final est toujours meilleur.

Mis bout à bout, cela nous donne le résultat suivant (de gauche à droite : bilinéaire, trilinéaire, anisotropie + bilinéaire, anisotropie + trilinéaire). Notez que tous les réglages ont été effectués dans le jeu, et que ceux de l’anisotropie ainsi que de l’antialiasing des drivers ont été désactivés (GeForce 4 Ti 4400, 40.72 WHQL, -« parce que je le vaux bien ! »).

Les choix d’ATI et de nVidia

Ce qu’il faut bien comprendre, c’est qu’outre les réglages disponibles dans certains jeux, ces différentes méthodes de filtrage des textures sont également à l’origine des différents modes d’anisotropie que l’on peut choisir dans les drivers d’ATI et d’nVidia.

Du côté d’ATI, la méthode utilisée sur les Radeon 8500 avait fait l’objet de quelques critiques (‘RIP mapping’). En fait, l’algorithme utilisé était adaptatif, et n’était efficace que sur les surfaces parfaitement verticales ou horizontales avec l’écran, ce qui permettait à ATI d’obtenir de meilleures performances. En mode ‘highest quality’, le filtre utilisait 16 blocs de texels ayant subi un filtrage bilinéaire : 16 blocs x 4 texels = ‘64tap’. Par opposition au mode ‘high’ ou ‘16tap’ qui s’opérait sur 4 blocs. Concrètement, dans un jeu où l’on se trouve exactement en face d’un mur, même avec l’anisotropie activée, l’ancien filtre n’effectuait qu’un filtrage bilinéaire, puisque la différence avec un filtrage réellement anisotropique est, en théorie, nulle dans ce cas. Donc 4 texels utilisés. Dans les autres situations, le filtre s’effectuait à partir des 64 texels (seul le mode bilinéaire était utilisable avec l’anisotropie). Les fps sauvés au passage étaient donc considérables.

Actuellement, deux modes sont accessibles dans les drivers. Le mode ‘performance’ effectue l’anisotropie avec un filtrage bilinéaire (en Direct3D comme en OpenGL), alors qu’il s’agit d’un filtrage trilinéaire dans le cas du mode ‘qualité’ (mode Direct3D seulement). C’est donc par l’usage de ce dernier mode que le gain de qualité de l’anisotropie des Radeon 9700 par rapport à l’anisotropie des Radeon 8500 peut être observé. Souvenez vous : ce filtrage reste adaptatif, de sorte que seules quelques textures seront soumises, si l’algorithme juge qu’elles sont très dégradées, au filtrage anisotropique avec un filtrage trilinéaire (si l’on prend le mode ‘qualité’). Mais il peut très bien y avoir des cas où le filtre décide de rester sur un filtrage bilinéaire.

Dans le cas de nVidia, les choses restent compliquées (d’ailleurs j’y ai laissé ma greffe de neurone…). L’anisotropie utilisée pour les GeForce 4 est également de type adaptative. Mais d’abord, les algorithmes utilisés sont évidemment différents et leur comportement n’est pas identique à ceux d’ATI, et ensuite, le filtre monte jusqu’à un filtrage anisotropique avec filtrage trilinéaire. C’est donc cette simple différence de qualité de filtrage maximum, qui explique en partie l’écart entre l’impact de l’usage de l’anisotropie sur les performances des Radeon 8500 avec les GeForce 4 Ti. Même s’il est clair que le filtre utilisé par nVidia semble être plus exigeant sur la qualité que celui d’ATI, c’est-à-dire qu’il utilisera plus souvent un filtrage anisotropique sur des textures où une Radeon 8500 se contentera peut-être d’un simple filtrage trilinéaire.

Si l’on en croie David Kirk de nVidia, un autre facteur serait à prendre en compte : la géométrie prise en compte par chaque carte pour dessiner l’« ombre porté de la lampe » (si l’on repart sur l’exemple initial). Ainsi, là où ATI se verrouillerait sur la forme d’un rectangle, les algorithmes de nVidia partiraient plus sur la base d’un polygone à 4 faces, dont les caractéristiques exactes seraient définies, je vous le donne en mille, selon l’angle de la surface avec la caméra. Cette technique reste donc supérieure sur le plan de la qualité à l’approche d’ATI. Mais elle reste, fatalement, plus gourmande. Notez d’ailleurs que l’utilisation des algorithmes non adaptatifs, disponibles dans les drivers nVidia (GeForce FX uniquement), permettent de mesurer le gain en performance permis par l’emploi de ce genre de solutions « intelligentes », c’est-à-dire qui analysent les texels à traiter.

Le GeForce FX n’a donc en rien inauguré l’usage d’un filtrage anisotropique adaptatif par nVidia, puisqu’au moins les GeForce 4 l’utilisaient déjà. Il est d’ailleurs clair qu’nVidia s’est plusieurs fois contredit sur cette question.

J’aimerais enfin revenir brièvement sur le fait que ces deux méthodes sont adaptatives, mais n’utilisent évidemment pas les mêmes critères de sélection et d’exigence. Cela implique qu’il devient beaucoup plus délicat de comparer les cartes des deux constructeurs, sur le plan de l’anisotropie. Tout simplement parce que même en sélectionnant les méthodes a priori correspondantes, c’est-à-dire mode ‘qualité’ sur une Radeon 9700 et mode ‘balanced’ sur une GeForce FX, chaque carte ne traitera pas les mêmes scènes de la même manière. Cela invalide donc quelque part la méthode utilisée par certains testeurs, qui a été de d’abord comparer visuellement la qualité de ces différents filtrages sur un seul screenshot particulier, pour ensuite se verrouiller sur ces constations, et comparer les performances respectives des cartes dans un second temps. D’ailleurs, cela est d’autant plus vrai s’il est exact que certains des filtres d’anisotropie ne sont appliqués qu’après le passage dans le frame-buffer, dans le cas de la GeForce FX, puisque c’est pourtant à ce stade que les screenshots que l’on peut faire dans les jeux sont pris. C’est peut-être ce qui a induit en erreur certains testeurs, qui sont arrivés à la conclusion que le mode nVidia ‘balanced’ est équivalent au mode ATI ‘performance’.

Les logiciels d’évaluation du filtrage, conclusion

Différents procédés sont possibles, qu’il s’agisse de lignes de commandes dans les jeux ou de logiciels spécialisés, tel le test ‘Texture Filtering’ dans 3DMark03, ou encore Texture Filter TestApp V1.2 de Georg Kolling (Georg.Kolling@gmx.de) qui présente l’avantage d’être disponible avec son code source. Tous participent de la même volonté : permettre de distinguer, à l’aide d’une coloration artificielle, les différents niveaux de mipmap (rendu également appelé « Alice au pays du LSD »…).

Sur ce dernier programme, qui est intéressant du fait de l’utilisation d’un tunnel de forme ronde, ce sont les transitions entre les mipmaps qui sont à observer. Plus le filtrage s’effectue sur la majorité des mipmaps (c’est-à-dire meilleur il est), et plus les transitions deviennent floues et arborent un dégradé.

Par ailleurs, la forme et l’allure des transitions entre les mipmaps nous permettent également d’évaluer la qualité des méthodes d’anisotropie adaptatives utilisées, puisque celles-ci diffèrent entre elles. Ainsi, dans le cas d’un filtrage non adaptatif, on obtiendrait des mipmaps formant un cercle. Or, l’anisotropie produisant surtout des améliorations sur des angles faibles par rapport à l’horizontale et à la verticale, il est logique que ce soit sur ces mêmes angles que l’anisotropie devrait être plus appuyée dans le cas des méthodes adaptatives.

Voici par exemple le résultat, toujours avec une GeForce 4 Ti 4400, avec une anisotropie 8x :


–> Notez les irrégularités des transitions pour chaque angle

Toutefois, gardez en tête que ces programmes restent encore une fois théoriques, et qu’il sera difficile de se baser dessus pour comparer deux méthodes d’anisotropie adaptative différentes, car les résultats n’auront probablement rien à voir. Cela dit, il faut bien résoudre ce dilemme, mais une étude approfondie représentant différentes situations sous plusieurs jeux reste à privilégier.

En bref, l’impact relativement important résultant de l’usage de l’anisotropie sur les performances, a fait que chaque constructeur a développé des méthodes propriétaires adaptatives qui complexifient grandement la tâche du testeur. Le gain en terme de qualité d’image est réel, particulièrement dans les FPS ou dans les simulations aériennes, d’autant plus s’il est couplé à l’antialiasing qui a tendance à délaver les textures.

S’il est difficile de justifier par l’avènement de ce simple procédé, le temps qu’ont attendus certains créateurs pour produire leurs jeux vidéo, on peut simplement prendre ces techniques comme une brique dans l’évolution des graphismes qui ont permis d’atteindre le niveau actuel !