OpenGL Moderne

Tutoriel 10 : la transparence

Opengl-tutorial.org

Traducteur

Alexandre Laurent

Dans ce tutoriel, on va discuter de la transparence des modèles 3D en OpenGL.

Commentez

- Titre : OpenGL Moderne

- Auteur : Opengl-tutorial.org

- Traducteur : Alexandre Laurent

- Parution : 27 mai 2014

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2014 opengl-tutorial.org. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- Navigation

- I. La canal alpha

- II. L'ordre est important

- II-A. Le problème

- II-B. Solution classique

- II-C. Mise en garde

- II-D. Transparence indépendante de l'ordre

- III. La fonction de mélange

- IV. Remerciements

- Navigation

Navigation

Tutoriel précédent : indexation de VBO

Sommaire

Tutoriel suivant : texte 2D

I - La canal alpha

Le concept du canal alpha est très simple. À la place d'écrire un résultat en RGB, vous écrivez un résultat en RGBA :

// Données de sorties : c'est maintenant un vec4
out vec4 color;

les trois premières composantes sont toujours accessibles avec .xyz, tandis que la dernière est accessible avec .a :

color.a = 0.3;

Contre toute logique, alpha = opacité, donc alpha = 1 signifie complètement opaque alors que alpha = 0 signifie complètement transparent.

Ici, on a simplement codé en dur le canal alpha à 0.3, mais vous souhaitez sûrement utiliser une variable uniforme ou la lire à partir d'une texture RGBA (le format TGA supporte le canal alpha et GLFW supporte le format TGA).

Voici le résultat. Assurez-vous de désactiver le « backface culling » (suppression des faces arrières) (glDisable(GL_CULL_FACE)) car comme on peut voir à travers le modèle, on pourrait penser qu'il n'a pas de face « arrière ».

II - L'ordre est important

La capture d'écran précédente paraît correcte, mais c'est uniquement car on est chanceux.

II-A - Le problème

Ici, j'ai dessiné deux carrés ayant 50 % d'alpha, un vert et un rouge. Vous pouvez voir que l'ordre est important, la couleur finale donne une importante piste visuelle sur la perception de la profondeur.

Ce phénomène se produit aussi sur la scène. Changez le point de vue :

En fait, c'est un problème très complexe. Vous ne voyez jamais énormément de transparence dans les jeux vidéo, n'est-ce pas ?

II-B - Solution classique

La solution classique est de trier tous les triangles transparents. Oui, TOUS les triangles transparents.

- Dessinez la partie du monde opaque afin que le tampon de profondeur puisse déjà rejeter les triangles transparents cachés.

- Triez les triangles transparents, du plus loin aux plus proches.

- Dessinez les triangles transparents.

Vous pouvez trier ce que vous voulez avec qsort (en C) ou std::sort (en C++). Je n'entrerai pas dans les détails, car…

II-C - Mise en garde

Faire comme cela fonctionne (plus de détails dans la section suivante), mais :

- vous allez être limité par la bande passante. En effet, chaque fragment sera écrit 10, 20 fois ou même plus. Cela est beaucoup trop pour le pauvre bus mémoire. Habituellement, le tampon de profondeur permet de rejeter assez de fragments « lointains », mais là, vous les triez explicitement, faisant que le tampon de profondeur soit totalement inutile ;

- vous allez faire cela quatre fois par pixel (on utilise le 4xMSAA), sauf si vous utilisez une optimisation plus intelligente ;

- le tri des triangles prend du temps ;

- si vous devez changer de texture, ou pire, de shader, de triangle en triangle, vous allez avoir de sérieux problèmes de performance. Ne le faites pas.

Une solution assez bonne est souvent de :

- limitez à un maximum le nombre de polygones transparents ;

- utilisez le même shader et la même texture pour tous les polygones transparents ;

- s'ils sont sensés être très différents, utilisez votre texture ;

- si vous pouvez éviter le tri et que cela n'est pas trop moche, vous pouvez vous dire chanceux.

II-D - Transparence indépendante de l'ordre

De nombreuses autres techniques sont intéressantes si votre moteur a vraiment, vraiment besoin de l'état de l'art de la transparence :

- le papier original 2001 Depth Peeling : résultats parfait au niveau du pixel, pas très rapide ;

- Dual Depth Peeling : une petite amélioration ;

- de nombreux papiers sur le tri comptage (bucket sort) utilisent un tableau de fragments ; les tris par la profondeur dans le shader ;

- démonstration d'ATI Mecha : bon et rapide, mais compliqué à implémenter et nécessite du matériel récent. Utilise une liste chaînées de fragments ;

- variation de la technique d'ATI par Cyril Crassin : implémentation encore plus compliquée.

Même un jeu récent comme Little Big Planet, s'exécutant sur une console puissante, utilise une unique couche de transparence.

III - La fonction de mélange

Afin que le code précédent fonctionne, vous devez initialiser la fonction de mélange :

// Active le mélange
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

Ce qui signifie :

nouvelle couleur dans le tampon d'image =
alpha actuel dans le tampon d'image * couleur actuelle dans le tampon d'image +
(1 - alpha actuel dans le tampon d'image) * la couleur de sortie du shader

Exemple de l'image ci-dessus, avec le rouge au-dessus :

nouvelle couleur = 0.5 * (0,1,0) 1+ (1-0.5) * (1,0.5,0.5) ; // (le rouge était déjà mélangé avec le fond blanc) ;
nouvelle couleur = (1, 0.75, 0.25) = le même orange

IV - Remerciements

Cet article est une traduction autorisée dont le texte original peut être trouvé sur opengl-tutorial.org.

Navigation

Tutoriel précédent : indexation de VBO

Sommaire

Tutoriel suivant : texte 2D