Android incluye compatibilidad con gráficos 2D y 3D de alto rendimiento con Open Graphics Library (OpenGL®), específicamente, la API de OpenGL ES. OpenGL es una API multiplataforma de gráficos que especifica una interfaz de software estándar para hardware de procesamiento de gráficos 3D. OpenGL ES es una versión de la especificación OpenGL diseñada para dispositivos incorporados. Android admite varias versiones de la API de OpenGL ES:
- OpenGL ES 1.0 y 1.1: Esta especificación de API es compatible con Android 1.0 y versiones posteriores.
- OpenGL ES 2.0: Esta especificación de API es compatible con Android 2.2 (API nivel 8) y versiones posteriores.
- OpenGL ES 3.0: Esta especificación de API es compatible con Android 4.3 (API nivel 18) y versiones posteriores.
- OpenGL ES 3.1: Esta especificación de API es compatible con Android 5.0 (API nivel 21) y versiones posteriores.
Precaución:La compatibilidad de la API de OpenGL ES 3.0 en un dispositivo requiere una implementación de esta canalización de gráficos que proporciona el fabricante del dispositivo. Es posible que un dispositivo con Android 4.3 o versiones anteriores no admita la API de OpenGL ES 3.0. Para obtener información sobre cómo comprobar qué versión de OpenGL ES es compatible durante el tiempo de ejecución, consulta Cómo averiguar la versión de OpenGL ES.
Nota: La API específica que proporciona el marco de trabajo de Android es similar a la API de OpenGL ES JSR 239 de J2ME, pero no es idéntica. Si conoces la especificación JSR 239 de J2ME, mantente al tanto de las variantes.
Ver también
- Cómo mostrar gráficos con OpenGL ES
- OpenGL ES
- Especificación de OpenGL ES 1.x
- Especificación de OpenGL ES 2.x
- Especificación de OpenGL ES 3.x
Conceptos básicos
Android admite OpenGL mediante su API de marco de trabajo y el kit de desarrollo nativo (NDK). Este tema se centra en las interfaces del marco de trabajo de Android. Para obtener más información sobre el NDK, consulta la página del NDK de Android.
Hay dos clases fundamentales en el marco de Android que te permiten crear y manipular
gráficos con la API de OpenGL ES: GLSurfaceView
y
GLSurfaceView.Renderer
. Si planeas usar OpenGL en tu aplicación para Android,
lo primero que debes hacer es comprender el modo de implementar estas clases en una actividad.
GLSurfaceView
- Esta clase es una
View
donde puedes dibujar y manipular objetos usando llamadas a la API de OpenGL y es similar en función a unaSurfaceView
. Puedes usar esta clase si creas una instancia deGLSurfaceView
y le agregas tuRenderer
. Sin embargo, si deseas capturar eventos de pantalla táctil, debes extender la claseGLSurfaceView
para implementar los objetos de escucha táctiles, como se muestra en la lección de capacitación de OpenGL Cómo responder a eventos táctiles. GLSurfaceView.Renderer
- Esta interfaz define los métodos necesarios para dibujar gráficos en una
GLSurfaceView
. Debes proporcionar una implementación de esta interfaz como una clase separada y adjuntarla a tu instanciaGLSurfaceView
utilizandoGLSurfaceView.setRenderer()
.La interfaz
GLSurfaceView.Renderer
requiere que implementes los siguientes métodos:-
onSurfaceCreated()
: El sistema llama a este método una vez cuando crea elGLSurfaceView
. Usa este método para realizar acciones que solo deben ocurrir una vez, como establecer parámetros de entorno de OpenGL o inicializar objetos gráficos de OpenGL. -
onDrawFrame()
: El sistema llama a este método cada vez que se vuelve a dibujarGLSurfaceView
. Utiliza este método como el punto de ejecución principal para dibujar (y volver a dibujar) objetos gráficos. -
onSurfaceChanged()
: El sistema llama a este método cuando cambia la geometría deGLSurfaceView
, incluidos los cambios en el tamaño deGLSurfaceView
o la orientación de la pantalla del dispositivo. Por ejemplo, el sistema llama a este método cuando el dispositivo cambia de orientación vertical a horizontal. Usa este método para responder a los cambios en el container deGLSurfaceView
.
-
Paquetes de OpenGL ES
Una vez que hayas establecido una vista de container para OpenGL ES usando GLSurfaceView
y GLSurfaceView.Renderer
, podrás comenzar
a llamar a las API de OpenGL con las siguientes clases:
- Paquetes de API de OpenGL ES 1.0/1.1
android.opengl
: Este paquete proporciona una interfaz estática para las clases de OpenGL ES 1.0/1.1 y un mejor rendimiento que las interfaces del paquetejavax.microedition.khronos
.javax.microedition.khronos.opengles
: Este paquete proporciona la implementación estándar de OpenGL ES 1.0/1.1.
- Clase de API de OpenGL ES 2.0
android.opengl.GLES20
: Este paquete proporciona la interfaz para OpenGL ES 2.0 y está disponible a partir de Android 2.2 (API nivel 8).
- Paquetes de API de OpenGL ES 3.0/3.1
android.opengl
: Este paquete proporciona la interfaz para las clases de OpenGL ES 3.0/3.1. La versión 3.0 está disponible a partir de Android 4.3 (API nivel 18). La versión 3.1 está disponible a partir de Android 5.0 (API nivel 21).
Si quieres comenzar a crear una app con OpenGL ES de inmediato, sigue la clase Cómo mostrar gráficos con OpenGL ES.
Cómo declarar requisitos de OpenGL
Si tu aplicación utiliza funciones de OpenGL que no están disponibles en todos los dispositivos, debes incluir estos requisitos en tu archivo AndroidManifest.xml. Estas son las declaraciones de manifiesto de OpenGL más comunes:
- Requisitos de versión de OpenGL ES: Si tu aplicación requiere una versión
específica de
OpenGL ES, debes declarar ese requisito. Para hacerlo, agrega la siguiente configuración a tu manifiesto como
se muestra a continuación.
Para OpenGL ES 2.0:
<!-- Tell the system this app requires OpenGL ES 2.0. --> <uses-feature android:glEsVersion="0x00020000" android:required="true" />
Si agregas esta declaración, Google Play impedirá que tu aplicación se instale en dispositivos no compatibles con OpenGL ES 2.0. Si la aplicación es exclusiva para dispositivos que admiten OpenGL ES 3.0, también puedes especificarlo en el manifiesto:
Para OpenGL ES 3.0:
<!-- Tell the system this app requires OpenGL ES 3.0. --> <uses-feature android:glEsVersion="0x00030000" android:required="true" />
Para OpenGL ES 3.1:
<!-- Tell the system this app requires OpenGL ES 3.1. --> <uses-feature android:glEsVersion="0x00030001" android:required="true" />
Nota: La API de OpenGL ES 3.x es retrocompatible con la API 2.0, lo que significa que puedes ser más flexible con la implementación de OpenGL ES en tu aplicación. Si declaras la API de OpenGL ES 2.0 como un requisito en el manifiesto, puedes usar esa versión de API como la predeterminada, verificar la disponibilidad de la API 3.x durante el tiempo de ejecución y usar funciones de OpenGL ES 3.x si el dispositivo es compatible. Para obtener más información sobre cómo verificar la versión de OpenGL ES compatible con un dispositivo, consulta Cómo averiguar la versión de OpenGL ES.
- Requisitos de compresión de textura: Si tu aplicación utiliza formatos
de compresión de textura, debes declarar los formatos que admite la aplicación en el archivo de manifiesto
con
<supports-gl-texture>
. Para obtener más información sobre los formatos de compresión de textura disponibles, consulta Compatibilidad con la compresión de texturas.Si declaras los requisitos de compresión de texturas en el archivo de manifiesto, se ocultará la aplicación de los usuarios con dispositivos que no admitan al menos uno de los tipos de compresión declarados. Para obtener más información sobre cómo funciona el filtrado de Google Play de las compresiones de textura, consulta la sección Google Play y el filtrado de compresión de texturas de la documentación de
<supports-gl-texture>
.
Cómo asignar coordenadas para objetos dibujados
Uno de los problemas básicos para mostrar gráficos en dispositivos Android es que sus pantallas pueden variar en tamaño y forma. OpenGL adopta un sistema de coordenadas cuadrado y uniforme y, de manera predeterminada, dibuja esas coordenadas en la pantalla normalmente no cuadrada como si tuviera ese formato.

Figura 1: Sistema de coordenadas predeterminado de OpenGL (izquierda) asignado a una pantalla típica de dispositivo Android (derecha)
En la ilustración anterior, se muestra el sistema de coordenadas uniforme que se adopta para un marco OpenGL (izquierda) y cómo estas coordenadas se asignan a una pantalla típica de dispositivo en orientación horizontal (derecha). Para resolver este problema, puedes aplicar modos de proyección OpenGL y vistas de cámara a fin de transformar coordenadas y hacer que tus objetos gráficos tengan las proporciones correctas en cualquier pantalla.
Para aplicar proyección y vistas de cámara, crea una matriz de proyección y una de vista de cámara. Luego, aplica las matrices a la canalización de procesamiento de OpenGL. La matriz de proyección vuelve a calcular las coordenadas de los gráficos para que se asignen correctamente a las pantallas de los dispositivos Android. La matriz de vista de cámara crea una transformación que renderiza objetos desde una posición específica del ojo.
Proyección y vista de cámara en OpenGL ES 1.0
En la API de ES 1.0, puedes aplicar la proyección y la vista de cámara si creas cada matriz y luego las agregas al entorno de OpenGL.
- Matriz de proyección: Crea una matriz de proyección con la geometría de la
pantalla del dispositivo para volver a calcular las coordenadas del objeto de modo que se dibujen con las proporciones correctas.
En el siguiente código de ejemplo, se muestra cómo modificar el método
onSurfaceChanged()
de una implementaciónGLSurfaceView.Renderer
para crear una matriz de proyección basada en la relación de aspecto de la pantalla y aplicarla al entorno de procesamiento de OpenGL.Kotlin
override fun onSurfaceChanged(gl: GL10, width: Int, height: Int) { gl.apply { glViewport(0, 0, width, height) // make adjustments for screen ratio val ratio: Float = width.toFloat() / height.toFloat() glMatrixMode(GL10.GL_PROJECTION) // set matrix to projection mode glLoadIdentity() // reset the matrix to its default state glFrustumf(-ratio, ratio, -1f, 1f, 3f, 7f) // apply the projection matrix } }
Java
public void onSurfaceChanged(GL10 gl, int width, int height) { gl.glViewport(0, 0, width, height); // make adjustments for screen ratio float ratio = (float) width / height; gl.glMatrixMode(GL10.GL_PROJECTION); // set matrix to projection mode gl.glLoadIdentity(); // reset the matrix to its default state gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7); // apply the projection matrix }
- Matriz de transformación de la cámara: Luego de ajustar el sistema de coordenadas
usando una matriz de proyección, también deberás aplicar una vista de cámara. En el siguiente código de ejemplo, se muestra cómo
modificar el método
onDrawFrame()
de una implementaciónGLSurfaceView.Renderer
para aplicar una vista de modelo y usar la utilidadGLU.gluLookAt()
a fin de crear una transformación de visualización que simule la posición de una cámara.Kotlin
override fun onDrawFrame(gl: GL10) { ... gl.apply { // Set GL_MODELVIEW transformation mode glMatrixMode(GL10.GL_MODELVIEW) glLoadIdentity() // reset the matrix to its default state } // When using GL_MODELVIEW, you must set the camera view GLU.gluLookAt(gl, 0f, 0f, -5f, 0f, 0f, 0f, 0f, 1.0f, 0.0f) ... }
Java
public void onDrawFrame(GL10 gl) { ... // Set GL_MODELVIEW transformation mode gl.glMatrixMode(GL10.GL_MODELVIEW); gl.glLoadIdentity(); // reset the matrix to its default state // When using GL_MODELVIEW, you must set the camera view GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f); ... }
Proyección y vista de cámara en OpenGL ES 2.0 y versiones posteriores
En las API de ES 2.0 y 3.0, puedes aplicar la proyección y la vista de cámara si agregas primero un miembro de la matriz a los sombreadores de vértices de los objetos gráficos. Con este miembro de la matriz agregado, puedes generar y aplicar matrices de proyección y de visualización de cámara a tus objetos.
- Agrega una matriz a los sombreadores de vértices: Crea una variable para la matriz de proyección de vista
y luego inclúyela como un multiplicador de la posición del sombreador. En el siguiente ejemplo de código de sombreador de
vértices, el miembro
uMVPMatrix
incluido te permite aplicar matrices de proyección y visualización de cámara a las coordenadas de los objetos que usan este sombreador.Kotlin
private val vertexShaderCode = // This matrix member variable provides a hook to manipulate // the coordinates of objects that use this vertex shader. "uniform mat4 uMVPMatrix; \n" + "attribute vec4 vPosition; \n" + "void main(){ \n" + // The matrix must be included as part of gl_Position // Note that the uMVPMatrix factor *must be first* in order // for the matrix multiplication product to be correct. " gl_Position = uMVPMatrix * vPosition; \n" + "} \n"
Java
private final String vertexShaderCode = // This matrix member variable provides a hook to manipulate // the coordinates of objects that use this vertex shader. "uniform mat4 uMVPMatrix; \n" + "attribute vec4 vPosition; \n" + "void main(){ \n" + // The matrix must be included as part of gl_Position // Note that the uMVPMatrix factor *must be first* in order // for the matrix multiplication product to be correct. " gl_Position = uMVPMatrix * vPosition; \n" + "} \n";
Nota: En el ejemplo anterior, se define un miembro de matriz de transformación único en el sombreador de vértices en el que aplicas una matriz de proyección y una matriz de vista de cámara combinadas. Según los requisitos de tu aplicación, tal vez quieras definir miembros separados de la matriz de proyección y la matriz de visualización de cámara en tus sombreadores de vértices para poder cambiarlos de forma independiente.
- Accede a la matriz del sombreador: Después de crear un enlace en los sombreadores de vértices
para aplicar la proyección y la vista de cámara, puedes acceder a esa variable a fin de aplicar las matrices de proyección y de
visualización de cámara. En el siguiente código, se muestra cómo modificar el método
onSurfaceCreated()
de una implementaciónGLSurfaceView.Renderer
para acceder a la variable de la matriz definida en el sombreador de vértices anterior.Kotlin
override fun onSurfaceCreated(gl: GL10, config: EGLConfig) { ... muMVPMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix") ... }
Java
public void onSurfaceCreated(GL10 unused, EGLConfig config) { ... muMVPMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix"); ... }
- Crea matrices de proyección y visualización de cámara: Genera las matrices de proyección y
visualización que aplicarás a los objetos gráficos. En el siguiente código de ejemplo, se muestra cómo modificar
los métodos
onSurfaceCreated()
yonSurfaceChanged()
de una implementaciónGLSurfaceView.Renderer
para crear una matriz de vista de cámara y una matriz de proyección según la relación de aspecto de la pantalla del dispositivo.Kotlin
override fun onSurfaceCreated(gl: GL10, config: EGLConfig) { ... // Create a camera view matrix Matrix.setLookAtM(vMatrix, 0, 0f, 0f, -3f, 0f, 0f, 0f, 0f, 1.0f, 0.0f) } override fun onSurfaceChanged(gl: GL10, width: Int, height: Int) { GLES20.glViewport(0, 0, width, height) val ratio: Float = width.toFloat() / height.toFloat() // create a projection matrix from device screen geometry Matrix.frustumM(projMatrix, 0, -ratio, ratio, -1f, 1f, 3f, 7f) }
Java
public void onSurfaceCreated(GL10 unused, EGLConfig config) { ... // Create a camera view matrix Matrix.setLookAtM(vMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f); } public void onSurfaceChanged(GL10 unused, int width, int height) { GLES20.glViewport(0, 0, width, height); float ratio = (float) width / height; // create a projection matrix from device screen geometry Matrix.frustumM(projMatrix, 0, -ratio, ratio, -1, 1, 3, 7); }
- Aplicar matrices de proyección y de visualización de cámara: Para aplicar las transformaciones de proyección
y vista de cámara, multiplica las matrices y luego establécelas en el sombreador
de vértices. En el siguiente código de ejemplo, se muestra cómo modificar el método
onDrawFrame()
de una implementaciónGLSurfaceView.Renderer
para combinar la matriz de proyección con la vista de cámara creada en el código anterior y luego aplicarla a los objetos gráficos que va a renderizar OpenGL.Kotlin
override fun onDrawFrame(gl: GL10) { ... // Combine the projection and camera view matrices Matrix.multiplyMM(vPMatrix, 0, projMatrix, 0, vMatrix, 0) // Apply the combined projection and camera view transformations GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, vPMatrix, 0) // Draw objects ... }
Java
public void onDrawFrame(GL10 unused) { ... // Combine the projection and camera view matrices Matrix.multiplyMM(vPMatrix, 0, projMatrix, 0, vMatrix, 0); // Apply the combined projection and camera view transformations GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, vPMatrix, 0); // Draw objects ... }
Para ver un ejemplo completo de cómo aplicar la proyección y la vista de cámara con OpenGL ES 2.0, consulta la clase Cómo mostrar gráficos con OpenGL ES.
Caras de las formas y devanado
En OpenGL, la cara de una forma es una superficie definida por tres o más puntos en el espacio tridimensional. Un conjunto de tres o más puntos tridimensionales (llamados vértices en OpenGL) tiene una cara frontal y una posterior. ¿Cómo puedes saber cuál es cuál? Buena pregunta. La respuesta tiene que ver con el devanado, o la dirección en la que defines los puntos de una forma.

Figura 1: Ilustración de una lista de coordenadas que se traduce en un orden de dibujo en el sentido antihorario
En este ejemplo, los puntos del triángulo se definen en un orden tal que se dibujan en el sentido antihorario. El orden en el que se dibujan estas coordenadas define la dirección del devanado de la forma. De manera predeterminada, en OpenGL, la cara que se dibuja en sentido antihorario es la cara frontal. El triángulo que se muestra en la figura 1 se define de modo que mires la cara frontal de la forma (según la interpreta OpenGL) y el otro lado sea la cara posterior.
¿Por qué es importante saber cuál es la cara frontal de una forma? La respuesta tiene que ver con una función de OpenGL que se usa a menudo y se llama eliminación de caras. La eliminación de caras es una opción para el entorno de OpenGL que permite que la canalización de procesamiento ignore (no calcule ni dibuje) la cara posterior de una forma, lo que ayuda a ahorrar tiempo, memoria y ciclos de procesamiento:
Kotlin
gl.apply { // enable face culling feature glEnable(GL10.GL_CULL_FACE) // specify which faces to not draw glCullFace(GL10.GL_BACK) }
Java
// enable face culling feature gl.glEnable(GL10.GL_CULL_FACE); // specify which faces to not draw gl.glCullFace(GL10.GL_BACK);
Si intentas usar la función de eliminación de caras sin saber cuáles son los lados frontal y posterior de tus formas, los gráficos de OpenGL se verán un poco delgados o tal vez no se mostrarán. Por lo tanto, siempre define las coordenadas de tus formas de OpenGL en un orden de dibujo en sentido antihorario.
Nota: Puedes configurar un entorno de OpenGL para que se interprete que la cara en sentido horario es la frontal; pero, si lo haces, necesitarás más código y es probable que confundas a los desarrolladores expertos de OpenGL cuando les pidas ayuda. Te recomendamos que no lo hagas.
Versiones de OpenGL y compatibilidad de dispositivos
Las especificaciones de la API de OpenGL ES 1.0 y 1.1 son compatibles desde Android 1.0. A partir de Android 2.2 (API nivel 8), el marco de trabajo admite la especificación de la API de OpenGL ES 2.0. OpenGL ES 2.0 es compatible con la mayoría de los dispositivos Android y se recomienda para las aplicaciones nuevas que se desarrollan con OpenGL. OpenGL ES 3.0 es compatible con Android 4.3 (API nivel 18) y versiones posteriores en dispositivos que proporcionan una implementación de la API de OpenGL ES 3.0. Para obtener más información sobre la cantidad relativa de dispositivos con Android que admiten una versión determinada de OpenGL ES, consulta el panel de versiones de OpenGL ES.
La programación de gráficos con la API de OpenGL ES 1.0/1.1 es muy diferente a usar la versión 2.0 y versiones posteriores. La versión 1.x de la API tiene métodos más convenientes y una canalización gráfica fija, mientras que las API de OpenGL ES 2.0 y 3.0 proporcionan un control más directo de la canalización mediante el uso de sombreadores de OpenGL. Debes analizar en detalle los requisitos gráficos y elegir la versión de la API que funcione mejor para tu aplicación. Para obtener más información, consulta Cómo elegir una versión de la API de OpenGL.
La API de OpenGL ES 3.0 proporciona funciones adicionales y un mejor rendimiento que la API 2.0, y también es retrocompatible. Esto significa que podrías escribir tu aplicación dirigida a OpenGL ES 2.0 y luego incluir con condiciones funciones gráficas de OpenGL ES 3.0 si están disponibles. Para obtener más información sobre cómo comprobar la disponibilidad de la API 3.0, consulta Cómo averiguar la versión de OpenGL ES.
Compatibilidad con la compresión de texturas
La compresión de texturas puede aumentar de forma significativa el rendimiento de tu aplicación de OpenGL,
ya que reduce los requisitos de memoria y hace un uso más eficiente del ancho de banda de la memoria. El marco de trabajo
de Android ofrece compatibilidad para el formato de compresión ETC1 como una función predeterminada, lo que incluye una
clase de utilidad ETC1Util
y la herramienta de compresión etc1tool
(que se encuentra en el
SDK de Android en <sdk>/tools/
). Si quieres ver un ejemplo de una aplicación para Android que usa
la compresión de texturas, consulta el ejemplo de código CompressedTextureActivity
en el SDK de Android
(<sdk>/samples/<version>/ApiDemos/src/com/example/android/apis/graphics/
).
Precaución: El formato ETC1 es compatible con la mayoría de los dispositivos Android,
pero no se garantiza que esté disponible. Para comprobar si el formato ETC1 es compatible con un dispositivo, llama al
método ETC1Util.isETC1Supported()
.
Nota: El formato de compresión de texturas ETC1 no admite texturas con una transparencia (canal alfa). Si tu aplicación requiere texturas transparentes, debes investigar otros formatos de compresión de texturas disponibles en los dispositivos de destino.
Se garantiza que los formatos de compresión de texturas ETC2/EAC estarán disponibles cuando se use la API de OpenGL ES 3.0. Este formato de textura ofrece excelentes proporciones de compresión con alta calidad visual y el formato también admite la transparencia (canal alfa).
Más allá de los formatos ETC, los dispositivos Android tienen compatibilidad variada con la compresión de texturas en función de sus chipsets de GPU y sus implementaciones de OpenGL. Debes investigar la compatibilidad con la compresión de texturas en los dispositivos a los que orientes tu aplicación para determinar qué tipos de compresión debe admitir. Para determinar qué formatos de texturas son compatibles con un dispositivo específico, debes consultar el dispositivo y revisar los nombres de extensión de OpenGL, que identifican los formatos de compresión de texturas (y otras funciones de OpenGL) que son compatibles con el dispositivo. Estos son algunos formatos de compresión de texturas que se suelen admitir:
- ATITC (ATC): La compresión de texturas ATI (ATITC o ATC) está disponible en una
amplia variedad de dispositivos y admite la compresión a una velocidad fija para texturas RGB con y sin
un canal alfa. Este formato se puede representar con varios nombres de extensión de OpenGL, por ejemplo:
GL_AMD_compressed_ATC_texture
GL_ATI_texture_compression_atitc
- PVRTC: La compresión de texturas PowerVR (PVRTC) está disponible en una amplia
variedad de dispositivos y admite texturas de 2 bits y 4 bits por píxel con o sin un canal alfa.
Este formato se representa con el siguiente nombre de extensión de OpenGL:
GL_IMG_texture_compression_pvrtc
- S3TC (DXTn/DXTC): La compresión de texturas S3 (S3TC) tiene diferentes
variaciones de formato (DXT1 a DXT5) y su disponibilidad no es tan amplia. El formato admite texturas RGB con
canales alfa de 4 bits o de 8 bits. Estos formatos se representan con el siguiente nombre de extensión de
OpenGL:
GL_EXT_texture_compression_s3tc
GL_EXT_texture_compression_dxt1
- 3DC: La compresión de texturas 3DC (3DC) es un formato menos disponible que
admite texturas RGB con un canal alfa. Este formato se representa con el siguiente nombre
de extensión de OpenGL:
GL_AMD_compressed_3DC_texture
Advertencia: Estos formatos de compresión de texturas no son compatibles con todos los dispositivos. La compatibilidad con estos formatos puede variar según el fabricante y el dispositivo. Para obtener más información sobre cómo determinar qué formatos de compresión de texturas tiene un dispositivo en particular, consulta la siguiente sección.
Nota: Cuando hayas determinado los formatos de compresión de texturas que admite tu aplicación, asegúrate de declararlos en el manifiesto con <supports-gl-texture>. Usar esta declaración permite filtrar por servicios externos, como Google Play, para que tu app se instale solo en dispositivos compatibles con los formatos que requiere la app. Para obtener más información, consulta Declaraciones de manifiesto de OpenGL.
Cómo determinar las extensiones de OpenGL
Las implementaciones de OpenGL varían según el dispositivo Android en términos de las extensiones de la API de OpenGL ES que son compatibles. Estas extensiones incluyen las compresiones de texturas, pero también suelen incluir otras extensiones del conjunto de funciones de OpenGL.
Para determinar los formatos de compresión de texturas y otras extensiones de OpenGL que son compatibles con un dispositivo en particular, realiza lo siguiente:
- Ejecuta el siguiente código en tus dispositivos de destino para determinar qué formatos de compresión de texturas
son compatibles:
Kotlin
var extensions = gl.glGetString(GL10.GL_EXTENSIONS)
Java
String extensions = gl.glGetString(GL10.GL_EXTENSIONS);
Advertencia: Los resultados de esta llamada varían según el modelo del dispositivo. Debes ejecutar esta llamada en varios dispositivos de destino para determinar qué tipos de compresión suelen admitirse.
- Revisa el resultado de este método para determinar qué extensiones de OpenGL son compatibles con el dispositivo.
Paquete de extensiones de Android (AEP)
El AEP garantiza que tu aplicación sea compatible con un conjunto estandarizado de extensiones de OpenGL más allá del conjunto central descrito en la especificación de OpenGL 3.1. Crear un paquete de estas extensiones fomenta un conjunto consistente de funcionalidades en todos los dispositivos y, al mismo tiempo, permite a los desarrolladores aprovechar al máximo la última generación de GPU para dispositivos móviles.
El AEP también mejora la compatibilidad para imágenes, búferes de almacenamiento de sombreadores y contadores atómicos en sombreadores de fragmentos.
Para que tu app pueda usar el AEP, su manifiesto debe declarar que se requiere el AEP. Además, la versión de la plataforma debe ser compatible.
Sigue estos pasos para declarar que se requiere el AEP en el manifiesto:
<uses feature android:name="android.hardware.opengles.aep" android:required="true" />
Para verificar que la versión de la plataforma es compatible con el AEP, utiliza el
método hasSystemFeature(String)
y pasa
FEATURE_OPENGLES_EXTENSION_PACK
como el argumento. En el siguiente fragmento de código,
se muestra un ejemplo de cómo hacerlo:
Kotlin
var deviceSupportsAEP: Boolean = packageManager.hasSystemFeature(PackageManager.FEATURE_OPENGLES_EXTENSION_PACK)
Java
boolean deviceSupportsAEP = getPackageManager().hasSystemFeature (PackageManager.FEATURE_OPENGLES_EXTENSION_PACK);
Si el método muestra el valor true, el AEP es compatible.
Para obtener más información sobre el AEP, visita su página en el Registro de OpenGL ES de Khronos.
Cómo averiguar la versión de OpenGL ES
Hay varias versiones de OpenGL ES disponibles en los dispositivos Android. Puedes especificar la versión mínima de la API que requiere tu aplicación en el manifiesto, pero, al mismo tiempo, también puedes aprovechar las funciones de una API más nueva. Por ejemplo, la API de OpenGL ES 3.0 es retrocompatible con la versión 2.0 de la API, por lo que tal vez quieras escribir tu aplicación de manera que use las funciones de OpenGL ES 3.0, pero recurra a la API 2.0 si la API 3.0 no está disponible.
Antes de usar las funciones de OpenGL ES desde una versión posterior al mínimo requerido en el manifiesto de tu aplicación, esta debe verificar la versión de la API disponible en el dispositivo. Para eso, puedes usar uno de estos métodos:
- Intenta crear el contexto de OpenGL ES de nivel superior (
EGLContext
) y comprueba el resultado. - Crea un contexto de OpenGL ES con compatibilidad mínima y comprueba el valor de la versión.
En el siguiente código de ejemplo, se muestra cómo verificar la versión disponible de OpenGL ES creando
un EGLContext
y verificando el resultado. Este ejemplo muestra cómo verificar
la versión OpenGL ES 3.0:
Kotlin
private const val EGL_CONTEXT_CLIENT_VERSION = 0x3098 private const val glVersion = 3.0 private class ContextFactory : GLSurfaceView.EGLContextFactory { override fun createContext(egl: EGL10, display: EGLDisplay, eglConfig: EGLConfig): EGLContext { Log.w(TAG, "creating OpenGL ES $glVersion context") return egl.eglCreateContext( display, eglConfig, EGL10.EGL_NO_CONTEXT, intArrayOf(EGL_CONTEXT_CLIENT_VERSION, glVersion.toInt(), EGL10.EGL_NONE) ) // returns null if 3.0 is not supported } }
Java
private static double glVersion = 3.0; private static class ContextFactory implements GLSurfaceView.EGLContextFactory { private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098; public EGLContext createContext( EGL10 egl, EGLDisplay display, EGLConfig eglConfig) { Log.w(TAG, "creating OpenGL ES " + glVersion + " context"); int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, (int) glVersion, EGL10.EGL_NONE }; // attempt to create a OpenGL ES 3.0 context EGLContext context = egl.eglCreateContext( display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); return context; // returns null if 3.0 is not supported; } }
Si el método createContext()
anterior muestra un valor nulo, el código debería crear un contexto
de OpenGL ES 2.0 y volver a usar solo esa API.
En el siguiente código de ejemplo, se muestra cómo comprobar la versión de OpenGL ES creando primero un contexto mínimo admitido y luego verificando la string de la versión:
Kotlin
// Create a minimum supported OpenGL ES context, then check: gl.glGetString(GL10.GL_VERSION).also { Log.w(TAG, "Version: $it") } // The version format is displayed as: "OpenGL ES <major>.<minor>" // followed by optional content provided by the implementation.
Java
// Create a minimum supported OpenGL ES context, then check: String version = gl.glGetString(GL10.GL_VERSION); Log.w(TAG, "Version: " + version ); // The version format is displayed as: "OpenGL ES <major>.<minor>" // followed by optional content provided by the implementation.
Con este enfoque, si detectas que el dispositivo admite una versión de la API de nivel superior, debes destruir el contexto mínimo de OpenGL ES y crear un nuevo contexto con la versión más alta disponible de la API.
Cómo elegir una versión de la API de OpenGL
La versión de la API de OpenGL ES 1.0 (y las extensiones 1.1), la versión 2.0 y la versión 3.0 proporcionan interfaces gráficas de alto rendimiento para crear juegos 3D, visualizaciones e interfaces de usuario. La programación de gráficos para OpenGL ES 2.0 y 3.0 es muy similar, y la versión 3.0 representa un superconjunto de la API 2.0 con funciones adicionales. La programación para la API de OpenGL ES 1.0/1.1 y para OpenGL ES 2.0 y 3.0 difiere significativamente, por lo que los desarrolladores deben analizar con cuidado los siguientes factores antes de iniciar el desarrollo con estas API:
- Rendimiento: En general, OpenGL ES 2.0 y 3.0 proporcionan un rendimiento de gráficos más rápido que las API de ES 1.0/1.1. Sin embargo, la diferencia de rendimiento puede variar según el dispositivo Android en el que se ejecuta tu aplicación de OpenGL debido a las diferencias en la implementación que hace el fabricante de hardware de la canalización de gráficos de OpenGL ES.
- Compatibilidad del dispositivo: Los desarrolladores deben considerar los tipos de dispositivos, las versiones de Android y las versiones de OpenGL ES disponibles para sus clientes. Para obtener más información sobre la compatibilidad de OpenGL en los dispositivos, consulta la sección Versiones de OpenGL y compatibilidad de dispositivos.
- Conveniencia de la codificación: La API de OpenGL ES 1.0/1.1 ofrece una canalización de funciones fija y funciones convenientes que no están disponibles en las API de OpenGL ES 2.0 o 3.0. Los desarrolladores que recién comienzan a usar OpenGL ES pueden notar que la codificación para la versión 1.0/1.1 es más rápida y conveniente.
- Control de gráficos: Las API de OpenGL ES 2.0 y 3.0 proporcionan un mayor grado de control, ya que brindan una canalización totalmente programable mediante el uso de sombreadores. Con un control más directo de la canalización de procesamiento de gráficos, los desarrolladores pueden crear efectos que serían muy difíciles de generar con la API 1.0/1.1.
- Compatibilidad con texturas: La API de OpenGL ES 3.0 ofrece la mejor compatibilidad con la compresión de texturas porque garantiza la disponibilidad del formato de compresión ETC2, que admite la transparencia. Las implementaciones de la API 1.x y 2.0 generalmente incluyen compatibilidad con ETC1. Sin embargo, este formato de textura no admite la transparencia y, por lo tanto, debes proporcionar recursos en otros formatos de compresión compatibles con los dispositivos a los que orientas la aplicación. Para obtener más información, consulta Compatibilidad con la compresión de texturas.
Si bien el rendimiento, la compatibilidad, la conveniencia, el control y otros factores pueden influir en tu decisión, debes elegir una versión de la API de OpenGL según lo que consideres que brinda la mejor experiencia a los usuarios.