Mélange Alpha retardé

Dans cet article, je veux parler des méthodes de mélange de la géométrie tramée. Les modèles classiques de mélange d'objets translucides - Alpha, additif, multiplicatif - sont unis par le même principe de dessin: dessinez séquentiellement une primitive après l'autre, en mélangeant les pixels reçus à la sortie du fragment shader avec ce qui se trouve dans le tampon actuel. Chaque nouvelle primitive met à jour la zone du tampon dans laquelle elle est dessinée; dans le cas du mélange alpha, les objets qui sont plus élevés que ceux précédemment dessinés. Mais que faire si vous voulez faire quelque chose avec un groupe d'objets dessinés au-dessus de la scène - par exemple, les recadrer par masque ou les mettre en surbrillance? Ici, deux décisions viennent immédiatement à l'esprit: soit apporter des modifications à leur matériau (c'est-à-dire changer le shader, étendre l'ensemble de textures), par exemple, ajouter une projection d'une autre texture,qui sera responsable du masque de transparence. Cependant, si nous avons beaucoup d'objets marbrés, changer chaque matériau unique est gênant et semé d'erreurs. La deuxième option consiste à dessiner tous les objets qui nous intéressent dans une cible plein écran distincte et à la dessiner déjà sur la scène finale. Ici, nous pouvons faire tout ce que nous voulons avec son contenu, mais cela nécessite l'allocation de mémoire supplémentaire et, plus désagréablement, la commutation du rendu cible. Ce n'est pas l'opération «la moins chère» sur les appareils mobiles, qui devra être effectuée deux fois. Et si vous souhaitez travailler avec plusieurs calques comme celui-ci?Ici, nous pouvons faire tout ce que nous voulons avec son contenu, mais cela nécessite l'allocation de mémoire supplémentaire et, plus désagréablement, la commutation du rendu cible. Ce n'est pas l'opération «la moins chère» sur les appareils mobiles, qui devra être effectuée deux fois. Et si vous souhaitez travailler avec plusieurs calques comme celui-ci?Ici, nous pouvons faire tout ce que nous voulons avec son contenu, mais cela nécessite l'allocation de mémoire supplémentaire et, plus désagréablement, la commutation du rendu cible. Ce n'est pas l'opération «la moins chère» sur les appareils mobiles, qui devra être effectuée deux fois. Et si vous souhaitez travailler avec plusieurs calques comme celui-ci?



Il existe une autre façon, plus simple et plus élégante, de résoudre ces problèmes. Nous pouvons peindre la scène à l'envers!

Une petite digression pour vous rappeler le fonctionnement de la méthode de rendu classique
- Alpha Blending , , , . 4 RGBA, RGB — A(Alpha) — ( ). . :


ColorSrc — RGB , ( , ), ColorDst — , , Color_Result — , , , . Variable1 Variable2, ? , ( , ). , : , ... 

:


AlphaSrc — - (), OneMinusAlphaSrc, , 1.0 — AlphaSrc. : 1 * + 2 * (1 — ). alpha (). = 1, , = 0, . OpenGL .

OpenGL ES 2.0 — .

Comment l'image est formée par étapes: nous dessinons d'abord un arrière-plan, puis nous dessinons tous les objets en couches les uns après les autres. Le dernier rendu remplace les pixels précédents: 





Quelle est l'astuce? 


L'essence de la technologie du rendu inversé ou, comme on peut aussi l'appeler, du mixage retardé est la suivante. Nous dessinons la scène à l'envers en utilisant une formule de mélange différente. De plus, l'image finale restera exactement la même qu'avec l'approche classique.

Comment ça fonctionne?


La méthode de mélange à travers le canal de transparence de l'image que nous dessinons a été décrite ci-dessus. Maintenant, nous allons l'inverser: nous allons utiliser la transparence des pixels déjà dessinés (ou plutôt, mélanger la transparence dessinée avec celle déjà dessinée). Autrement dit, au lieu d'AlphaSrc, nous utiliserons AlphaSaturate et au lieu de OneMinusAlphaSrc - One. Il s'avère que s'il y a déjà quelque chose avec transparence = 1 dans le tampon, alors la contribution sera nulle et la couleur d'un tel pixel ne changera pas. S'il n'y avait aucune transparence, ajoutons les deux couleurs ensemble (pour cela, nous devrons effacer le tampon de trame avec des zéros ou du noir avec zéro transparence). Avec cet ajout, la couleur résultante sera égale au dessin. La formule finale ressemble à ceci:
 

(environ AlphaSaturate = min (AlphaSrc, 1 - AlphaDst))

Les valeurs de transparence doivent être ajoutées: il doit accumuler couche par couche, c'est-à-dire que nous aurons un et un dans les variables de mélange pour le canal alpha. Pourquoi ne modifions-nous pas ColorDst et n'effaçons-nous pas le tampon avec des zéros? Ceci est nécessaire pour le mélange additif, AdditiveBlending ne différera que par le fait qu'il aura zéro dans la variable AlphaSrc. Il ne doit pas modifier la transparence, seulement la couleur.

Pour plus de clarté, le schéma de rendu inverse ressemble à ceci: 

Tout d'abord, nous effaçons le tampon de trame. Ensuite, nous définissons la fonction de mélange indiquée ci-dessus et commençons à dessiner à partir des objets les plus hauts (dans l'approche classique, ils seraient dessinés en dernier), en descendant vers les objets inférieurs. L'image d'arrière-plan sera dessinée en dernier.


Comment cela peut-il être utilisé?


Je décrirai plusieurs tâches résolues par cette méthode, en utilisant notre projet comme exemple:

  1. Détourage d'objets par masque avec transparence. Détourage en douceur de la salle de jeux:


    Après avoir tracé le terrain de jeu, il suffit d'effacer la transparence aux endroits de l'image que nous voulons masquer. Cela se fait à l'aide de la formule de mélange, dans laquelle l'objet masque dessiné écrase la couleur et la transparence inversement avec sa propre transparence, et le degré de nettoyage peut être ajusté en continu. Dans ce cas, la géométrie suivante est utilisée pour l'écrêtage:


    Il change de forme lorsque la caméra se déplace entre les pièces. La formule de mélange pour le nettoyage est la suivante:

    ColorSrc = GL_ZERO,
    ColorDst = GL_ONE_MINUS_SRC_ALPHA,
    AlphaSrc = GL_ZERO,
    AlphaDst = GL_ONE_MINUS_SRC_ALPHA

    Vous pouvez utiliser n'importe quelle géométrie avec n'importe quelle texture, en commençant le nettoyage à partir de la couche dont vous aurez besoin:

  2. La disparition en douceur du champ se fait de façon similaire. Le prix d'émission est d'un DrawCall.
  3. :


    , UI, . , «» , , « », . , : , . :

    ColorSrc = GL_SRC_ALPHA,
    ColorDst = GL_ONE_MINUS_SRC_ALPHA,
    AlphaSrc = GL_ZERO,
    AlphaDst = GL_ONE
  4. , :


  5. «»:



    . , . — 2 DrawCalls.



Ambient occlusion





Il y a un inconvénient, ou plutôt des restrictions: tous les mélanges ne peuvent pas être répétés pour une telle technique. Le mélange alpha et l'additif sont certainement possibles, mais vous devez adapter ou ne pas utiliser vos propres mélanges spéciaux. Mais il existe une issue: vous pouvez séparer les étapes du rendu de la scène. Une partie devrait être faite par la méthode inverse, une partie est la méthode habituelle, et c'est ce que nous avons fait pour les effets spéciaux sur le terrain et après le processus.

Un point important avec les techniques de rendu additif et mixte: s'il est dessiné AVANT le passage de rendu inverse, et s'il n'y a aucune information de transparence dans la texture (texture comme "tache blanche sur fond noir"), alors un tel objet écrasera la transparence. Dans le passage «retour», les informations sur cette zone seront perdues et visuellement, elles ressembleront à un «carré sombre» ou à une bordure noire autour d'un point additif léger:


Cela peut être surmonté en modifiant le mélange additif en termes de mélange du canal alpha:

AlphaSrc = GL_ONE_MINUS_DST_ALPHA
AlphaDst = GL_ONE

Mais cela ne convient pas à tous les types de mélange, et il sera plus fiable de modifier la texture elle-même. Signification:

s'il existe des textures du formulaire: 


Ensuite, vous devez faire l'un d'eux:


C'est-à-dire que la luminosité des canaux de couleur doit être convertie en transparence et étirer les couleurs inversement avec la transparence. La texture résultante et ancienne doit être identique sur un fond noir. Manuellement, il est peu probable que cela réussisse, il est logique de faire un convertisseur automatique. Dans ce cas, le pseudo-code de conversion de canal ressemblera à ceci:

RGB_old = Texel_in.rgb
A_old = Texel_in.a
A_middle = 1.0 / ((RGB_old) / 3.0) * A_old // linear color space
RGB_new = RGB_old * A_middle;
A_shift = minimum( 1.0 / RGB_new.r, 1.0)
A_shift = minimum( 1.0 / RGB_new.g, A_shift)
A_shift = minimum( 1.0 / RGB_new.b, A_shift)
RGB_result = RGB_new * A_shift; 
A_result = (RGB_result) / 3.0)
Texel_out = Vector4(RGB_result, A_result)



Ici, je vais passer par les étapes de rendu de la scène de notre projet
 
  1. . , -.

  2. , , , «» :


  3. UI:

  4. , , , :

  5. :

  6. :

  7. , .




Conclusion


La méthode permet de travailler assez simplement et à moindre coût avec des couches de la scène en cours de dessin, en utilisant le canal alpha comme masque. Il est relativement simple de l'implémenter dans un projet déjà en marche: il ne nécessite pas de modification profonde du code du sous-système graphique, il suffit de changer l'ordre de rendu et la formule de mixage. Par endroits, il peut considérablement réduire les performances. Il y a des limites, mais dans la plupart des cas, vous pouvez les accepter.

Source: https://habr.com/ru/post/undefined/


All Articles