2012-02-14 13 views
6

(Modifica: ho provato un campione che dipingeva semplicemente un triangolo senza texture o shader e solo OpenGL-ES 1.1 sul mio dispositivo e poteva vedere gli stessi artefatti. Ho provato lo stesso campione nell'emulatore e non c'erano artefatti lì potrebbe essere un problema di Tegra 2 o devo impostare uno stato specifico o qualcosa che non è necessario nell'emulatore?)Perché i colori dei pixel non sono corretti in OpenGL ES 2.0 su Android?

Sto riproducendo un quadrato corretto di pixel sullo schermo ma quando creo uno screengrab e guarda il pixel poi alcuni di loro sono leggermente fuori come antializzati o filtrati o qualcosa del genere. Lo vedi solo quando lo zoom su di loro, ma non è questo il punto. Voglio fare un po 'di matematica nel pixel shader e se i pixel sono leggermente spenti e questo non mi va bene. Ho bisogno di loro esattamente come nella bitmap in cui li ho inseriti.

Ecco uno screengrab ingrandito del problema. Intorno alla linea bianca i valori scuri sono leggermente più brillante di quello che dovrebbe essere:

enter image description here

Ho già provato:

GLES20.glDisable(GLES20.GL_DITHER); 
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); 
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST); 
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); 

, ma non ha avuto alcun effetto. I pixel sono leggermente fuori. È facile da vedere tra pixel scuri e bianchi, perché il pixel scuro accanto ad esso è leggermente più luminoso e anche i valori r, g, b con un programma di pittura mi mostrano questo.

Qualcuno potrebbe aiutarmi con questo?

qualche informazione in più: CPU

mio dispositivo è un Tegra 2.0. Rendo esattamente un quadrato 256x256 in 256x256 pixel (l'ho verificato prendendo uno schermo con DDMS eclipse). La trasparenza è disattivata e la bitmap ha un valore alfa di 255 per ciascun pixel. Ho creato la superficie come una superficie 32bit con alfa con:

glSurface.setEGLConfigChooser(8, 8, 8, 8, 0, 0); 

ho semplificato il codice, ma comunque possibile verificare il problema quando mi rendono con seguenti shaders:

String vshaderquad = "attribute vec4 a_pos;    \n" + // in  position 
          "attribute vec2 a_tex;    \n" + // in  Texture coordinates 
          "varying vec2 vtex;     \n" + // out  Texture coordinates 
          "void main(void) {     \n" + 
          " gl_Position = vec4(a_pos);  \n" + 
          " vtex = a_tex;     \n" + 
          "}"; 

    String fshaderquad = "precision mediump float;      \n" + 
          "varying vec2  vtex;      \n" + 
          "uniform sampler2D samp0;      \n" + 
          "void main() {         \n" + 
          " gl_FragColor = texture2D(samp0, vtex);  \n" + 
          "}"; 

e comandi:

GLES20.glActiveTexture(GLES20.GL_TEXTURE0); 
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mapid[0]); 
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); 
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST); 
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); 
GLES20.glUniform1i(handlesampler0, 0); 
GLES20.glDisable(GLES20.GL_DITHER); 



GLES20.glViewport(0, 0, screenx, screeny); 

float screenx = (float)ddimx; 
float screeny = (float)ddimy; 
// 
vdata.put(0*4+0,  0.0f * (2.0f/screenx)); 
vdata.put(0*4+1, 256.0f * (2.0f/screeny)); 
vdata.put(0*4+2,  0.0f * (1.0f/256f)); 
vdata.put(0*4+3, 256.0f * (1.0f/256f)); 
// 
vdata.put(1*4+0,  0.0f * (2.0f/screenx)); 
vdata.put(1*4+1,  0.0f * (2.0f/screeny)); 
vdata.put(1*4+2,  0.0f * (1.0f/256f)); 
vdata.put(1*4+3,  0.0f * (1.0f/256f)); 
// 
vdata.put(2*4+0, 256.0f * (2.0f/screenx)); 
vdata.put(2*4+1, 256.0f * (2.0f/screeny)); 
vdata.put(2*4+2, 256.0f * (1.0f/256f)); 
vdata.put(2*4+3, 256.0f * (1.0f/256f)); 
// 
vdata.put(3*4+0, 256.0f * (2.0f/screenx)); 
vdata.put(3*4+1,  0.0f * (2.0f/screeny)); 
vdata.put(3*4+2, 256.0f * (1.0f/256f)); 
vdata.put(3*4+3,  0.0f * (1.0f/256f)); 

GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 

PS: il leggero cambiamento di colore non è realmente visibile senza uno zoom estremo ma voglio fare calcoli con i valori e questo significa che devono essere precisi.

Modifica: ho aggiunto un'immagine a piena risoluzione. I colori sulle linee dovrebbero andare da (0,0,0) a (255,255,255) e sono inversi al gradiente di sfondo. Ho fatto questa immagine solo per testare l'accuratezza della trama e lì ho trovato il problema che non è proprio preciso. È necessario ingrandire anche se per distinguere le differenze è per questo che ho postato l'immagine ingrandita. Nota: le coordinate sono diverse rispetto al codice pubblicato sopra, ma il problema è lo stesso (ho provato diverse coordinate su schermo e il problema persiste).

enter image description here

+0

Uno screengrab sarebbe grande per mostrare il problema, ma da quello che si scrive ho il sospetto che sia [dithering] (http://www.curious-creature.org/2010/12/08/bitmap-quality-banding-and-dithering/). È una postelaborazione, quindi non dovrebbe influenzare i pixel shader. –

+0

Ciao, grazie per la tua risposta e ho aggiunto un'immagine per mostrare meglio il problema. Inoltre, non penso che sia solo un errore di post-elaborazione perché eseguo alcuni calcoli negli shader e i valori attesi erano spenti e puntano a questo come al problema. – HardCoder

+0

Chiedo come dunce Android: esiste un modo in cui si utilizza un display PenTile e si leggono i colori che vengono calcolati dagli effettivi elementi di visualizzazione? – Tommy

risposta

3

Ok, penso di aver trovato la soluzione.

Come ho già scritto, ho creato uno screenshot con il DDMS di eclissi e sembra che questo stia causando il problema. Quello screenshot non è il framebuffer esatto, ma una sorta di smoothing/anti-aliasing sta succedendo lì.

Questo sembra non essere il risultato del DDMS stesso, ma sembra accadere solo quando viene utilizzato sul mio dispositivo reale. Quando ho provato con l'emulatore che il problema non si verifica, potrebbe essere che il mio dispositivo abbia uno schermo pentile (è stato rilasciato solo in Giappone finora e non ho trovato materiale informativo in modo da confermarlo o negarlo, ma la sua sony e sony lo ha fatto usa i display pentili nei dispositivi) o forse ha a che fare con il chip Tegra 2 o forse con un qualche tipo di compressione che si verifica quando l'immagine viene trasferita o forse per qualche altra ragione.

In entrambi i casi, quando utilizzo la seguente funzione, posso salvare schermate assolutamente perfette in quanto richiede il FrameBuffer OpenGL-ES 2.0 e lo salva in un file PNG che posso quindi trasferire facilmente con un file batch ("adb tirare /mnt/sdcard/info/Testfile.txt ") e visualizzare sul mio computer:

public boolean SaveFrameBuffer(int x, int y) 
{ try 
    { IntBuffer pinbuffer = IntBuffer.allocate(x*y*4); 
     IntBuffer poutbuffer = IntBuffer.allocate(x*y*4); 
     int   i,j,z; 
     int []  pin   = pinbuffer.array(); 
     int []  pout  = poutbuffer.array(); 
     // 
     GLES20.glReadPixels(0, 0, x, y, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, pinbuffer);    
     for(i=0;i<y;i++) 
     { for(j=0;j<x;j++) 
      { z = pin[(y-1-i)*x+j]; 
       pout[i*x+j] = (z & 0xff000000) | ((z >> 16) & 0x000000ff) | ((z << 16) & 0x00ff0000) | (z & 0x0000ff00); 
      } 
     } 
     Bitmap map = Bitmap.createBitmap(x, y, Bitmap.Config.ARGB_8888); 
     map.setPixels(pout, 0, x, 0,0, x, y); 
     OutputStream stream = new FileOutputStream("/sdcard/info/test.png"); 
     map.compress(CompressFormat.PNG, 100, stream); 
     stream.close(); 
     return true; 
    } catch (Exception e) 
    { e.printStackTrace(); 
     return false; 
    } 
}