Cómo construir un entorno de OpenGL ES

A fin de dibujar gráficos con OpenGL ES en tu aplicación para Android, debes crear un contenedor de vistas. Una de las formas más directas de hacerlo es implementar una GLSurfaceView y un GLSurfaceView.Renderer. GLSurfaceView es un contenedor de vista para gráficos dibujados con OpenGL y GLSurfaceView.Renderer controla lo que se dibuja dentro de esa vista. Si deseas obtener más información sobre estas clases, consulta la guía para desarrolladores de OpenGL ES.

GLSurfaceView es solo una forma de incorporar gráficos de OpenGL ES en la aplicación. Para una vista de gráficos de pantalla completa o casi completa, es una opción razonable. Los desarrolladores que quieran incorporar gráficos de OpenGL ES en una parte pequeña de sus diseños deben consultar cómo funciona TextureView. Quienes prefieran desarrollar sus propias herramientas también pueden crear una vista de OpenGL ES con SurfaceView, pero deberán escribir bastante código adicional.

En esta lección se explica cómo completar una implementación mínima de GLSurfaceView y GLSurfaceView.Renderer en una actividad de aplicación simple.

Cómo declarar el uso de OpenGL ES en el manifiesto

Para que tu aplicación use la API de OpenGL ES 2.0, debes agregar la siguiente declaración al manifiesto:

    <uses-feature android:glEsVersion="0x00020000" android:required="true" />
    

Si la aplicación usa compresión de texturas, también debes declarar qué formatos de compresión admite para que solo se instale en dispositivos compatibles.

    <supports-gl-texture android:name="GL_OES_compressed_ETC1_RGB8_texture" />
    <supports-gl-texture android:name="GL_OES_compressed_paletted_texture" />
    

Si deseas obtener más información sobre los formatos de compresión de texturas, consulta la guía para desarrolladores de OpenGL.

Crea una actividad para los gráficos de OpenGL ES

Las aplicaciones para Android que usan OpenGL ES incluyen actividades como cualquier otra aplicación que tenga una interfaz de usuario. La diferencia principal con otras aplicaciones es lo que pones en el diseño de tu actividad. Aunque en muchas aplicaciones puedes usar TextView, Button y ListView, en una app que emplea OpenGL ES, también puedes agregar GLSurfaceView.

En el siguiente ejemplo de código, se muestra una implementación mínima de una actividad que usa GLSurfaceView como vista principal:

Kotlin

    class OpenGLES20Activity : Activity() {

        private lateinit var gLView: GLSurfaceView

        public override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)

            // Create a GLSurfaceView instance and set it
            // as the ContentView for this Activity.
            gLView = MyGLSurfaceView(this)
            setContentView(gLView)
        }
    }
    

Java

    public class OpenGLES20Activity extends Activity {

        private GLSurfaceView gLView;

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);

            // Create a GLSurfaceView instance and set it
            // as the ContentView for this Activity.
            gLView = new MyGLSurfaceView(this);
            setContentView(gLView);
        }
    }
    

Nota: OpenGL ES 2.0 requiere Android 2.2 (nivel de API 8) o versiones posteriores, así que asegúrate de que el proyecto de Android se oriente a esa API o a versiones posteriores.

Cómo construir un objeto GLSurfaceView

GLSurfaceView es una vista especializada donde puedes dibujar gráficos de OpenGL ES. No hace mucho por sí sola. El dibujo real de los objetos se controla en el GLSurfaceView.Renderer que configuraste en la vista. De hecho, el código de este objeto es tan fino que quizás te veas tentado a no extenderlo y a crear tan solo una instancia de GLSurfaceView sin modificar; pero no lo hagas. Debes extender esta clase para capturar eventos táctiles. El tema se aborda en la lección Cómo responder a eventos táctiles.

El código esencial de una GLSurfaceView es mínimo. En una implementación rápida, es común crear tan solo una clase interna en la actividad que la utiliza:

Kotlin

    import android.content.Context
    import android.opengl.GLSurfaceView

    class MyGLSurfaceView(context: Context) : GLSurfaceView(context) {

        private val renderer: MyGLRenderer

        init {

            // Create an OpenGL ES 2.0 context
            setEGLContextClientVersion(2)

            renderer = MyGLRenderer()

            // Set the Renderer for drawing on the GLSurfaceView
            setRenderer(renderer)
        }
    }
    

Java

    import android.content.Context;
    import android.opengl.GLSurfaceView;

    class MyGLSurfaceView extends GLSurfaceView {

        private final MyGLRenderer renderer;

        public MyGLSurfaceView(Context context){
            super(context);

            // Create an OpenGL ES 2.0 context
            setEGLContextClientVersion(2);

            renderer = new MyGLRenderer();

            // Set the Renderer for drawing on the GLSurfaceView
            setRenderer(renderer);
        }
    }
    

Otro agregado opcional a la implementación de GLSurfaceView consiste en configurar el modo de renderizado de manera que solo se dibuje la vista cuando haya un cambio en los datos de dibujo; para ello, usa la configuración GLSurfaceView.RENDERMODE_WHEN_DIRTY:

Kotlin

    // Render the view only when there is a change in the drawing data
    renderMode = GLSurfaceView.RENDERMODE_WHEN_DIRTY
    

Java

    // Render the view only when there is a change in the drawing data
    setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
    

Esta configuración evita que el marco de GLSurfaceView se vuelva a dibujar hasta que llames a requestRender(), que es más eficiente para la app de ejemplo.

Cómo compilar una clase de procesador

La implementación de la clase GLSurfaceView.Renderer, o procesador, dentro de una aplicación que usa OpenGL ES vuelve el desarrollo más interesante. La clase controla lo que se dibuja en la GLSurfaceView con la que está asociada. El sistema Android llama a tres métodos de un procesador para determinar qué dibujar en una GLSurfaceView y cómo hacerlo:

  • onSurfaceCreated(): Se llama una vez para configurar el entorno de OpenGL ES de la vista.
  • onDrawFrame(): Se llama cada vez que se vuelve a dibujar la vista.
  • onSurfaceChanged(): Se llama cuando cambia la geometría de la vista, por ejemplo, cuando cambia la orientación de la pantalla del dispositivo.

A continuación se incluye una implementación muy básica de un procesador de OpenGL ES que todo lo que hace es dibujar un fondo negro en la GLSurfaceView:

Kotlin

    import javax.microedition.khronos.egl.EGLConfig
    import javax.microedition.khronos.opengles.GL10

    import android.opengl.GLES20
    import android.opengl.GLSurfaceView

    class MyGLRenderer : GLSurfaceView.Renderer {

        override fun onSurfaceCreated(unused: GL10, config: EGLConfig) {
            // Set the background frame color
            GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f)
        }

        override fun onDrawFrame(unused: GL10) {
            // Redraw background color
            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
        }

        override fun onSurfaceChanged(unused: GL10, width: Int, height: Int) {
            GLES20.glViewport(0, 0, width, height)
        }
    }
    

Java

    import javax.microedition.khronos.egl.EGLConfig;
    import javax.microedition.khronos.opengles.GL10;

    import android.opengl.GLES20;
    import android.opengl.GLSurfaceView;

    public class MyGLRenderer implements GLSurfaceView.Renderer {

        public void onSurfaceCreated(GL10 unused, EGLConfig config) {
            // Set the background frame color
            GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        }

        public void onDrawFrame(GL10 unused) {
            // Redraw background color
            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        }

        public void onSurfaceChanged(GL10 unused, int width, int height) {
            GLES20.glViewport(0, 0, width, height);
        }
    }
    

Eso es todo. Los ejemplos de código anteriores crean una aplicación para Android simple que muestra una pantalla negra con OpenGL. Si bien el código no hace nada muy interesante, cuando creas estas clases, sientas las bases para comenzar a dibujar elementos gráficos con OpenGL.

Nota: Quizás te preguntes por qué estos métodos tienen un parámetro GL10 cuando usas las API de OpenGL ES 2.0. Las firmas de método simplemente se reutilizan para las API 2.0 a fin de simplificar el código del framework de Android.

Si estás familiarizado con las API de OpenGL ES, ahora deberías poder configurar un entorno de OpenGL ES en tu app y comenzar a dibujar gráficos. Sin embargo, si necesitas un poco más de ayuda para comenzar a usar OpenGL, continúa con las siguientes lecciones y obtendrás más información.