2011-08-17 5 views
8

J'apprends juste à travailler avec OpenGL ES 2.0 pour Android. J'ai essayé d'afficher simplement une texture au milieu de l'écran, ce qui était assez facile, mais je n'arrive pas à faire fonctionner le PNG alpha correctement. L'image apparaîtra avec un fond noir ou l'image entière sera légèrement mélangée à la couleur d'arrière-plan, en fonction des paramètres que j'utilise. Les tutoriels réels que j'ai suivis pour arriver à ce point n'ont jamais travaillé avec la transparence, donc j'ai essayé de travailler dans le code que j'ai trouvé en cherchant autour, et j'ai probablement raté une étape importante. J'ai beaucoup cherché pour comprendre ce problème, et je n'ai pas vu de réponses qui avaient quelque chose que ma configuration n'a pas. J'ai essayé toutes les combinaisons de glBlendFunc et ce qui ne va pas sans chance. Je me suis dit que si j'essayais de coller dans tout le code qui pourrait être lié à ceci, la question semblerait très gonflée, donc je serais heureux de poster des morceaux de code que vous demandez. J'apprécierais grandement des idées pour ce que je devrais essayer ensuite.OpenGL ES 2.0 PNG canal alpha

EDIT :: Voici mon fragment shader, qui est ce que je crois être la cause. C'est la seule partie que je n'ai jamais vraiment trouvé un exemple décent pour travailler avec la transparence, et tout le reste correspond à ce que j'ai vu ailleurs.

 final String fragmentShader =   
     "precision mediump float;  \n" 
     + "varying vec2 v_Color;   \n"  
     + "uniform sampler2D s_baseMap; \n" 
     + "void main()     \n"  
     + "{        \n" 
     + " vec4 baseColor;    \n" 
     + " baseColor = texture2D(s_baseMap, v_Color); \n" 
     + " gl_FragColor = baseColor;  \n"  
     + "}        \n"; 

Il ne fait rien avec l'alpha explicitement, il est d'un exemple qui ne l'utilise pas après tout, mais je ne sais toujours pas beaucoup sur Shaders fragment et parce qu'il semblait « sorte de » travailler quand il mélange l'image dans l'arrière-plan, je pensais que cela fonctionnait avec l'alpha dans une certaine forme et j'ai juste eu quelque chose mal réglé.

EDIT :: Voici la méthode "loadTexture". C'est à peu près la même chose que l'exemple du livre openGL ES 2.0 que j'essaie d'apprendre, avec quelques modifications qui semblent rapprocher l'image du bon fonctionnement.

private int loadTexture (InputStream is) 
{ 
    int[] textureId = new int[1]; 
    Bitmap bitmap; 
    bitmap = BitmapFactory.decodeStream(is); 
    byte[] buffer = new byte[bitmap.getWidth() * bitmap.getHeight() * 4]; 

    for (int y = 0; y < bitmap.getHeight(); y++) 
     for (int x = 0; x < bitmap.getWidth(); x++) 
     { 
      int pixel = bitmap.getPixel(x, y); 
      buffer[(y * bitmap.getWidth() + x) * 4 + 0] = (byte)((pixel >> 16) & 0xFF); 
      buffer[(y * bitmap.getWidth() + x) * 4 + 1] = (byte)((pixel >> 8) & 0xFF); 
      buffer[(y * bitmap.getWidth() + x) * 4 + 2] = (byte)((pixel >> 0) & 0xFF); 
     } 

    ByteBuffer byteBuffer = ByteBuffer.allocateDirect(bitmap.getWidth() * bitmap.getHeight() * 4); 
    byteBuffer.put(buffer).position(0); 

    GLES20.glGenTextures (1, textureId, 0); 
    GLES20.glBindTexture (GLES20.GL_TEXTURE_2D, textureId[0]); 

    GLES20.glTexImage2D (GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, bitmap.getWidth(), bitmap.getHeight(), 0, 
          GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, byteBuffer); 

    GLES20.glTexParameteri (GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); 
    GLES20.glTexParameteri (GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); 
    GLES20.glTexParameteri (GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); 
    GLES20.glTexParameteri (GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); 

    return textureId[0]; 
} 

Je comprends ce que fait le code, mais il est vrai qu'il me confond encore un peu pour que je puisse juste manquer quelque chose évidente en raison de mon manque de connaissances.

Je ne vois pas d'autres parties de mon code qui pourraient causer le genre de problèmes que j'ai, mais la programmation est toujours pleine de l'inattendu (surtout dans le monde d'OpenGL), donc si vous pense que quelque chose d'autre est la cause, je serai sûr de poster cela pour vous aussi. Désolé pour tous les problèmes!

+0

Assurez-vous que la couche alpha du format PNG est préservée lors du chargement de l'image dans la texture (au lieu de charger une image RVB ou de créer une texture RVB). Et bien sûr, assurez-vous que vous appelez 'glEnable (GL_BLEND)' (en plus de régler correctement 'glBlendFunc'). Mais du code aiderait sûrement un peu plus à vous aider. Peut-être juste le chargement de l'image et le code de création de texture et le code où vous configurez l'état de fusion. Et bien sûr, comme vous êtes nouveau ici, n'oubliez pas de vous informer sur les fonctionnalités d'acceptation et de vote. –

+0

Le fragment shader semble valide, car il délègue correctement l'alpha de la texture à la couleur des fragments. Vous ne pourrez donc pas afficher certains de vos codes de chargement et de création de texture. –

+0

Vous pouvez essayer 'gl_FragColor = vec4 (baseColor.aaa, 1.0)' avec la fusion désactivée. Cela devrait vous donner une image en niveaux de gris de la couche alpha. – trenki

Répondre

3

Vous voudrez probablement utiliser glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) comme fonction de fusion et vous devez vous assurer d'écrire également la valeur alpha de la texture dans la variable de sortie gl_FragColor. Pour que tout cela fonctionne, vos données de texture téléchargées doivent contenir une valeur alpha et vous devez avoir utilisé un format de texture qui supporte un canal alpha (RGBA, RGBA8, etc.).

Vous pouvez vérifier cela en routant simplement la valeur alpha sur les composants de couleur RVB et en inspectant l'image que vous obtenez.

EDIT:

Dans votre image code de chargement vous oubliez de copier sur le canal alpha! Essayez la suggestion que davebytes donne.

+0

Si j'utilise cette configuration sur le GlBlendFunc, l'image n'apparaît pas du tout. Il semble que glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA) fonctionne le mieux pour moi, ou au moins le plus proche de travailler comme il se doit. Je devrais également mentionner que lorsque l'image se fond dans l'arrière-plan, il semble également supprimer les parties transparentes de l'image. Je crois que mon problème réside dans le fragment shader, car je n'en sais pas encore beaucoup et c'est surtout une copie de code d'un exemple qui n'utilisait pas la transparence. Je l'afficherai dans le post principal. – DaeKo

1

votre shader initial est très bien. L'alpha est inhérent aux opérations de couleur, il peut ne pas être appliqué en fonction du mélange/mode/etc. Etant donné que votre texture est noire si vous faites fragcolor = base.aaa, cela implique que vos données de texture sont 'mauvaises'. En regardant votre charge de texture, oui, c'est faux. vous ne copiez jamais l'alpha, juste le RVB. En supposant que java efface le tableau d'octets à 0, tout alpha sera égal à zéro, ce qui vous donnerait votre boîte noire, ce qui ferait disparaître l'image lorsque vous activez l'alpha blending.

Pour vous simplifier la vie, au lieu de toute la copie de la main et d'autres choses, vous pouvez simplement charger le bitmap normalement et utiliser l'assistant de GLUtils télécharger au lieu d'utiliser directement glTexImage2D:

bitmap = BitmapFactory.decodeStream(is); 
    GLES20.glGenTextures (1, textureId, 0); 
    GLES20.glBindTexture (GLES20.GL_TEXTURE_2D, textureId[0]); 
    GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); 

Quelque chose comme ça. Activez ensuite le fondu, utilisez le mode de fusion src + invsrc s'il n'est pas prémultiplié, et le rendu, vous devriez obtenir le résultat souhaité.

9

changement

for (int y = 0; y < bitmap.getHeight(); y++) 
    for (int x = 0; x < bitmap.getWidth(); x++) 
    { 
     int pixel = bitmap.getPixel(x, y); 
     buffer[(y * bitmap.getWidth() + x) * 4 + 0] = (byte)((pixel >> 16) & 0xFF); 
     buffer[(y * bitmap.getWidth() + x) * 4 + 1] = (byte)((pixel >> 8) & 0xFF); 
     buffer[(y * bitmap.getWidth() + x) * 4 + 2] = (byte)((pixel >> 0) & 0xFF); 
    } 

dans

for (int y = 0; y < bitmap.getHeight(); y++) 
    for (int x = 0; x < bitmap.getWidth(); x++) 
    { 
     int pixel = bitmap.getPixel(x, y); 
     buffer[(y * bitmap.getWidth() + x) * 4 + 0] = (byte)((pixel >> 16) & 0xFF); 
     buffer[(y * bitmap.getWidth() + x) * 4 + 1] = (byte)((pixel >> 8) & 0xFF); 
     buffer[(y * bitmap.getWidth() + x) * 4 + 2] = (byte)((pixel >> 0) & 0xFF); 
     buffer[(y * bitmap.getWidth() + x) * 4 + 3] = (byte)((pixel >> 24) & 0xFF); 
    } 

pour inclure les informations alpha puis simplement ajouter

GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA); 
GLES20.glEnable(GLES20.GL_BLEND); 

droit avant de tirer la texture. N'oubliez pas de désactiver GL_BLEND une fois que vous avez terminé.