2011-11-21 11 views
9

Estoy tomando una captura de pantalla con glReadPixels para realizar un efecto "cruzado" entre dos imágenes.OpenGL ES - glReadPixels

En el simulador Mermelada SDK, la pantalla se toma muy bien y el efecto "cross-over" funciona un convite: enter image description here

Sin embargo, esto es lo que parece en dispositivos iOS y Android - corrompido: http://www.eikona.info/images/81269689420703803966.png

Siempre leo la pantalla como RGBA 1 byte/canal, como documentation says SIEMPRE se acepta.

Aquí es el código utilizado para tomar la captura de pantalla:

uint8* Gfx::ScreenshotBuffer(int& deviceWidth, int& deviceHeight, int& dataLength) { 

    /// width/height 
    deviceWidth = IwGxGetDeviceWidth(); 
    deviceHeight = IwGxGetDeviceHeight(); 
    int rowLength = deviceWidth * 4; /// data always returned by GL as RGBA, 1 byte/each 

    dataLength = rowLength * deviceHeight; 

    // set the target framebuffer to read 
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 
    glPixelStorei(GL_PACK_ALIGNMENT, 1); 
    uint8* buffer = new uint8[dataLength]; 
    glReadPixels(0, 0, deviceWidth, deviceHeight, GL_RGBA, GL_UNSIGNED_BYTE, buffer); 

    return buffer; 
} 

void Gfx::ScreenshotImage(CIwImage* img, uint8*& pbuffer) { 

    int deviceWidth, deviceHeight, dataLength; 

    pbuffer = ScreenshotBuffer(deviceWidth, deviceHeight, dataLength); 
    img->SetFormat(CIwImage::ABGR_8888); 
    img->SetWidth(deviceWidth); 
    img->SetHeight(deviceHeight); 
    img->SetBuffers(pbuffer, dataLength, 0, 0); 
} 
+1

Si elimina su bloque 'de arriba hacia abajo', ¿la corrupción desaparece? ¿Solo al revés? ¿O está dañado _y_ al revés? – sarnold

+0

La cosa es que no tengo un dispositivo, así que tengo que enviarlo a mi cliente, luego esperar a que lo instale y pruebe ... todo esto puede demorar hasta un par de días :-( –

+0

Los comentarios anteriores son ahora irrelevante después de volver a editar mi mensaje para reflejar mis nuevos hallazgos. –

Respuesta

5

Al final, fue la falta de memoria. El "nuevo uint8 [dataLength];" nunca devolvió un puntero existente, por lo que todo el proceso se corrompió.

TomA, su idea de limpiar el búfer en realidad me ayudó a resolver el problema. Gracias.

5

Eso es un error del conductor. Simple como eso.

El controlador tiene el tono de la superficie en la memoria de video equivocado. Puedes ver esto claramente en las líneas superiores. Además, la basura que se ve en la parte inferior de la imagen es la memoria donde el controlador piensa la imagen está almacenada, pero allí hay datos diferentes. Textures/Vertex data maybe.

Y lo siento, no tengo forma de solucionarlo. Puede tener mejor suerte con un formato de superficie diferente o habilitando/deshabilitando la multimuestreo.

+0

Ojalá fuera cierto, la corrupción es evidente tanto en iOS como en Android, entonces algo más debe estar equivocado de mi parte ... –

+0

Bill, probablemente sea el mismo chip 3D SGX con el mismo controlador ARM en Android y iOS. –

3

No sé acerca de Android o el SDK que está utilizando, pero en IOS cuando tomar una captura de pantalla que tengo que hace el buffer del tamaño de la siguiente textura POT, algo como esto:

int x = NextPot((int)screenSize.x*retina); 
int y = NextPot((int)screenSize.y*retina); 

void *buffer = malloc(x * y * 4); 

glReadPixels(0,0,x,y,GL_RGBA,GL_UNSIGNED_BYTE,buffer); 

La función NextPot me da el siguiente tamaño de POT, por lo que si el tamaño de la pantalla es de 320x480, la x, y sería de 512x512.

Tal vez lo que ves es la envoltura del búfer porque está esperando un tamaño de búfer más grande?

También esta podría ser una razón para que funcione en el simulador y no en el dispositivo, mi tarjeta gráfica no tiene la limitación de tamaño POT y obtengo un resultado similar (aspecto extraño).

1

No tengo una solución para arreglar glReadPixels. Mi sugerencia es que cambies tu algoritmo para evitar la necesidad de volver a leer los datos desde la pantalla.

Eche un vistazo a this page. Estos chicos han hecho un efecto de cambio de página todo en Flash. Todo está en 2D, la ilusión se logra solo con gradientes de sombra.

Creo que puede utilizar un enfoque similar, pero un poco mejor en 3D. Básicamente, debe dividir el efecto en tres partes: la parte superior (nubes), la página inferior (la niña) y la parte posterior de la página principal. Tienes que dibujar cada parte por separado. Puede dibujar fácilmente la página superior que mira hacia el frente y la página inferior juntas en la misma pantalla, solo necesita invocar el código de dibujo para cada una con una región de recorte preestablecida que esté alineada con la línea divisoria donde se dobla la página superior. Después de que tenga que dibujar las secciones superior y posterior de la página, puede dibujar la parte posterior gris hacia arriba, también alineada con la línea divisoria.

Con este enfoque, lo único que se pierde es un poco de deformación donde la imagen de las nubes comienza a doblarse, por supuesto, no habrá deformación con mi método.Espero que eso no disminuya el efecto, creo que las sombras son mucho más importantes para dar el efecto de profundidad y ocultará esta pequeña inconsistencia.

3

Lo que supongo que está sucediendo es que está tratando de usar glReadPixels en la ventana que está cubierta. Si el área de vista está cubierta, el resultado de glReadPixels no está definido.

Ver How do I use glDrawPixels() and glReadPixels()? y The Pixel Ownership Problem.

Como se ha dicho here:

La solución es hacer que un tampón fuera de la pantalla (FBO) y prestar a la FBO.

Otra opción es asegurarse de que la ventana no esté cubierta cuando usa glReadPixels.

1

Estoy obteniendo capturas de pantalla de mi juego de Android sin ningún problema en dispositivos Android que usan glReadPixels.

No estoy seguro aún cuál es el problema en su caso, necesito más información. Así que vamos a empezar:

  1. le recomiendo que no para especificar el formato PixelStore. Me preocupa tu alineación en 1 byte, ¿realmente "lo usas"/"sabes lo que hace"? Parece que obtienes exactamente lo que especifiques: un byte extra (mira tu imagen, ¡hay un píxel adicional todo el tiempo!) En lugar de una imagen completamente empaquetada. Así que intente eliminar esto:

    glPixelStorei (GL_UNPACK_ALIGNMENT, 1); glPixelStorei (GL_PACK_ALIGNMENT, 1);

  2. no estoy seguro en código C, ya que estaba trabajando sólo en java, pero esto se ve como posible punto:

    // anchura/altura deviceWidth = IwGxGetDeviceWidth(); deviceHeight = IwGxGetDeviceHeight();

¿Obtiene el tamaño de un dispositivo? Debe utilizar el tamaño de su superficie OpenGL, así:

public void onSurfaceChanged(GL10 gl, int width, int height) { 
int surfaceWidth = width; 
int surfaceHeight = height; 
} 
  1. ¿Qué haces junto con la imagen capturada? ¿Sabe que el bloque de memoria que obtuvo de OpenGL es RGBA, pero todas las operaciones de imágenes no abiertas esperan ARGB? Por ejemplo, aquí en su código espera que alfa sea el primer bit, no el último:

    img-> SetFormat (CIwImage :: ABGR_8888);

  2. En caso de que 1, 2 y 3 no hayan sido de ayuda, es posible que desee guardar la pantalla capturada en la tarjeta SD del teléfono para examinarla más tarde. Tengo un programa que convierte OpenGL RGBA bloque a mapa de bits normal para examinar en PC. Puedo compartirlo contigo.