2011-08-17 15 views
8

Estoy aprendiendo a trabajar con OpenGL ES 2.0 para Android. He intentado simplemente mostrar una textura en el medio de la pantalla, lo cual fue bastante fácil, pero parece que no puedo hacer que el alfa PNG funcione correctamente. La imagen se mostrará con un fondo negro, o toda la imagen se mezclará ligeramente en el color de fondo, dependiendo de la configuración que use.OpenGL ES 2.0 PNG canal alfa

Los tutoriales reales que he seguido para llegar a este punto nunca funcionaron con transparencia, así que traté de trabajar en el código que encontré buscando, y probablemente me haya perdido un paso importante. Sin embargo, he buscado mucho para resolver este problema, y ​​no he visto ninguna respuesta que haya tenido algo que mi configuración no tenga. He probado todas las combinaciones de glBlendFunc y no sin suerte.

Pensé que si trataba de pegar todo el código que pudiera estar relacionado con esto, la pregunta sería muy abultada, por lo que me complacerá publicar cualquier fragmento de código que pidan. Agradecería enormemente cualquier idea sobre lo que debería intentar a continuación.

EDIT :: Aquí está mi sombreador de fragmentos, que es lo que creo que es la causa. Esta es la única parte que nunca he encontrado un ejemplo decente para trabajar con transparencia, y todo lo demás coincide con lo que he visto en otros lugares.

 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"; 

Nunca hace nada con el alfa de forma explícita, es a partir de un ejemplo que no utiliza, después de todo, pero aún no se sabe mucho acerca de los sombreadores de fragmentos y porque parecía "una especie de" trabajo cuando combina la imagen con el fondo, pensé que estaba trabajando con el alfa de alguna forma y que me equivoqué.

EDITAR :: Aquí está el método "loadTexture". Es más o menos lo mismo que el ejemplo del libro OpenGL ES 2.0 del que estoy tratando de aprender, con algunas modificaciones que parecen hacer que la imagen esté más cerca de funcionar correctamente.

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]; 
} 

entiendo lo que el código está haciendo, pero hay que admitir que todavía me confunde un poco, así que sólo puede estar perdiendo algo obvio debido a mi falta de conocimiento.

No veo ninguna otra parte de mi código que parezca que podría causar el tipo de problemas que estoy teniendo, pero la programación siempre está llena de lo inesperado (especialmente en el mundo de OpenGL) así que si Piensa que otra cosa es la causa. Voy a estar seguro de publicar eso para ti también. ¡Lo siento por todos los problemas!

+0

Asegúrate de que el canal alfa de PNG se conserva al cargar la imagen en la textura (en lugar de cargar una imagen RGB o crear una textura RGB). Y, por supuesto, asegúrese de llamar a 'glEnable (GL_BLEND)' (además de configurar el 'glBlendFunc' correcto). Pero algún código seguramente te ayudaría un poco más para ayudarte. Tal vez solo el código de creación de texturas y carga de imágenes y el código donde configura el estado de fusión. Y, por supuesto, como eres nuevo aquí, no te olvides de informarte sobre las funciones de aceptar y votar. –

+0

El sombreador de fragmentos parece válido, ya que delega correctamente el alfa de la textura en el color de los fragmentos. Por lo tanto, no tendrás que publicar algo de tu código de carga y creación de texturas. –

+0

Puede probar 'gl_FragColor = vec4 (baseColor.aaa, 1.0)' con la mezcla desactivada. Esto debería darle una imagen en escala de grises del canal alfa. – trenki

Respuesta

3

Lo más probable es que desee utilizar glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) como la función de fusión y también debe asegurarse de escribir el valor alfa de la textura en la variable de salida del sombreador de fragmentos gl_FragColor.

Para que todo funcione, los datos de textura cargados deben contener un valor alfa y debe haber usado un formato de textura que admita un canal alfa (RGBA, RGBA8, etc.).

Puede verificar esto simplemente enrutando el valor alfa a los componentes de color RGB e inspeccionando la imagen que obtiene.

EDIT:

En el código de la carga de imágenes se olvida de copiar el canal alfa! Pruebe la sugerencia de que da davebytes.

+0

Si utilizo esa configuración en glBlendFunc, la imagen no aparece en absoluto. Parece que glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA) funciona mejor para mí, o al menos lo más cercano a funcionar como debería. También debo mencionar que cuando la imagen se mezcla con el fondo, también parece eliminar las partes transparentes de la imagen. Creo que mi problema radica en el sombreador de fragmentos, porque aún no sé mucho sobre él y en su mayoría es una copia del código de un ejemplo que no estaba usando transparencia. Lo publicaré en la publicación principal. – DaeKo

1

su shader inicial está bien. alpha es inherente a las operaciones de color, simplemente no se puede aplicar dependiendo de blend/mode/etc.

dado que su textura sale negra si lo hace fragcolor = base.aa, eso implica que los datos de su textura son 'malos'.

mirando su carga de textura, sí, está mal. nunca copias sobre el alfa, solo el rgb. suponiendo que java borre el conjunto de bytes a 0, todos los alfa serán cero, que obtendría su cuadro negro, que causaría que la imagen 'desaparezca' cuando habilite la mezcla alfa.

para simplificar su vida, en lugar de toda la copia mano y esas cosas, sólo tiene que cargar el mapa de bits con normalidad y los auxiliares de GLUtils para cargar en lugar de utilizar directamente 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); 

Algo por el estilo. Luego, habilite la mezcla, utilice el modo de combinación src + invsrc si no está premultiplicado, y renderice, debe obtener el resultado deseado.

9

Cambio

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); 
    } 

en

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); 
    } 

para incluir la información alfa continuación, sólo tiene que añadir

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

justo antes de dibujar la textura. Recuerde desactivar GL_BLEND una vez que haya terminado.