Forums Développement Multimédia

Aller au contenu

[Résolu] Stage3D: Problème avec texture transparente

CODE Actionscript

11 réponses à ce sujet

#1 lilive

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 2993 messages

Posté 05 November 2011 - 18:12 PM

Bonjour,
Quelqu'un arrive à faire des textures transparentes avec AGAL?

Mon essai:

// Image transparente
var textureBD:BitmapData =  new BitmapData(textureW, textureH, true, 0x00000000);
// Ajout d'un point rouge au milieu
textureBD.setPixel32(textureW >> 1, textureH >> 1, 0xFFFF0000);

var texture:Texture = _context3D.createTexture(textureW, textureH, Context3DTextureFormat.BGRA, false);
texture.uploadFromBitmapData(textureBD);

// Les shaders
var vertexShaderAssembler : AGALMiniAssembler = new AGALMiniAssembler();
vertexShaderAssembler.assemble(
        Context3DProgramType.VERTEX,
        "m44 op, va0, vc0\n" + // pos to clipspace
        "mov v0, va1" // copy uv
);
var fragmentShaderAssembler : AGALMiniAssembler = new AGALMiniAssembler();
fragmentShaderAssembler.assemble(
        Context3DProgramType.FRAGMENT,
        "tex oc, v0, fs0 <2d,linear, nomip>"
);

Résultat: je vois bien le point rouge au milieu de la texture, mais autour c'est du noir, alors que j'attendais des pixels transparents.

Merci pour les conseils.

#2 lilive

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 2993 messages

Posté 05 November 2011 - 18:37 PM

Bon ben j'ai trouvé, il me manquait:
_context3D.setBlendFactors(Context3DBlendFactor.SOURCE_ALPHA, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA);

J'ai trouvé en regardant le code de la classe Image de Starling.

#3 Jean-Marc Le Roux

    Ceinture Noire

  • Minko
  • PipPipPipPipPipPipPip
  • 210 messages

Posté 25 November 2011 - 03:24 AM

Attention, les problèmes de blending sont malheureusement très contraignants et il ne suffit pas d'utiliser la bonne équation de blending pour avoir des objets transparents dessinés correctement à l'écran. Tu pourras trouver plus de détails dans ce post.

a+

#4 lilive

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 2993 messages

Posté 25 November 2011 - 13:40 PM

Oui merci, j'avais vu (j'ai posté dans cette discussion d'ailleurs).
J'aurais pu mettre à jour cette discussion depuis que j'ai avancé. C'est chose faite grâce à ton intervention.

#5 lilive

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 2993 messages

Posté 09 December 2011 - 16:29 PM

Je croyais en avoir fini avec ma compréhension de la gestion de la transparence, mais apparemment non.

J'utilise un BitmapData transparent comme texture.
En haut à gauche j'affiche 2 fois ce bitmap, légèrement décalé, sous forme de flash.display.Bitmap
A côté, j'affiche 2 fois la texture avec Stage3D, avec un seul drawTriangles.
Je ne vois pas comment me débarrasser du halo noir. J'aimerais que le rendu Stage3D soit le même que celui de la display list.
Image attachée: test.png

Voici les extraits du code:

var textureBD:BitmapData =  new BitmapData(textureW, textureH, true, 0x00000000);
// dessin dans textureBD [...]


// Affichage dans la display list
addChild(new Bitmap(textureBD));
var b:Bitmap = new Bitmap(textureBD);
b.x = 50;
b.y = 50;
addChild(<img src='http://forums.mediabox.fr/public/style_emoticons/<#EMO_DIR#>/cool.png' class='bbc_emoticon' alt='B)' />;


// Affichage avec Stage3D

var texture:Texture = _context3D.createTexture(textureW, textureH, Context3DTextureFormat.BGRA, false);
texture.uploadFromBitmapData(textureBD);
// [...]

var vertexShaderAssembler : AGALMiniAssembler = new AGALMiniAssembler();
vertexShaderAssembler.assemble(
        Context3DProgramType.VERTEX,
        "m44 op, va0, vc0\n" + // pos to clipspace
        "mov v0, va1" // copy uv
);
var fragmentShaderAssembler : AGALMiniAssembler = new AGALMiniAssembler();
fragmentShaderAssembler.assemble(
        Context3DProgramType.FRAGMENT,
        "tex oc, v0, fs0 <2d,linear, nomip>"
);
// [...]

_context3D.setBlendFactors(Context3DBlendFactor.SOURCE_ALPHA, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA);
// [...]

_context3D.clear ( 1, 1, 1, 1 );
// un seul appel de drawTriangles, les 4 triangles nécessaires au rendu des 2 ronds sont inclus
_context3D.drawTriangles(_indexBuffer);
_context3D.present();
 

Il y a quelque chose que je ne comprends pas au niveau du calcul des couleurs.
Dans la doc de Context3DBlendFactor on trouve ceci:

Purpose   Source factor   Destination factor       Blend formula                                                                                                        Result
Alpha    SOURCE_ALPHA   ONE_MINUS_SOURCE_ALPHA   (.6,.4,.2,.4) * (.4,.4,.4,.4) + (.8,.8,.8,.5) * (.6,.6,.6,.6)  (.72,.64,.56,.46)
La combinaison SOURCE_ALPHA, ONE_MINUS_SOURCE_ALPHA est suggérée pour avoir un blending en transparence.

Mais si je fais ce calcul pour ajouter un point rouge semi transparent (1, 0, 0, .5) sur un fond blanc opaque (1, 1, 1, 1) cela donne:
(1, 0, 0, .5) * (.5, .5, .5, .5) + (1, 1, 1, 1) * (.5, .5, .5, .5)
= (.5, 0, 0, .25) + (.5, .5, .5, .5)
= (1, .5, .5, .75)
Les couleur 1, .5, .5 me semblent correspondre à ce que j'attendais, mais la transparence est de .75 et pas de 1.
Il y a un problème, non?

Ce qui m'amène à une autre question que je me pose. Ce point (1, .5, .5, .75) va être écrit dans le backbuffer, si je comprends bien, et remplacer le point qui y était présent. Au final je vais donc avoir un point transparent dans le backbuffer. Mais j'ai cru comprendre que les Stage3D ne sont pas transparentes. Que se passe-t'il alors? La donnée alpha est-elle simplement ignorée? Ou alors multiplie-t'elle les valeurs RGB, ce qui expliquerait les halos noir?

Je me suis demandé si faire autant de drawTriangles qu'il y a d'objets pourrait résoudre le problème. Mais non, comme on le voit d'ailleurs, le halo noir étant présent partout, et pas seulement à l'intersection des ronds.

Merci pour tout nouvel élément de réflexion, qui me permettrait d'avoir un vrai blending alpha.


Le code complet: Fichier joint  Main.as   6.25 Ko   58 téléchargement(s)

#6 lilive

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 2993 messages

Posté 09 December 2011 - 18:10 PM

Si j'augmente le rayon du flou appliqué sur le BitmapData, la différence de rendu entre display list et stage3D est encore plus flagrante:


Image attachée: test2.png

La couleur est toute assombrie. Beurk!

#7 lilive

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 2993 messages

Posté 09 December 2011 - 20:59 PM

Bon, je ne sais pas si j'ai résolu le problème dans tous les cas, mais pour cet exemple ça marche:
Image attachée: test3.png

J'ai simplement changé les BlendFactors:
_context3D.setBlendFactors(Context3DBlendFactor.ONE, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA);

Je m'apercevrais peut-être plus tard que ça ne marche pas dans d'autres contextes...

#8 lilive

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 2993 messages

Posté 11 December 2011 - 02:00 AM

En essayant d'utiliser le blendFactor précédent dans une animation plus compliquée j'ai eu des problèmes. Alors en attendant que plus expérimenté ou plus malin que moi se penche sur le sujet, je continue mes essais pour essayer de trouver la formule qui va me permettre d'obtenir de zolis sprites transparents avec Stage3D. Comme je n'y voyais pas bien clair dans la théorie, j'ai codé à la main différentes formules de composition. Voici les résultats en pièce jointe.

Chaque case numérotée est un BitmapData. En 4 couches, initialement teinté en 0xFFFFFFFF, par-dessus lequel sont dessinés successivement un cercle rouge et un cercle bleu. Chaque cercle est un bitmap transparent sur lequel est dessiné la lettre "O", ensuite floutée.

Voici le détail de la génération de chaque case:


Case 1
Les cercles sont ajoutés par un draw(), en BlendMode.NORMAL.
On retrouve bien là le rendu qu'on attend d'une superposition d'images transparentes au-dessus d'un fond uni et opaque


Case 2
Les cercles sont ajoutés en calculant pixel par pixel selon la formule de composition trouvée sur le net (par exemple ici):

RGB0 = RGB1 * A1 + RGB2 * A2 * (1 - A1)
A0 = A1 + A2 * (1 - A1)



- RGB sont les composantes de couleur
- A la composante alpha
- 2 est l'index du bitmap destination avant l'opération d'ajout
- 1 est l'index du bitmap à ajouter au-dessus (un cercle, donc)
- 0 est l'index du bitmap résultant

Je fais cette opération 2 fois, pour chaque pixel de la case. La première fois pour ajouter le cercle rouge sur le fond blanc, la seconde fois pour ajouter le cercle bleu sur le tout.

La case 2 est identique à la case 1, c'est donc cette opération qu'il faut essayer de faire pour reproduire avec Stage3D le rendu 2D habituel de flash.


Case 3
Dans cette case j'essaie de faire ce que je crois que fais Stage3D pour
setBlendFactors(Context3DBlendFactor.SOURCE_ALPHA, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA)

En reprenant les même conventions qu'au-dessus, le calcul est cette fois:

RGB0 = RGB1 * A1 + RGB2 * (1- A1)
A0 = A1 * A1 + A2 * (1 - A1)


Comme je l'avais calculé à la main dans un post précédent, ce qui est bizarre avec cette méthode c'est que l'opacité peut descendre en dessous de 1, comme on le voit bien grâce à la grille que j'ai dessinée en fond.
Le truc que j'aimerais éclaircir, c'est savoir ce qui se passe au final, puisque la Stage3D n'est pas transparente. Que deviennent les pixels transparents? C'est ce que j'ai cherché dans les cases 4 et 5


Case 4
Le bitmapdata 4 est exactement le même que le 3, à la différence près que j'ai rempli la couche alpha avec la valeur 255. On dirait qu'en faisant ceci on retombe sur le rendu des cases 1 et 2. Mais ça ne correspond pas à ce que j'avais observé dans les posts précédents, d'où l'idée de la case 5.


Case 5
Cette fois aussi je repars de la case 3, et je mets la couche alpha à 255. Mais avant de modifier l'alpha, je multiplie chaque composante de couleur par l'alpha. Et là ça me semble correspondre à mes observations précédentes, sur le rendu que j'avais obtenu avec Stage3D et ces blend factors. J'ai donc bien envie de conclure que la couche alpha du backbuffer multiplie les composantes rgb lors du Context3D.present()
Et c'est bien dommage, parce-que tout à l'air assombri, du coup, et il y a ces halos noir disgracieux.


Case 6
Pour tenter de voir ce qui se passe si on utilise
setBlendFactors(Context3DBlendFactor.ONE, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA)
j'ai cette fois utilisé la formule:

RGB0 = RGB1 + RGB2 * (1 - A1)
A0 = A1 + A2 * (1 - A1)


Si tous les pixels sont bien complétement opaques au final, ce qui est bien, on voit un sacré problème à l'intersection des cercles. Donc ce ne serait pas une bonne solution, finalement. Ce qui m'étonne c'est que je ne reconnais pas là le résultat de mon expérience du post précédent. En fait, je commence à me demander si les textures uploadées ne seraient pas par hasard converties en couleurs prémultipliées par l'alpha.


Bon ben je me demande si quelqu'un lira ça un jour Image IPB
En tout cas je souhaite que ça serve, où que ça donne envie de me rejoindre dans mes interrogations (ou encore mieux, de me donner des réponses Image IPB).

Miniature(s) jointe(s)

  • Image attachée: test4.png

Fichier(s) joint(s)



#9 lilive

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 2993 messages

Posté 11 December 2011 - 02:33 AM

Voir le messagelilive, le 11 December 2011 - 02:00 AM, dit :

En fait, je commence à me demander si les textures uploadées ne seraient pas par hasard converties en couleurs prémultipliées par l'alpha.
Oh, bien vu, bravo lilive :)

http://help.adobe.co...itmapData%28%29

Citation

Flash BitmapData objects store colors already multiplied by the alpha component. For example, if the "pure" rgb color components of a pixel are (0x0A, 0x12, 0xBB) and the alpha component is 0x7F (.5), then the pixel is stored in the BitmapData object with the rgba values: (0x05, 0x09, 0x5D, 0x7F). You can set the blend factors so that the colors rendered to the buffer are multiplied by alpha or perform the operation in the fragment shader. The rendering context does not validate that the colors are stored in premultiplied format.
Je ne comprends pas bien la fin, mais je crois qu'on peut en conclure que les textures uploadées depuis un bitmap sont bien en alpha prémultiplié.

#10 lilive

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 2993 messages

Posté 11 December 2011 - 03:32 AM

Voir le messagelilive, le 11 December 2011 - 02:00 AM, dit :

Case 6
Pour tenter de voir ce qui se passe si on utilise
setBlendFactors(Context3DBlendFactor.ONE, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA)
j'ai cette fois utilisé la formule:

RGB0 = RGB1 + RGB2 * (1 - A1)
A0 = A1 + A2 * (1 - A1)


Si tous les pixels sont bien complétement opaques au final, ce qui est bien, on voit un sacré problème à l'intersection des cercles. Donc ce ne serait pas une bonne solution, finalement. Ce qui m'étonne c'est que je ne reconnais pas là le résultat de mon expérience du post précédent. En fait, je commence à me demander si les textures uploadées ne seraient pas par hasard converties en couleurs prémultipliées par l'alpha.

Bon ben cette fois je peux conclure je crois.
Puisque la texture que j'utilise est créée depuis un BitmapData, les couleurs sont pré-multipliées par l'alpha.
Donc ma case 6 ne rend pas compte de ce que ferais Stage3D.
Avec texture prémultipliée et setBlendFactors(ONE, ONE_MINUS_SOURCE_ALPHA) le calcul devient:

RGB0 = PRGB1 + RGB2 * (1 - A1)
A0 = A1 + A2 * (1 - A1)


où PRGB1 sont les couleurs prémultipliées, c'est-à-dire PRGB1 = RGB1 * A1
Si on remplace ça donne:

RGB0 = RGB1 * A1 + RGB2 * (1 - A1)
A0 = A1 + A2 * (1 - A1)


Ce qui est presque égal à la formule de la case 2 qui donne le bon résultat visuel:

RGB0 = RGB1 * A1 + RGB2 * A2 * (1 - A1)
A0 = A1 + A2 * (1 - A1)


La seule différence est qu'il n'y a pas le * A2
Mais vu que le alpha du fond est toujours à 1, cela revient au même.

Donc je confirme ce que j'avais déjà trouvé plus haut, mais cette fois c'est argumenté:
Pour dessiner des triangles texturés les uns par dessus les autres, avec gestion de la transparence des textures, et si les textures sont prémultipliées par l'alpha (comme c'est le cas pour des textures crées à partir de BitmapData), alors il faut utiliser:
setBlendFactors(Context3DBlendFactor.ONE, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA)

Et ben, ça m'en aura pris du temps. On voit que ça manque encore de ressources et de documentations tout ça (où alors c'est moi qui sait pas chercher).

Pour faire joli en conclusion, une petite animation avec transparence. Déplacer la souris pour faire varier le rendu:

Fichier(s) joint(s)



#11 lilive

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 2993 messages

Posté 13 December 2011 - 14:09 PM

Bon du coup, il faudrait refaire tous les test du post au-dessus pour voir ce que ça donne avec des textures pré-multipliées en alpha. Mais comme j'ai ma solution, j'ai la flemme :)

#12 Jean-Marc Le Roux

    Ceinture Noire

  • Minko
  • PipPipPipPipPipPipPip
  • 210 messages

Posté 29 June 2012 - 21:58 PM

Les textures ne sont pas prémultipliées lors de l'upload sur le GPU.
Stage3D utilise un format de texture R8G8B8A8. Donc l'alpha est bien là.

Par contre il ne faut pas oublier d'utiliser le bon blending...

Ensuite c'est encore plus compliqué : les pixels transparents - même invisibles à l'écran - sont quand même présent dans le z-buffer. Donc il faut trier les draw calls (avec l'algo du peintre par exemple) avant de les dessiner.

Après il y'a aussi moyen de faire du blending dans le shader directement pour implémenter des équations non supportées par le hardware comme c'est malheureusement le cas pour certains mode de fusion de Photoshop très utiles par exemple.

Modifié par Jean-Marc Le Roux, 29 June 2012 - 22:01 PM.




1 utilisateur(s) li(sen)t ce sujet

0 membre(s), 1 invité(s), 0 utilisateur(s) anonyme(s)