Considérations sur la transparence
En général, la transparence ne fait pas bon ménage avec le Z-Buffer, mais on peut tenter de les faire cohabiter sans trops de dégats.
Le problème, avec la transparence, c’est que ce qui se trouve derrière une face peut être visible (c’est justement pour ça qu’elle est transparente). On voit tout de suite que si on affiche la face en Z-Buffer, toute face qui serait dessinée après la face transparente, et se situant derrière elle, ne serait pas vue.
On peut corriger partiellement ce problème en décidant qu’au moment de tracer la face, on se contente de lire le Z-Buffer, sans jamais écrire dedans. Mais ça inverse le problème : si une face non-transparente est affichée derrière une face transparente, elle va recouvrir tout ou une partie de cette face transparente, mais sans être affectée par la transformation venant de la transparence (texture transparente, ...).
Exemple : la face rose est transparente, la face jaune ne l’est pas, se trouve derrière la face rose et est affichée en dernier. A gauche, le résultat correct, au centre le résultat avec Z-Buffer, et à droite le résultat avec Z-Buffer uniquement en lecture pour la transparence :
Par contre, si on se débrouille pour que la face rose (transparente) soit toujours affichée après la face jaune, alors il n’y a aucun problème, c’est correct dans tous les cas. Première leçon : toujours afficher les faces transparentes après les faces qui ne le sont pas.
Le second problème qui va se poser, c’est que, bien souvent, la formule de transparence utilisée n’est pas associative ni commutative. Je m’explique : si on a deux faces transparentes, afficher la premier au dessus de l’autre ou vice-versa ne va pas donner le même résultat (malgré ce que l’on pourrait croire à prioris). Ca vient du fait qu’en général on utilise plutôt une formule de superposition à la place d’une formule de filtrage.
Le filtrage, c’est ce qui se passe quand vous placez effectivement une face rose transparente au dessus d’une face jaune : vous voyez du rouge. Pourquoi ? Parce que la couleur jaune est une combinaison de rouge et de vert, tandis que la couleur rose est une combinaison de rouge et de bleu. Le point commun entre les deux, c’est bien le rouge. Il s’agit du filtrage (le rose ne laisse passer que le rouge et le bleu, le vert du jaune est donc arrêté).
La superposition, c’est l’inverse, on fait un mix des couleurs. C’est à dire que c’est exactement le contraire : du rouge sur du vert, ca va donner du jaune, comme ceci :
On utilise cette formule car elle est plus simple à programmer. Mais si vous permuttez l’ordre des faces, bien souvent le résultat sera différent (pas ici avec ces exemples simples). Pour me convaincre, en son temps, j’avais fait la preuve mathématique, mais je suis sûr que ça ne vous intéresse pas, contentez-vous de me croire et puis basta.
Bref qu’au final, il faut faire quoi ? Il faut trier les faces transparentes pour être sûr de toujours les afficher dans le même « bon » ordre. Les trier selon Z par exemple, comme à l’époque de l’avant Z-Buffer. Un vrai plaisir, hein ?
Moralité, un pipeline devrait faire les choses suivantes :
- Afficher, avec Z-Buffer, toutes les faces non transparentes.
- Trier selon Z toutes les faces transparentes.
- Afficher, avec Z-Buffer uniquement en lecture, toutes les faces transparentes dans l’ordre Z.
Mais en général on ne possède pas toutes les faces à afficher d’un seul coup comme ça. En pratique il est normal de passer les objets un à un en revue, et de relancer le pipeline dessus chaque fois. Ben ici ça ne marche plus, car avec ça, même si les faces transparentes sont affichées en dernier dans un objet particulier, il est fort probable que l’objet suivant affichera des faces non transparentes.
Une solution, c’est de séparer les objets en deux catégories : les objets transparents et les objets qui ne le sont pas. Les objets non transparents sont affichés avant les transparents, et les faces des objets transparents sont tirées. De plus, les objets transparents sont tirés en Z entre eux, de sorte d’afficher en premier les objets transparents les plus éloignés. Il faut bien comprendre qu’un objet « transparent » sera considéré tel quel si il possède au moins une face transparente. C’est pourquoi il est conseillé de faire des objets soit totalement transparents, soit pas du tout. Si vous faites un avion avec le cockpitt transparent, il vaudrait mieux décomposer cet avion en deux objets : le cockpitt et le reste de l’avion. Et le cockpitt sera affiché après l’avion.
Ce système fonctionera « souvent », mais dès que vous ferez des intersections entre des objets transparents, tout va tomber en morceau. Moralité : évitez à tout prix de faire se rentrer dedans des objets transparents.
La gestion de la transparence demande un peu plus d’organisation que l’affichage de « bêtes » objets non transparents.