2011-08-17 13 views
8

Sto solo imparando a lavorare con OpenGL ES 2.0 per Android. Ho cercato semplicemente di visualizzare una texture al centro dello schermo, che era abbastanza facile, ma non riesco a far funzionare correttamente il PNG alfa. L'immagine verrà visualizzata con uno sfondo nero oppure l'intera immagine verrà sfumata leggermente nel colore di sfondo, a seconda delle impostazioni che uso.OpenGL ES 2.0 PNG canale alfa

Le esercitazioni che ho seguito per arrivare a questo punto non hanno mai funzionato con la trasparenza, quindi ho provato a lavorare nel codice che ho trovato cercando in giro, e probabilmente ho appena perso un passaggio importante. Ho cercato parecchio per capire questo problema, e non ho visto nessuna risposta che avesse qualcosa che il mio setup non avesse. Ho provato ogni combinazione di glBlendFunc e cosa no senza fortuna.

Ho pensato che se avessi provato a incollare tutto il codice che potrebbe essere collegato a questo, la domanda sembrerebbe molto gonfia, quindi sarò felice di pubblicare qualsiasi bit di codice che voi ragazzi chiedete. Apprezzerei molto qualsiasi idea su cosa dovrei provare dopo.

EDIT :: Ecco il mio frammento shader, che è quello che ritengo essere la causa. Questa è l'unica parte in cui non ho mai trovato un esempio decente per lavorare con la trasparenza, e tutto il resto corrisponde a quello che ho visto altrove.

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

E non fa mai nulla con l'alfa in modo esplicito, è da un esempio che non fa uso di esso, dopo tutto, ma io ancora non so molto di shader frammento e perché sembrava "sorta di" lavoro quando si confonde l'immagine sullo sfondo, ho pensato che funzionasse con l'alfa in qualche modo e ho appena avuto qualcosa di sbagliato.

MODIFICA :: Ecco il metodo "loadTexture". È all'incirca uguale all'esempio del libro openGL ES 2.0 da cui sto cercando di imparare, con alcune modifiche che sembrano rendere l'immagine più vicina al corretto funzionamento.

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

Capisco quello che il codice sta facendo, ma devo ammettere che mi confonde ancora un po 'così che io possa semplicemente mancare qualcosa di ovvio a causa della mia mancanza di conoscenza.

Non vedo altre parti del mio codice che sembrano poter causare il tipo di problemi che sto avendo, ma la programmazione è sempre piena di imprevisti (Soprattutto nel mondo di OpenGL sembra) quindi se si pensate che qualcos'altro è la causa che sicuramente scriverò per voi. Scusa per tutti i problemi!

+0

Assicurarsi che il canale alfa del PNG sia conservato quando si carica l'immagine nella trama (invece di caricare un'immagine RGB o creare una trama RGB). E ovviamente assicurati di chiamare 'glEnable (GL_BLEND)' (oltre a impostare il corretto 'glBlendFunc'). Ma un codice sicuramente ti aiuterà un po 'di più ad aiutarti. Forse solo il codice di caricamento dell'immagine e di creazione della trama e il codice in cui si imposta lo stato di fusione. E naturalmente, dato che sei nuovo qui, non dimenticare di informarti sulle funzioni di accettazione e di voto ascendente. –

+0

Lo shader del frammento sembra valido, poiché delega correttamente l'alfa della texture al colore dei frammenti. Quindi non andrai in giro a postare parte del tuo codice di caricamento e creazione della trama. –

+0

Puoi provare 'gl_FragColor = vec4 (baseColor.aaa, 1.0)' con il blending disabilitato. Questo dovrebbe darti un'immagine in scala di grigi del canale alfa. – trenki

risposta

3

Molto probabilmente si desidera utilizzare glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) come funzione di fusione e si deve assicurarsi di scrivere anche il valore alfa della trama nella variabile di output dello shader di frammento gl_FragColor.

Per fare in modo che i dati della trama caricati contengano un valore alfa, è necessario aver utilizzato un formato di trama che supporta un canale alfa (RGBA, RGBA8 ecc.).

È possibile verificare questo semplicemente instradando il valore alfa ai componenti di colore RGB e ispezionando l'immagine che si ottiene.

EDIT:

nella vostra immagine del codice di caricamento si dimentica di copiare il canale alfa! Prova il suggerimento che dà davebytes.

+0

Se utilizzo questa impostazione su glBlendFunc, l'immagine non viene visualizzata. Sembra che glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA) funzioni meglio per me, o almeno il più vicino a lavorare come dovrebbe. Vorrei anche ricordare che quando l'immagine si fonde con lo sfondo, sembra che rimuova anche le parti trasparenti dell'immagine. Credo che il mio problema risieda nello shader di frammenti, perché non ne so ancora molto ed è soprattutto una copia di codice di un esempio che non utilizzava la trasparenza. Lo posterò nel post principale. – DaeKo

1

lo shader iniziale va bene. l'alfa è inerente ai colori op, semplicemente non può essere applicato a seconda di blend/mode/etc.

dato che la texture risulta nera se si fa fragcolor = base.aaa, ciò implica che i propri dati di trama sono "cattivi".

guardando il carico della trama, sì, è sbagliato. non copi mai l'alfa, solo l'RGB. supponendo che java cancelli l'array di byte a 0, tutto l'alfa sarà pari a zero, ciò porterebbe la tua scatola nera, che farebbe sì che l'immagine "svanisca" quando abiliti la fusione alfa.

per semplificare la vita, invece di tutti la copia a mano e cose, si può semplicemente caricare la bitmap normalmente e utilizzare l'helper GLUtils per caricare invece di usare direttamente 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); 

Qualcosa del genere. Quindi abilita la fusione, usa la modalità di fusione src + invsrc se non premoltiplicato, e render, dovresti ottenere il risultato desiderato.

9

Change

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

in

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

per includere le informazioni alpha poi semplicemente aggiungere

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

destra prima di disegnare la texture. Ricordati di disabilitare GL_BLEND una volta che hai finito.