OpenGL Moderne

Tutoriel 10 : la transparence

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

2 commentaires Donner une note à l'article (5)

Article lu   fois.

Les deux auteur et traducteur

Site personnel

Traducteur : Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

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 :

 
Sélectionnez
// 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 :

 
Sélectionnez
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 ».

Suzanne transparente

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.

Ordre de transparence

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

Problème d'ordre d'affichage et de transparence

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 :

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 :

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

Ce qui signifie :

 
Sélectionnez
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 :

 
Sélectionnez
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

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

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.