glClearColor no funciona correctamente (opengl android)

Quiero cambiar el color de fondo de mi aplicación en tiempo de ejecución. Así que en el botón de hacer clic en llamar por primera vez:

GLES20.glClearColor(color[0], color[1], color[2], color[3]); 

Entonces llamo:

 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); 

¡Y no hace nada! Mantiene el color de fondo actual – no lo cambia. Pero cuando hago una pausa en mi aplicación y la reanudo de nuevo el color de fondo se cambia.

EDIT: Descubrí una manera de hacerlo. Cada marco primero llamo glClear pero no llamé glClearColor . Así que si primero llamo a glClearColor cada fotograma antes de llamar a glClear funciona. Pero esto todavía no tiene sentido para mí, quería evitar llamar glClearColor en cada marco, pensé que sería suficiente si lo llamo una vez cuando quiero cambiar el color.

Sólo puede realizar llamadas OpenGL mientras tenga un contexto OpenGL actual. Cuando se utiliza GLSurfaceView , manejo de contexto se cuida para usted, por lo que todo simplemente mágicamente parece funcionar. Hasta que algo salga mal, como en tu caso. En lugar de darle sólo la solución, permítanme explicar lo que pasa bajo el capó, para evitar futuras sorpresas.

Antes de poder realizar llamadas OpenGL, es necesario crear un contexto OpenGL y establecerlo como contexto actual. En Android, esto utiliza la API de EGL. GLSurfaceView maneja eso para usted, y todo esto sucede antes de que onSurfaceCreated() sea ​​llamado en su render. Por lo tanto, cuando se llaman los métodos de la implementación de Renderer , siempre puede contar con un contexto actual, sin tener que preocuparse por ello.

El aspecto crucial es sin embargo que el contexto actual es por hilo . GLSurfaceView crea un subproceso de representación y todos los métodos Renderer se invocan en este subproceso.

La consecuencia de esto es que no puede realizar llamadas OpenGL desde otros subprocesos , ya que no tienen un contexto OpenGL actual. Que incluye el hilo de interfaz de usuario. Esto es exactamente lo que intentaba hacer. Si realiza la llamada glClearColor() en respuesta a un clic de botón, está en el subproceso de UI y no tiene un contexto OpenGL actual.

La solución que ya encontró podría ser la solución más realista en este caso. glClearColor() debe ser una llamada barata, por lo que antes de cada glClear() no será significativa. Si la acción que necesitabas tomar fuera más costosa, también podrías establecer una bandera booleana cuando el valor cambiara, y entonces solo haría el trabajo correspondiente en onDrawFrame() si el flag está establecido.

Hay otro aspecto sutil pero muy importante aquí: la seguridad de hilo. Tan pronto como se establecen los valores en un hilo (hilo de interfaz de usuario) y utilizarlos en otro hilo (subproceso de representación), esto es algo que tiene que preocuparse. Diga si tiene 3 valores para los componentes RGB del color de fondo y los establece en el subproceso de UI uno por uno. Es posible que el hilo de renderizado utilice los 3 valores mientras el subproceso de UI los está configurando, terminando con una mezcla de valores antiguos y nuevos.

Para ilustrar todo esto, utilizaré su ejemplo y diseñaré una solución de trabajo y de seguridad. Los miembros de la clase involucrados podrían verse así:

 float mBackRed, mBackGreen, mBackBlue; boolean mBackChanged; Object mBackLock = new Object(); 

A continuación, donde se establece el valor en el subproceso de interfaz de usuario:

 synchronized(mBackLock) { mBackRed = ...; mBackGreen = ...; mBackBlue = ...; mBackChanged = true; } 

Y en el método onDrawFrame() antes de llamar a glClear() :

 Boolean changed = false; float backR = 0.0f, backG = 0.0f, backB = 0.0f; synchronized(mBackLock) { if (mBackChanged) { changed = true; backR = mBackRed; backG = mBackGreen; backB = mBackBlue; mBackChanged = false; } } if (changed) { glClearColor(backR, backG, backB, 0.0f); } 

Observe cómo todo el acceso a los miembros de clase compartidos por los dos subprocesos está dentro de un bloqueo. En el último fragmento de código, observe también cómo se copian los valores de color en las variables locales antes de utilizarlas. Esto puede ir demasiado lejos para este ejemplo simple, pero quise ilustrar el objetivo general que la cerradura se debe celebrar tan brevemente como sea posible. Si utiliza las variables de miembro directamente, tendría que hacer la llamada glClearColor() dentro del bloqueo. Si se trata de una operación que puede tardar mucho tiempo, el subproceso de interfaz de usuario no podría actualizar los valores y podría quedar bloqueado durante un tiempo esperando el bloqueo.

Hay un enfoque alternativo para usar una cerradura. GLSurfaceView tiene un método queueEvent() que le permite pasar un Runnable que luego se ejecutará en el subproceso de renderizado. Hay un ejemplo de esto en la documentación de GLSurfaceView , por lo que no voy a escribir el código aquí.

  • Primeros pasos para crear un efecto de chroma key utilizando la cámara android
  • Utilizar glVertexAttribPointer y glDrawElements para extraer de un buffer de vértice empaquetado
  • Cómo dibujar círculo básico en OpenGL ES 2.0 Android
  • GLSurfaceView - cómo hacer el fondo translúcido
  • Adreno 220 GLSL bug
  • referencia indefinida glBindVertexArrayOES en eclipse
  • For-loop en código de sombreado que trabaja con un número codificado pero no con una variable uniforme
  • Aprenda OpenGL: ¿por dónde empezar o cómo ha aprendido OpenGL?
  • Aplicando textura a Cubo, textura diferente en cada cara de cubo
  • Actualización de la textura con glTexImage2D (..) en OpenglES2
  • Varias cámaras en libgdx (probablemente similar en otros marcos)
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.