Fonctionnement de la composition alpha

image

La transparence peut ne pas sembler être un sujet intéressant. Le format GIF, qui permettait à certains pixels de briller à l'arrière-plan, a été publié il y a plus de 30 ans. Presque toutes les applications de conception graphique publiées au cours des deux dernières décennies prennent en charge la création de contenu translucide. Ces concepts ont depuis longtemps cessé d'être quelque chose de nouveau.

Dans mon article, je veux montrer qu'en fait, la transparence dans les images numériques est beaucoup plus intéressante qu'il n'y paraît - dans ce que nous tenons pour acquis, il y a une profondeur et une beauté invisibles.

L'opacité


Si vous avez déjà regardé à travers des lunettes roses, vous pouvez voir quelque chose de similaire à ce qui est illustré dans la figure ci-dessous. [Dans l'article d'origine, de nombreuses images sont interactives.] Essayez de déplacer les lunettes pour voir comment elles affectent ce qui est visible à travers elles:


Ces lunettes fonctionnent comme suit: il leur manque beaucoup de rouge, une quantité décente de bleu et très peu de vert. Les mathématiques de ces points peuvent être écrites dans un ensemble de trois équations. La lettre R indique le résultat de l'opération, et la lettre D décrit le point que nous regardons. Les indices RVB indiquent les composantes rouge, verte et bleue:

R R = D R × 1.0
R G = D G × 0.7
R B = D B × 0.9

Ce vitrail transmet les composants rouges, verts et bleus de l'arrière-plan avec des forces variables. En d'autres termes, la transparence des verres roses dépend de la couleur de la lumière incidente. En général, la transparence peut varier en fonction de la longueur d'onde de la lumière , mais dans cet exemple simplifié, nous nous intéressons uniquement à la façon dont les lunettes affectent les composants RVB classiques.

La simulation du comportement des lunettes de soleil ordinaires est beaucoup plus simple, elles atténuent généralement la lumière incidente d'une certaine manière:


Ces verres ne laissent passer que 30% de la lumière. Leur comportement peut être décrit par les équations suivantes:

R R = D R × 0.3
R G = D G × 0.3
R B = D B × 0.3

Les trois composantes de couleur sont réduites de la même valeur - l'absorption de la lumière incidente est la même. On peut dire que les verres noirs sont 30% transparents (opaques) ou 70% opaques. L'opacité d'un objet détermine la quantité de couleur qu'il bloque. En infographie, nous avons généralement affaire à un modèle simplifié dans lequel une seule valeur est nécessaire pour décrire cette propriété. L'opacité peut varier spatialement. comme, par exemple, une colonne de fumée qui devient plus haute et plus transparente.

Dans le monde réel, les objets avec une opacité de 100% sont simplement opaques et ne transmettent pas du tout la lumière. Le monde des images numériques est un peu différent. Il y a des cas limites lorsque même des objets opaques solides passent une certaine quantité de lumière.

Couverture


Les graphiques vectoriels traitent de descriptions claires et infiniment précises de formes définies à l'aide de points, de segments de ligne, de courbes de Bézier et d'autres primitives mathématiques. Lorsque vous devez afficher des figures sur un écran d'ordinateur, ces entités impeccables doivent être pixellisées en un bitmap:


Rastérisation d'une forme vectorielle en bitmap

La façon la plus primitive de pixelliser est de vérifier où se trouve l'échantillon de pixels - à l'intérieur ou à l'extérieur de la forme vectorielle. Dans les exemples ci-dessous, vous pouvez faire glisser le triangle, dans une vue agrandie, les mouvements seront plus précis. Un contour bleu indique la géométrie vectorielle d'origine. Comme vous pouvez le voir, l'échelle sur les bords du triangle a l'air moche et scintille beaucoup lors du déplacement de la géométrie:


L'inconvénient de cette approche est que nous n'effectuons qu'une seule vérification pour chaque pixel affiché, et les résultats sont discrétisés à l'une des deux valeurs possibles - à l'intérieur ou à l'extérieur.

Vous pouvez échantillonner la géométrie vectorielle plusieurs fois par pixel pour obtenir une grande gradation des étapes et décider que certains pixels ne sont que partiellement fermés. Une solution possible consiste à utiliser quatre points d'échantillonnage pour représenter cinq niveaux de couverture: 0, 14 , 24 , 34 et 1:


La qualité des bords du triangle s'est améliorée, mais seulement cinq niveaux de couverture possibles ne sont souvent pas suffisants et nous pouvons facilement obtenir un bien meilleur résultat. Bien que la vue d'un pixel comme un petit carré dans le monde du traitement du signal soit considérée avec désapprobation , dans certains contextes, c'est un modèle utile qui nous permet de calculer la couverture exacte en pixels par géométrie vectorielle. L'intersection d'une ligne et d'un carré peut toujours être décomposée en un trapèze et un rectangle :

image

Un segment de ligne divise un carré en un trapèze et un rectangle

Vous pouvez facilement calculer l'aire des deux parties, et leur somme divisée par l'aire du carré détermine le pourcentage de couverture en pixels. Ainsi, la couverture est calculée comme un nombre exact avec une précision arbitraire. Dans la démonstration ci-dessous, cette méthode est utilisée pour rendre de bien meilleurs bords qui restent lisses même lorsque vous faites glisser un triangle:


Lorsqu'il s'agit de formes plus complexes, par exemple des ellipses ou des Béziers , elles sont souvent divisées en simples segments de ligne droite qui vous permettent de calculer la couverture avec la bonne précision.

Le concept de couverture partielle est essentiel pour un rendu de haute qualité des graphiques vectoriels et, plus important encore, pour le rendu du texte. Si vous prenez une capture d'écran de cet article et l'examinez attentivement, vous remarquerez que presque tous les bords des glyphes ne couvrent que partiellement les pixels:


La couverture partielle est activement utilisée dans le rendu de texte

Ayant l'opacité de l'objet et le couvrant avec des pixels individuels, vous pouvez les combiner en une seule valeur.

Alpha


Le produit de l'opacité d'un objet et de sa couverture en pixels est appelé alpha :

= ×

Un objet avec une opacité de 60%, couvrant 30% de la zone de pixels, a une valeur alpha de 18% dans ce pixel. Naturellement, lorsque l'objet est transparent ou ne couvre pas complètement le pixel, la valeur alpha dans ce pixel est 0. Après multiplication, les différences entre l'opacité et le revêtement disparaissent, ce qui justifie en quelque sorte le fait que les concepts d '"alpha" et "d'opacité" sont utilisés comme synonymes.

Alpha est souvent représenté comme un quatrième canal d'une image bitmap. Les valeurs habituelles de rouge, vert et bleu sont complétées par une valeur alpha, formant quatre valeurs RGBA.

Lorsqu'il s'agit de stocker des valeurs alpha en mémoire, il y a une tentation d'utiliser seulement quelques bits pour cela. Dans le cas du recouvrement des pixels des bords d'objets opaques, il semble que 4 voire 3 bits suffiront, en fonction de la densité de pixels de l'écran:


Cependant, l'opacité affecte également la valeur alpha, de sorte qu'une faible profondeur de bits peut être catastrophique dans certains cas de changement de transparence en douceur. L'image ci-dessous montre un dégradé du noir opaque au blanc, ce qui démontre qu'une faible profondeur de bits entraîne de très fortes variations de couleur:


De toute évidence, plus il y a de bits, mieux c'est, et le plus souvent pour l'alpha, une profondeur de 8 bits est utilisée pour correspondre à la précision des composantes de couleur, c'est pourquoi de nombreux tampons RGBA occupent 32 bits par pixel. Il convient également de noter que, contrairement aux composants de couleur, qui sont souvent codés à l'aide d'une transformation non linéaire, l'alpha est stocké linéairement - la valeur codée de 0,5 correspond à une valeur alpha de 0,5.

En parlant d'alpha, nous avons complètement ignoré toutes les autres composantes de couleur, mais en plus de bloquer la couleur d'arrière-plan, le pixel lui-même peut ajouter un peu de couleur. L'idée est assez simple - un objet rose translucide bloque une partie de l'éclairage de fond entrant et émet ou réfléchit un peu de lumière rose:


Notez qu'il ne se comporte pas comme un vitrail. Le verre bloque simplement une partie de l'éclairage de fond avec une luminosité différente. Si vous regardez un objet complètement noir à travers du verre rose, sa noirceur restera, car l'objet noir n'émet pas et ne réfléchit aucune lumière. Cependant, l'objet rose translucide ajoute sa propre lumière. Si vous le placez sur un objet noir, le résultat sera rosâtre. Un bon analogue de ce comportement est un matériau fin en suspension dans l'air, comme de la brume, de la fumée, du brouillard ou de la poudre colorée.

Le rendu d'un canal alpha est un peu plus difficile - un objet parfaitement transparent est invisible par définition, donc pour distinguer les objets, nous devons utiliser deux astuces. Un arrière-plan en damier montre quelles parties de l'image sont transparentes; Ce modèle est utilisé dans de nombreuses applications graphiques:


Le motif d'échecs montre des pièces transparentes.

Les quatre petits carrés sous l'image nous indiquent que nous voyons les composantes rouge, verte, bleue et alpha de l'image. Dans certains cas, il est utile de voir directement les valeurs du canal alpha, et la façon la plus simple de les afficher consiste à utiliser des nuances de gris:


Afficher les valeurs RVB et A sur différentes surfaces

Plus la nuance de gris est brillante, plus la valeur alpha est élevée, c'est-à-dire que le noir pur correspond à 0% alpha et le blanc pur à 100% alpha. Les petits carrés indiquent que les composants RVB et A de l'image sont divisés en deux parties.

Le composant alpha lui-même n'est pas particulièrement utile, mais il devient très important lorsque nous parlons de compositing.

Compositing simple


Très peu d'effets de rendu 2D peuvent être implémentés en une seule opération, et pour créer un résultat final, nous utilisons un processus de composition qui combine différentes images. Par exemple, un simple bouton «Annuler» peut être créé en composant cinq éléments distincts:


Éléments de composition pour le bouton Annuler

Le compositing est souvent réalisé en plusieurs étapes, à chacune desquelles deux images sont combinées. L'image de premier plan utilisée en compositing est communément appelée source . L'image d'arrière-plan utilisée en compositing, sur laquelle la source est superposée, est généralement appelée destination .

Nous commencerons par composer sur un fond opaque, car c'est un cas très courant. Tout ce que vous voyez à l'écran est finalement superposé par la composition sur une destination opaque.

Lorsque la valeur alpha de la source est de 100%, la source est opaque et doit couvrir complètement la destination. Si la valeur alpha est de 0%, la source est complètement transparente et n'affecte en aucune façon la destination. Une valeur alpha de 25% permet à l'objet d'émettre 25% de sa lumière et passe 75% de la lumière de l'arrière-plan, etc.:


Composition d'une source violette avec différentes valeurs alpha vers une destination jaune

Vous pouvez déjà comprendre ce que tout va faire - un cas simple de composition alpha sur un fond opaque - c'est juste une interpolation linéaire entre les couleurs de destination et source. Dans le graphique ci-dessous, le curseur contrôle la valeur alpha de la source et les graphiques rouge, vert et bleu affichent les valeurs des composants RVB. Le résultat de R est juste un mélange entre la source S et la destination D :


Ce qui se passe ici peut être décrit par les équations ci-dessous. Comme précédemment, l'index dénote le composant, c'est-à-dire que S A est la valeur alpha dans la source et D G est la valeur verte dans la destination:

R R = S R × S A + D R × (1 − S A )

R G = S G × S A + D G × (1 − S A )

R B = S B × S A + D B × (1 − S A )

Les équations des composants rouge, vert et bleu ont la même apparence, vous pouvez donc simplement utiliser l'index RVB et les combiner en une seule ligne:

R RGB = S RGB × S A + D RGB × (1 − S A )

De plus, comme la destination est opaque et bloque déjà toute la lumière de fond, nous savons que la valeur alpha du résultat est toujours 1:

R A = 1

Compositer sur un fond opaque est simple, mais ses capacités sont assez limitées. Dans de nombreux cas, une solution plus fiable est requise.

Tampons intermédiaires


L'image ci-dessous montre le processus en deux étapes de composition de trois couches différentes, étiquetées A, B et C. Le symbole ⇨ signifie "superposé par composition sur":


Le résultat du compositing en deux étapes de trois couches

D'abord, nous superposons B à C en composant, puis superposons A à eux pour obtenir l'image finale. Dans l'exemple suivant, nous ferons les choses un peu différemment. Tout d'abord, nous allons connecter les deux couches supérieures par compositing, puis superposer le résultat sur la dernière destination:


Le résultat du compositing en deux étapes de trois couches dans un ordre différent

Vous vous demandez probablement si une telle situation se présente dans la pratique, mais en fait, elle est très courante. De nombreuses opérations de composition et effets de rendu non triviaux, tels que le masquage et le flou, nécessitent de passer par un tampon intermédiaire contenant uniquement des résultats de composition partiels. Ce concept a des noms différents: passes hors écran, couches de transparence ou tampons latéraux, mais ils sont généralement basés sur la même idée.

Ce qui est plus important pour nous, c'est que presque toutes les images transparentes peuvent être perçues comme le résultat partiel d'un certain rendu, qui sera ensuite superposé par la composition sur la dernière destination:


Compositing partiel d'un bouton dans un presse-papiers

Nous devons comprendre comment remplacer la composition d'images translucides A et B par une image (A⇨B) ayant la même couleur et l'opacité. Commençons par calculer la valeur alpha du tampon final.

Combinaison de valeurs alpha


Vous ne savez peut-être pas comment combiner l'opacité de deux objets, mais il est plus facile de parler de cette tâche si nous parlons plutôt de transparence.

Supposons qu'une certaine quantité de lumière passe à travers le premier objet, puis à travers le deuxième objet. Si la transparence du premier objet est de 80%, il passera alors 80% de la lumière incidente. De même, un deuxième objet avec 60% de transparence permettra à 60% de la lumière de le traverser, ce qui nous donne 60% × 80% = 48% de la lumière d'origine. Vous pouvez expérimenter la transparence dans l'article d'origine; n'oubliez pas que les curseurs contrôlent la transparence et non l'opacité des objets sur le chemin de la lumière:


Naturellement, lorsque le premier ou le deuxième objet est opaque, aucune lumière ne les traverse, même un autre est complètement transparent.

Si l'objet D a la transparence D T , et l'objet S a la transparence S T , alors la transparence générale finale R T de ces deux objets est égale à leur produit:

R T = D T × S T

Cependant, la transparence est juste une unité moins alpha, donc la substitution nous donne ce qui suit:

1 - R A = (1 - D A ) × (1 - S A )

Cette expression peut être développée en:

1 - R A = 1 - D A - S A + D A × S A

Et simplifiez comme ceci:

R A = D A + S A - D A × S A

Il peut être réduit à l'un des deux types similaires:

R A = S A + D A × (1 - S A )

R A = D A + S A × (1 - D A )

Bientôt, nous verrons que le second est le plus souvent utilisé. Il est également intéressant de noter que la valeur alpha résultante ne dépend pas de l'ordre relatif des objets - l'opacité des pixels résultants est la même, même si vous échangez la source et la destination. C'est très logique. La lumière traversant deux objets devrait s'estomper de la même manière, de n'importe quel côté de l'étoile, de l'avant ou de l'arrière.

Combinaison de couleurs


Le calcul de l'alpha n'a pas été si difficile, alors essayons de comprendre les calculs des composants RVB. L'image source a la couleur S RGB , mais son opacité S A force uniquement le produit de ces deux valeurs à prendre en compte dans le résultat final:

S RVB × S A

L'image de destination a la couleur D RGB , l'opacité lui fait émettre de la lumière D RGB × D A , cependant, une partie de la lumière est bloquée par l'opacité de l'image S, donc tout l'effet de destination est

D RVB × D A × (1 - S A )

L'apport total de lumière de S et D est égal à leur somme:

S RVB × S A + D RVB × D A × (1 - S A )

De même, la contribution des couches fusionnées est égale à leur couleur multipliée par leur opacité:

R RVB × R A

Nous voulons que ces deux valeurs correspondent:

R RGB × R A = S RGB × S A + D RGB × D A × (1 - S A )

Ce qui nous donne les équations finales:

R A = S A + D A × (1 - S A )

R RGB = (S RGB × S A + D RGB × D A × (1 - S A )) / R A

Voyez comme la deuxième équation est compliquée! Notez que pour obtenir les valeurs RVB du résultat, nous devons diviser par la valeur alpha. Cependant, pour la prochaine étape de la compositine, la multiplication par la valeur alpha sera à nouveau nécessaire, car le résultat de l'opération en cours deviendra la nouvelle source ou destination de la prochaine opération. C'est tout simplement moche.

Revenons à la forme presque finale de R RGB pendant une seconde:

R RGB × R A = S RGB × S A + D RGB × D A × (1 - S A )

La source, la destination et le résultat sont multipliés par leurs composants alpha. Cela nous fait comprendre que la couleur et l'alpha du pixel «aiment» être ensemble, nous devons donc prendre du recul et repenser la façon dont nous stockons les informations sur les couleurs.

Alpha prémultiplié


Rappelons que nous avons parlé d'opacité - si l'objet est partiellement opaque, sa contribution au résultat sera également partielle. Le concept d'alpha prémultiplié («pré-multiplication par alpha») met en œuvre cette idée. Les valeurs des composants RVB, comme leur nom l'indique, sont pré-multipliées par le composant alpha. Commençons par la couleur sans multiplication préalable:

(1,00, 0,80, 0,30, 0,40)

La multiplication préliminaire par alpha nous donne ce qui suit:

(0,40, 0,32, 0,12, 0,40)

Jetons un coup d'œil à plusieurs pixels à la fois. La figure ci-dessous montre comment les informations de couleur sont stockées sans multiplier d'abord l'alpha:


Informations RVB et A dans l'image sans multiplication préalable

Notez que les zones où alpha est 0 peuvent avoir des valeurs RVB arbitraires, comme le montrent les pépins vert et bleu de l'image. Dans le cas d'une multiplication préliminaire par alpha, les informations de couleur stockent également les valeurs d'opacité des pixels:


Informations RVB et A dans une image pré-multipliée

L'alpha prémultiplié est parfois appelé alpha associé, et l'alpha non prémultiplié est parfois appelé alpha droit ou non associé.

Lorsque le composant alpha de la couleur est 0, la multiplication préliminaire réinitialise tous les autres composants, quelles que soient leurs valeurs:

(0,0, 0,0, 0,0, 0,0)

Dans le cas de l'alpha prémultiplié, il n'y a qu'une seule couleur complètement transparente, et c'est charmant.

Les avantages de ce traitement des composants de couleur deviendront progressivement clairs pour vous, mais avant de revenir à l'exemple de la composition, voyons comment l'alpha prémultiplié aide à résoudre certains autres problèmes de rendu.

Filtrage


Le flou gaussien est un moyen populaire de créer un arrière-plan défocalisé intéressant ou de réduire la fréquence élevée de l' arrière - plan du contenu de certains éléments de l'interface utilisateur. Comme nous le verrons, la pré-multiplication de l'alpha est essentielle pour créer le flou parfait.

L'image que nous analyserons est créée en remplissant l'arrière-plan avec 1% de bleu opaque, sur lequel un cercle rouge opaque est dessiné. Voyons d'abord un exemple sans multiplication préalable. J'ai séparé les canaux RVB du canal alpha pour comprendre ce qui se passait. La flèche indique l'opération de flou:


Flou du contenu sans multiplication préalable

Le résultat final a un laid halo bleu. Cela s'est produit parce que le fond bleu s'est infiltré dans la zone rouge pendant le flou, et seulement ensuite , pendant le compositing, le poids alpha y a été ajouté.

Lorsque les couleurs sont pré-multipliées par alpha, le résultat est correct:


Flou du contenu pré-multiplié

En raison de la pré-multiplication, la couleur bleue de l'image est réduite à 1% de sa force d'origine, de sorte que son effet sur les couleurs du cercle flou est extrêmement faible.

Interpolation


Le rendu d'une image dont les pixels correspondent parfaitement à la destination est une tâche simple car nous devons effectuer un mappage univoque trivial entre les échantillons. Un problème survient lorsqu'il n'y a pas de mappage simple, par exemple, en raison de la rotation, de la mise à l'échelle ou de la césure. La figure ci-dessous montre que les pixels de l'image pivotée indiqués par le contour rouge ne correspondent plus à la destination:


Orientation relative de l'image et pixels de destination avant et après rotation

Il existe de nombreuses façons de sélectionner une couleur de l'image à écrire sur le pixel de destination, et la plus simple d'entre elles est l'interpolation dite du plus proche voisin, dans laquelle comme pixel final, l'échantillon le plus proche dans la texture est simplement sélectionné.

Dans la démonstration ci-dessous, le contour rouge montre la position de l'image dans la destination. Le côté droit montre les positions des échantillons du point de vue de l' image . En faisant glisser le curseur (dans l'article d'origine), vous pouvez faire pivoter le quadrilatère et observer comment les échantillons sélectionnent les couleurs du bitmap. J'ai mis en évidence un pixel dans la source et la destination, afin que leur relation soit plus claire:


Cette solution est assez fonctionnelle et les pixels ont une couleur holistique, mais la qualité est inacceptable. Il serait préférable d'utiliser une interpolation bilinéaire , qui calcule la moyenne pondérée des quatre pixels les plus proches de l'image échantillonnée:


Cela fonctionne mieux, mais les bords autour des rectangles ne semblent pas corrects, le contenu des pixels fusionne sans multiplication, car l'alpha est "appliqué" après l'interpolation. Parfois, la solution recommandée pour fusionner la couleur du bon contenu, qui est montrée dans l' article étonnant d' Adrian Correger [ traduction sur Habré], est loin d'être idéale - pas une seule couleur dans l'espace entre les rectangles rouges et bleus ne semblera droite.

Voyons à quoi tout ressemblera dans l’image avec de l’alpha prémultiplié et du compositing avec une formule avancée, que nous allons bientôt dériver:


Tout simplement parfait - nous nous sommes débarrassés de toutes les fusions de couleurs et les dents sont introuvables .

En fin de compte, les problèmes associés au flou et à l'interpolation sont étroitement liés. Toute opération qui nécessite une combinaison de couleurs translucides, sans d'abord multiplier les couleurs par alpha, est susceptible de donner des résultats incorrects.

Le bon compositing


Revenons au compositing. Nous nous sommes installés sur une équation presque dérivée:

R RGB × R A = S RGB × S A + D RGB × D A × (1 - S A )

Si vous imaginez des couleurs utilisant l'alpha prémultiplié, toutes ces multiplications inconfortables disparaîtront, car l'alpha fera déjà partie des valeurs de couleur. Ensuite, nous obtenons ce qui suit:

R RGB = S RGB + D RGB × (1 - S A )

Regardons l'équation alpha:

R A = S A + D A × (1 - S A )

Les coefficients pour les canaux rouge, vert, bleu et alpha sont les mêmes, nous pouvons donc exprimer l'expression entière avec une équation et nous rappeler juste que chaque composant subit la même opération:

R = S + D × (1 - S A )

Découvrez comment l'alpha prémultiplié a facilité les choses. Lorsque nous analysons les composants de l'équation, ils sont tous en place. L'opération masque une partie de la lumière d'arrière-plan et ajoute une nouvelle lumière:

R = S + D × (1 - S A )

Cette opération de mixage est appelée source over, sover ou tout simplement normale, et c'est sans aucun doute le mode de composition le plus courant. Presque tout ce que vous voyez sur mon site Web est mélangé dans ce mode.

Associativité


Une propriété source-over importante réalisée sur des couleurs pré-alpha-multipliées est l' associativité de cette opération. Grâce à lui, dans l'équation de mélange complexe, nous pouvons placer les parenthèses de manière complètement arbitraire. Toutes les compositions présentées ci-dessous sont équivalentes:

R = (((A⇨B) ⇨C) ⇨D) ⇨E

R = (A⇨B) ⇨ (C⇨ (D⇨E))

R = A⇨ (B⇨ (C⇨ (D⇨E)) )

La preuve en est assez simple, mais je ne vous encombrerai pas de manipulations algébriques. Dans la pratique, cela signifie que nous pouvons rendre partiellement des dessins complexes sans craindre que la composition finale soit incorrecte.

Dans la grande majorité des cas, l'alpha n'est utilisé que pour la composition en utilisant la source-over, mais ses avantages ne s'arrêtent pas là. Les valeurs alpha peuvent également être utilisées pour d'autres opérations de rendu utiles.

Porter-Duff Compositing


En juillet 1984, Thomas Porter et Tom Duff ont publié l'article original, «Compositing Digital Images» . Les auteurs ont non seulement introduit le concept d'alpha prémultiplié et dérivé de l'équation de composition source sur over, mais ont également présenté toute une famille d'opérations de composition alpha, dont beaucoup sont peu connues, bien que très utiles. Les nouvelles fonctions sont également appelées opérateurs , car, comme l'ajout ou la multiplication, elles effectuent des actions sur les valeurs d'entrée pour créer une valeur de sortie.

Plus


Dans de futurs exemples, nous utiliserons des démos interactives montrant les opérations de divers modes de fusion. L'image de destination sera le symbole «club» noir et l'image source sera le symbole «vers» rouge. Vous pouvez faire glisser le cœur sur l'image et observer le comportement des formes qui se chevauchent sous différents opérateurs de composition. Faites attention à la petite minicarte dans le coin. Certains modes de fusion sont très destructeurs et faciles à confondre. La mini-carte montre toujours le résultat d'un simple compositing source-over, ce qui simplifie la compréhension:


R = S + D × (1 - S A )

R = S × (1 - D A ) + D

Si vous passez à destination-over, vous vous rendrez immédiatement compte qu'il «retourne» simplement la source-over - destination et source sont échangées dans l'équation et le résultat est équivalent à ce que nous considérerons comme destination comme image source. Bien qu'il semble redondant, l'opérateur destination-over est extrêmement utile car il vous permet de composer des objets qui se trouvent sous un contenu existant.

Out


Les instructions source-out et destination-out sont idéales pour percer des trous dans la source ou la destination:


R = S × (1 - D A )

R = D × (1 - S A )

Parmi ces deux opérateurs, Destination-out est plus pratique car il utilise le canal alpha pour percer des trous dans le formulaire de destination.

Dans


Les opérateurs source-in et destination-in sont essentiellement des opérateurs de masquage:


R = S × D A

R = D × S A

Ils permettent de créer assez facilement des intersections complexes de géométrie non triviale sans résoudre les intersections relativement difficiles à calculer des contours vectoriels.

Au sommet


Les opérateurs source-atopet destination-atopvous permettent de superposer du nouveau contenu sur ceux existants, tout en le masquant le long du chemin de destination:


R = S × D A + D × (1 - S A )

R = S × (1 - D A ) + D × S A

Xor


L'opérateur OU exclusif ( xor) enregistre la source ou la destination, et leurs zones correspondantes disparaissent:


R = S × (1 - D A ) + D × (1 - S A )

Source, destination, effacer


Les trois derniers modes de composition classiques sont assez ennuyeux. Source, également appelé copy, prend simplement la source de couleur. De même, il destinationignore la source de couleur et revient simplement destination. L'opérateur clearefface simplement tout:


R = S

R = D

R = 0

L'applicabilité de ces modes est limitée. En l'utilisant clear, vous pouvez vider un tampon rempli, mais cette opération peut être optimisée en remplissant simplement la mémoire avec des zéros. De plus, dans certains cas, il source peut être plus économique dans les calculs, car il ne nécessite aucun mélange, mais remplace simplement le contenu du tampon par les informations source.

Porter Duff en action


Après avoir traité avec des opérateurs individuels, voyons comment vous pouvez les combiner. Dans l'exemple ci-dessous, nous allons dessiner un logo marin sans utiliser de masquage ou de formes géométriques complexes. Les contours bleus montrent la géométrie simple en cours de création. Vous pouvez parcourir les étapes en cliquant sur le côté droit de l'image, et revenir en arrière en cliquant sur la gauche:


Bien sûr, nous ne sommes en aucun cas obligés d'abandonner les masques et les contours de découpe, mais nous oublions souvent un outil comme les modes de composition Porter-Duff, bien qu'il soit beaucoup plus facile de créer des effets visuels avec leur aide.

Les opérateurs


Si vous regardez attentivement les opérateurs Porter-Duff, vous remarquerez qu'ils ont tous le même formulaire. La source est toujours multipliée par un certain coefficient F S et ajoutée à la destination multipliée par un coefficient F D :

R = S × F S + D × F D

F S peut prendre les valeurs 0, 1, D A + 1 - D A , F et D peuvent être égales à 0, 1, S A ou 1 - S A . Cela n'a aucun sens de multiplier la source ou la destination par leur propre alpha, car ils sont déjà pré-multipliés, et nous obtenons juste l'effet fantaisiste, mais pas très utile, de l'alpha quadratique. Tous les opérateurs peuvent être représentés sous la forme d'un tableau:

01D A1 - D A
0clairsourcesource-insource-out
1destinationdestination
S Adestinationdestination au sommet
1 - S Adestination-outsource-oversource-au sommetxor

Faites attention à la symétrie des opérateurs sur la diagonale. Les quatre éléments centraux du tableau sont manquants et c'est arrivé parce qu'ils sont différents des autres.

Éclairage additif


Dans son article, Porter et Duff a présenté un autre opérateur, dans lequel les deux F S et F D égal à 1. Il est connu sous le nom plus, lighteret plus-lighter:

R = S + D

Cette opération ajoute essentiellement un éclairage source à la destination:


L'éclairage additif mis en œuvre avec l'opérateurplus

Vert et rouge forme correctement le jaune, tandis que le vert et le bleu forment le cyan. Le noir est l'absence d'opération; il ne change en rien les valeurs de couleur, car l'ajout de zéro à un nombre ne change rien.

Les trois opérateurs restants n'ont pas reçu de nom car ils ne sont pas particulièrement utiles. Ils sont juste une combinaison de masquage et de mélange.

Il convient également de noter que l'alpha prémultiplié nous permet d'utiliser l'opérateur de source-overmanière inattendue. Jetons à nouveau un coup d'oeil à l'équation:

R = S + D × (1 - S A )

Si nous parvenons à rendre la valeur alpha de la source égale à zéro, alors s'il y a des valeurs non nulles dans les canaux RVB, nous pouvons obtenir un éclairage additif sans utiliser l'opérateur plus:


Éclairage additif implémenté à l'aide de l'opérateursource-over

Notez que vous devez faire attention ici - les valeurs ne sont plus correctement multipliées par alpha. Dans certains programmes, il peut y avoir une optimisation qui évite complètement de mélanger les couleurs avec zéro alpha, tandis que d'autres programmes peuvent inverser la pré-multiplication par des valeurs alpha, effectuer certaines opérations de couleur, puis pré-multiplier à nouveau par alpha, ce qui détruit complètement les canaux de couleur. Il peut également être difficile d'exporter des ressources dans ce format, donc si vous n'avez pas un contrôle total sur le pipeline de rendu, vous devez vous en tenir à l'opérateur plus.

Jusqu'à présent, tous les éléments dont nous discutons ont été bien combinés. Maintenant, retirons nos lunettes roses et discutons de certaines questions qui doivent être prises en compte lors de l'utilisation de la composition alpha.

Opacité du groupe


Jetons un coup d'œil à ce dessin de pilule simple composé de seulement six primitives:


Dessiner une pilule à l'aide de formes simples

Si on nous demandait de rendre une pilule avec une opacité de 50%, nous pourrions être tentés de simplement diviser l'opacité en deux à chaque opération de dessin, mais cela se révélerait être une décision erronée:


Résultat inattendu du rendu d'une pilule avec une demi-opacité.

Pour obtenir le résultat correct, nous ne pouvons pas simplement répartir l'opacité d'un objet sur chacun de ses composants individuels. Il faut d' abord créer un objet pour le rendre dans un bitmap, et seulement ensuite modifier l'opacité du bitmap, et à la fin de compositing effectuer:


Résultat attendu du rendu d'une pilule avec une demi-opacité

Il s'agit d'un autre cas qui démontre l'utilité du concept de rendu dans un tampon latéral.

Couverture de compositing


La conversion d'une couverture géométrique en une seule valeur alpha a des conséquences inconfortables. Considérons le cas où deux bords parfaitement adaptés de figures de géométrie vectorielle, illustrés dans la figure ci-dessous avec des contours orange et bleu, sont rendus dans une image bitmap. Dans un monde idéal, les résultats devraient ressembler à ceci, car chaque pixel est complètement fermé:


Un résultat de rendu idéal avec une couverture correcte.

Cependant, si nous rendons d'abord la géométrie orange puis le bleu, puis dans l'image finale un petit fond blanc fuira toujours dans les pixels de la bordure:


Le résultat d'un compositing en deux étapes

Dès que le revêtement est stocké dans le canal alpha, toutes ses informations géométriques sont perdues, et nous ne pouvons en aucun cas les restaurer. La géométrie bleue se mélange simplement avec une partie du contenu du tampon, mais ne sait pas que la géométrie représentée par les pixels rougeâtres doit y correspondre. Ce problème est particulièrement visible lorsque les géométries sont précisément superposées les unes aux autres. Dans l'image ci-dessous, un cercle blanc est dessiné au-dessus d'un noir. Les bords sombres sont visibles, bien que les deux cercles aient exactement le même rayon et la même position:


Un cercle blanc dessiné au-dessus d'un cercle noir

Une façon de résoudre ce problème est de ne pas calculer la couverture partielle des pixels et d'utiliser des tampons beaucoup plus grands. En pixellisant la géométrie vectorielle avec un simple revêtement d'entrée / sortie, puis en réduisant l'échelle du résultat à la taille de l'image d'origine, vous pouvez obtenir le résultat attendu.

Cependant, pour une comparaison parfaite de la qualité de rendu des bords du canal alpha 8 bits, les tampons doivent être 256 fois plus grands dans les deux sens, c'est-à-dire que le nombre de pixels doit augmenter de 2 16fois. Comme nous l'avons vu ci-dessus, tout en réduisant la profondeur de bits pour les valeurs de couverture, vous pouvez toujours obtenir des résultats satisfaisants, donc en pratique, vous pouvez utiliser une échelle plus petite.

Il convient également de noter que de tels problèmes peuvent souvent être évités relativement facilement sans l'utilisation d'énormes bitmaps. Par exemple, au lieu de dessiner deux cercles superposés, vous pouvez simplement dessiner deux carrés l'un sur l'autre, puis masquer le résultat pour former un cercle.

Valeurs linéaires


Si vous avez actualisé vos connaissances sur les espaces colorimétriques , vous vous souvenez que la plupart d'entre eux codent les valeurs chromatiques de manière non linéaire et qu'une linéarisation préliminaire est nécessaire pour effectuer les opérations mathématiques correctes. Une fois cette étape terminée, le résultat du compositing est le suivant; attention à la belle teinte jaunâtre des pièces superposées les unes aux autres:


Cercles rouges flous superposés par compositing sur un fond vert à l'aide de valeurs linéaires

, mais dans la plupart des cas, la compositing ne l' est pas . La méthode standard pour le Web et la plupart des logiciels graphiques consiste à mélanger directement des valeurs non linéaires:


Cercles rouges flous superposés par un compositeur sur un fond vert en utilisant des valeurs non linéaires

Notez que les zones où le rouge sur le vert se superposent sont beaucoup plus sombres. Ils sont loin d'être idéaux, mais dans certains cas, des opérations incorrectes sont profondément enracinées dans la compréhension de la façon dont nous percevons la couleur. Par exemple, le gris opaque à 50% de l'espace sRGB ressemble exactement au noir pur avec une opacité de 50% mélangée à un fond blanc:


Composition de deux couleurs sur un fond blanc sans linéarisation

Dans la figure ci-dessous, les couleurs sRGB des images source et de destination sont linéarisées puis reconverties en encodage non linéaire pour l'affichage. Voici à quoi devraient ressembler ces couleurs:


Composition de deux couleurs sur fond blanc avec linéarisation

Nous avons un écart qui ne correspond pas à nos attentes. La seule façon d'obtenir l'uniformité visuelle à l'aide de cette méthode est de sélectionner toutes les couleurs à l'aide de valeurs linéaires, mais cela est très différent de ce à quoi tout le monde est habitué. 50% de gris avec des valeurs linéaires ressemble à du gris sur 73,5% de l'espace sRGB.

De plus, vous devez être particulièrement prudent lorsque vous travaillez avec un alpha prémultiplié. La pré-multiplication doit être effectuée avec des valeurs linéaires , c'est-à-dire avant de coder en non linéaire. Pour cette raison, l'étape de linéarisation se terminera correctement avec les valeurs linéaires correctes, précédemment multipliées par alpha.

Profondeur Alpha et Bit prémultipliée


Malgré sa grande utilité pour la composition, le filtrage et l'interpolation, l'alpha prémultiplié n'est pas une «solution miracle» et a ses inconvénients. Le plus sérieux d'entre eux est la réduction de la profondeur de bits des couleurs imaginables. Imaginez un encodage 8 bits d'une valeur de 150, qui est pré-multiplié par alpha 20%. Après une multiplication préliminaire par alpha, on obtient

rond (150 × 0,2) = 30

Si nous répétons la même procédure avec une valeur de 151, nous obtenons:

rond (151 × 0,2) = 30

La valeur codée sera la même, malgré la différence des valeurs initiales. En fait, après multiplication par alpha, les valeurs de 148, 149, 150, 151 et 152 sont codées en 30, et la différence d'origine entre ces cinq couleurs uniques est perdue:


La pré-multiplication par alpha de 20% réduit les différentes valeurs de 8 bits à

1. Naturellement, plus l'alpha est petit, plus son effet est destructeur. Sur la plage possible de 256 4 (environ 4,3 milliards) de diverses combinaisons de valeurs RGBA 8 bits, après multiplication préliminaire par alpha, seulement 25,2% conservent une représentation unique; en fait, nous perdons près de 2 bits de la plage 32 bits.

Pour convertir les couleurs entre différents espaces colorimétriques, il est parfois nécessaire d'inverser la multiplication préliminaire, c'est-à-dire de diviser les valeurs dans le composant alpha pour obtenir la luminosité des couleurs d'origine. Cette étape est nécessaire car, comme mentionné ci-dessus, le codage est effectué de manière non linéaire. L'existence d'une pré-multiplication réduit la précision de la représentation des couleurs et les conversions entre les espaces colorimétriques peuvent être imparfaites.

En pratique, la réduction de la profondeur de bits est rarement importante, en particulier dans la composition. Plus la valeur alpha est faible, moins la couleur est visible et moins elle a d'influence sur la composition. En fin de compte, si vous vous efforcez de réaliser des opérations chromatiques précises, vous n'utiliserez pas leur représentation 8 bits - à cette fin, les formats sont beaucoup mieux adaptésvirgule flottante .

Lecture complémentaire


Le concept du canal alpha a été créé par les co-fondateurs du studio Pixar Elvy Smith et Ed Catmell . L'article de Smith «Alpha et l'histoire de la composition numérique» décrit l'histoire de l'invention et les sources du nom «alpha», ainsi que la façon dont ces concepts ont évolué et ont progressivement remplacé le concept de masques dans la production cinématographique .

Pour comprendre le sens de l'alpha, je vous recommande fortement de lire «Interpreting Alpha» d' Andrew Glassner . Cet article fournit une dérivation mathématique rigoureuse mais très accessible de l'alpha comme mesure de l'interaction entre l'opacité et la couverture.

Une discussion détaillée de l'alpha prémultiplié peut être explorée dans«Les GPU préfèrent la prémultiplication» par Eric Haines. L'article fournit non seulement un excellent aperçu des problèmes causés par le manque de multiplication préliminaire, en particulier dans le rendu 3D, mais fournit également des liens vers de nombreux autres articles sur ce sujet.

En conclusion


Initialement, cet article était destiné à expliquer les opérateurs de composition de Porter-Duff, mais tous les autres concepts liés à la composition alpha se sont avérés si intéressants que je ne pouvais pas les manquer.

Ce que j'aime le plus à propos de l'alpha, c'est que c'est juste un nombre supplémentaire qui accompagne les composants RVB, mais en même temps, il crée de nombreuses capacités de rendu uniques. Alpha a littéralement créé un nouveau changement d'opportunité dans l'ancien monde ennuyeux de la composition et du rendu 2D.

La prochaine fois que vous verrez les bords lisses des formes vectorielles ou remarquerez une superposition sombre qui assombrit certaines parties de l'interface utilisateur, pensez à un composant petit mais puissant qui a rendu tout cela possible.

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


All Articles