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:
- Irrlicht android en opengl es 2.0 driver
- Cómo salvar SurfaceTexture como bitmap
- La forma correcta de dibujar texto en OpenGL ES 2
- Convertir la textura procesada de OpenGL ES 2.0 en mapa de bits y volver
- Escena de OpenGL con fondo transparente + widgets nativos por debajo y por encima
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.
- Grabación de marcos generados por Open GL ES en android
- Cómo dibujar / hacer una colisión de física de bala cuerpo / forma?
- Cómo tratar NaN o inf en los shaders de OpenGL ES 2.0
- Añadir dinámicamente formas Opengl
- EglSwapBuffers es errático / lento
- OpenGL ES profundidad buffer android, no puede llegar a trabajar
- ¿Cuál es el parámetro "offset" en GLES20.glVertexAttribPointer / glDrawElements, y de dónde proviene ptr / indices?
- Android Openg GL ES 2 dibujo grandes texturas lento
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í.
- Cómo cambiar el color de la barra de herramientas
- Phonegap funciones no definidas en Phonegap construir aplicaciones – también pushNotifications no funcionan