OpenGL ES

Android est compatible avec les graphismes 2D et 3D hautes performances avec la bibliothèque Open Graphics (OpenGL®), et plus précisément avec l'API OpenGL ES. OpenGL est une API graphique multiplate-forme qui spécifie une interface logicielle standard pour le matériel de traitement graphique 3D. OpenGL ES est un type de spécification OpenGL destiné aux appareils embarqués. Android est compatible avec plusieurs versions de l'API OpenGL ES:

  • OpenGL ES 1.0 et 1.1 : cette spécification d'API est compatible avec Android 1.0 et versions ultérieures.
  • OpenGL ES 2.0 : cette spécification d'API est compatible avec Android 2.2 (niveau d'API 8) ou version ultérieure.
  • OpenGL ES 3.0 : cette spécification d'API est compatible avec Android 4.3 (niveau d'API 18) ou version ultérieure.
  • OpenGL ES 3.1 : cette spécification d'API est compatible avec Android 5.0 (niveau d'API 21) ou version ultérieure.

Attention:Quelle que soit la version de la plate-forme Android, un appareil ne peut pas prendre en charge l'API OpenGL ES 3.0, sauf si le fabricant de l'appareil fournit une implémentation de ce pipeline graphique. Si vous spécifiez dans le fichier manifeste qu'OpenGL ES 3.0 est requis, vous pouvez être sûr que cette version sera présente sur l'appareil. Si vous spécifiez qu'une version de niveau inférieur est requise, mais que vous souhaitez utiliser les fonctionnalités 3.0 si elles sont disponibles, vous devez vérifier au moment de l'exécution pour connaître la version d'OpenGL compatible avec l'appareil. Pour savoir comment procéder, consultez la section Vérifier la version d'OpenGL ES.

Remarque:L'API spécifique fournie par le framework Android est semblable à l'API OpenGL ES J2ME JSR239, mais elle n'est pas identique. Si vous connaissez bien la spécification JSR239, soyez à l'affût des variations.

Voir aussi

Principes de base

Android est compatible avec OpenGL via son API de framework et le kit de développement natif (NDK). Cet article porte sur les interfaces du framework Android. Pour en savoir plus sur le NDK, consultez le NDK Android.

Le framework Android comporte deux classes de base qui vous permettent de créer et de manipuler des graphiques avec l'API OpenGL ES: GLSurfaceView et GLSurfaceView.Renderer. Si votre objectif est d'utiliser OpenGL dans votre application Android, votre objectif premier est de comprendre comment implémenter ces classes dans une activité.

GLSurfaceView
Cette classe est une View dans laquelle vous pouvez dessiner et manipuler des objets à l'aide d'appels d'API OpenGL. Sa fonction est semblable à celle d'une SurfaceView. Pour utiliser cette classe, créez une instance de GLSurfaceView et ajoutez-y votre Renderer. Toutefois, si vous souhaitez capturer des événements d'écran tactile, vous devez étendre la classe GLSurfaceView pour implémenter les écouteurs tactiles, comme indiqué dans la leçon d'entraînement OpenGL intitulée Répondre aux événements tactiles.
GLSurfaceView.Renderer
Cette interface définit les méthodes requises pour dessiner des graphiques dans un élément GLSurfaceView. Vous devez fournir une implémentation de cette interface en tant que classe distincte et l'associer à votre instance GLSurfaceView à l'aide de GLSurfaceView.setRenderer().

L'interface GLSurfaceView.Renderer nécessite l'implémentation des méthodes suivantes:

  • onSurfaceCreated(): le système appelle cette méthode une fois lors de la création de l'GLSurfaceView. Utilisez cette méthode pour effectuer des actions qui ne doivent être effectuées qu'une seule fois, telles que la définition des paramètres d'environnement OpenGL ou l'initialisation d'objets graphiques OpenGL.
  • onDrawFrame(): le système appelle cette méthode à chaque redessinage de GLSurfaceView. Utilisez cette méthode comme point d'exécution principal pour dessiner (et redessiner) des objets graphiques.
  • onSurfaceChanged(): le système appelle cette méthode lorsque la géométrie GLSurfaceView change, y compris en cas de changement de taille de GLSurfaceView ou d'orientation de l'écran de l'appareil. Par exemple, le système appelle cette méthode lorsque l'appareil passe de l'orientation portrait à l'orientation paysage. Utilisez cette méthode pour répondre aux modifications apportées au conteneur GLSurfaceView.

Packages OpenGL ES

Une fois que vous avez établi une vue du conteneur pour OpenGL ES à l'aide de GLSurfaceView et GLSurfaceView.Renderer, vous pouvez commencer à appeler les API OpenGL à l'aide des classes suivantes:

Si vous souhaitez commencer à créer une application avec OpenGL ES immédiatement, suivez la classe Afficher des graphiques avec OpenGL ES.

Déclarer des exigences OpenGL

Si votre application utilise des fonctionnalités OpenGL qui ne sont pas disponibles sur tous les appareils, vous devez inclure ces exigences dans votre fichier AndroidManifest.xml. Voici les déclarations de fichier manifeste OpenGL les plus courantes:

  • Exigences relatives à la version OpenGL ES : si votre application nécessite une version spécifique d'OpenGL ES, vous devez déclarer cette exigence en ajoutant les paramètres suivants à votre fichier manifeste, comme indiqué ci-dessous.

    Pour OpenGL ES 2.0:

    <!-- Tell the system this app requires OpenGL ES 2.0. -->
    <uses-feature android:glEsVersion="0x00020000" android:required="true" />
    

    L'ajout de cette déclaration empêche Google Play d'installer votre application sur les appareils non compatibles avec OpenGL ES 2.0. Si votre application est destinée exclusivement aux appareils compatibles avec OpenGL ES 3.0, vous pouvez également l'indiquer dans votre fichier manifeste:

    Pour OpenGL ES 3.0:

    <!-- Tell the system this app requires OpenGL ES 3.0. -->
    <uses-feature android:glEsVersion="0x00030000" android:required="true" />
    

    Pour OpenGL ES 3.1:

    <!-- Tell the system this app requires OpenGL ES 3.1. -->
    <uses-feature android:glEsVersion="0x00030001" android:required="true" />
    

    Remarque:L'API OpenGL ES 3.x est rétrocompatible avec l'API 2.0, ce qui signifie que vous pouvez implémenter OpenGL ES de manière plus flexible dans votre application. En déclarant l'API OpenGL ES 2.0 comme exigence dans votre fichier manifeste, vous pouvez utiliser cette version d'API par défaut, vérifier la disponibilité de l'API 3.x au moment de l'exécution, puis utiliser les fonctionnalités OpenGL ES 3.x si l'appareil le permet. Pour savoir comment vérifier la version d'OpenGL ES compatible avec un appareil, consultez la section Vérifier la version d'OpenGL ES.

  • Exigences concernant la compression de texture : si votre application utilise des formats de compression de texture, vous devez déclarer les formats compatibles avec votre fichier manifeste à l'aide de <supports-gl-texture>. Pour en savoir plus sur les formats de compression de texture disponibles, consultez la page Compatibilité avec la compression de texture.

    La déclaration d'exigences de compression de texture dans le fichier manifeste masque votre application aux utilisateurs dont les appareils ne sont pas compatibles avec au moins l'un des types de compression que vous avez déclarés. Pour en savoir plus sur le fonctionnement du filtrage Google Play pour les compressions de texture, consultez la section Google Play et filtrage par compression de texture de la documentation <supports-gl-texture>.

Cartographier des coordonnées pour les objets dessinés

L'un des problèmes de base lors de l'affichage des éléments graphiques sur les appareils Android est que la taille et la forme des écrans peuvent varier. OpenGL suppose un système de coordonnées uniformes carrés et, par défaut, dessine ces coordonnées sur votre écran généralement non carré comme si celui-ci était parfaitement carré.

Figure 1 : Système de coordonnées OpenGL par défaut (à gauche) mappé sur un écran d'appareil Android standard (à droite).

L'illustration ci-dessus montre le système de coordonnées uniformes appliqué à une image OpenGL à gauche et la manière dont ces coordonnées sont mappées à un écran d'appareil classique en mode paysage à droite. Pour résoudre ce problème, vous pouvez appliquer des modes de projection OpenGL et des vues de caméra pour transformer les coordonnées afin que vos objets graphiques aient les proportions correctes sur n'importe quel écran.

Pour appliquer des vues de projection et de caméra, vous devez créer une matrice de projection et une matrice de vues de caméra, puis les appliquer au pipeline de rendu OpenGL. La matrice de projection recalcule les coordonnées de vos éléments graphiques pour les faire correspondre correctement aux écrans des appareils Android. La matrice de vue de la caméra crée une transformation qui affiche les objets à partir d'une position spécifique de l'œil.

Projection et vue de l'appareil photo dans OpenGL ES 1.0

Dans l'API ES 1.0, pour appliquer la projection et la vue de caméra, créez chaque matrice, puis ajoutez-les à l'environnement OpenGL.

  1. Matrice de projection : créez une matrice de projection à l'aide de la géométrie de l'écran de l'appareil afin de recalculer les coordonnées des objets afin qu'elles soient dessinées avec des proportions correctes. L'exemple de code suivant montre comment modifier la méthode onSurfaceChanged() d'une implémentation GLSurfaceView.Renderer pour créer une matrice de projection basée sur le format de l'écran et l'appliquer à l'environnement de rendu 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
    }
    
  2. Matrice de transformation de la caméra : une fois que vous avez ajusté le système de coordonnées à l'aide d'une matrice de projection, vous devez également appliquer une vue de caméra. L'exemple de code suivant montre comment modifier la méthode onDrawFrame() d'une implémentation GLSurfaceView.Renderer pour appliquer une vue de modèle et utiliser l'utilitaire GLU.gluLookAt() pour créer une transformation de visionnage qui simule une position de caméra.

    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);
        ...
    }
    

Projection et vue de l'appareil photo dans OpenGL ES 2.0 ou version ultérieure

Dans les API ES 2.0 et 3.0, pour appliquer la projection et la vue de caméra, commencez par ajouter un membre matriciel aux nuanceurs de sommets de vos objets graphiques. Avec ce membre de matrice ajouté, vous pouvez ensuite générer et appliquer des matrices de projection et de vue de caméra à vos objets.

  1. Ajouter une matrice aux nuanceurs de sommets : créez une variable pour la matrice de projection de vues et incluez-la en tant que multiplicateur de la position du nuanceur. Dans l'exemple de code de nuanceur de sommets suivant, le membre uMVPMatrix inclus vous permet d'appliquer des matrices de projection et de visualisation de la caméra aux coordonnées des objets qui utilisent ce nuanceur.

    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";
    

    Remarque:L'exemple ci-dessus définit un seul membre de la matrice de transformation dans le nuanceur de sommets, dans lequel vous appliquez une matrice de projection combinée à une matrice de vue de la caméra. En fonction des exigences de votre application, vous pouvez définir des membres distincts de la matrice de projection et de la matrice de visualisation des caméras dans vos nuanceurs de sommets, afin de pouvoir les modifier indépendamment.

  2. Accéder à la matrice de nuanceurs : après avoir créé un hook dans vos nuanceurs de sommets pour appliquer la projection et la vue de la caméra, vous pouvez accéder à cette variable pour appliquer des matrices de projection et d'affichage de la caméra. Le code suivant montre comment modifier la méthode onSurfaceCreated() d'une implémentation GLSurfaceView.Renderer pour accéder à la variable matricielle définie dans le nuanceur de sommets ci-dessus.

    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");
        ...
    }
    
  3. Créer des matrices de projection et d'affichage de caméra : générez les matrices de projection et de vue à appliquer aux objets graphiques. L'exemple de code suivant montre comment modifier les méthodes onSurfaceCreated() et onSurfaceChanged() d'une implémentation de GLSurfaceView.Renderer pour créer une matrice de vues de la caméra et une matrice de projection basée sur le format de l'écran de l'appareil.

    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);
    }
    
  4. Appliquer des matrices de projection et d'affichage de la caméra : pour appliquer les transformations de projection et de vue de la caméra, multipliez les matrices ensemble, puis définissez-les dans le nuanceur de sommets. L'exemple de code suivant montre comment modifier la méthode onDrawFrame() d'une implémentation GLSurfaceView.Renderer pour combiner la matrice de projection et la vue de caméra créées dans le code ci-dessus, puis comment l'appliquer aux objets graphiques à afficher par 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
        ...
    }
    

Pour obtenir un exemple complet d'application de la projection et de la vue de caméra avec OpenGL ES 2.0, consultez la classe Afficher des graphiques avec OpenGL ES.

Forme des faces et enroulement

Dans OpenGL, la face d'une forme est une surface définie par au moins trois points dans un espace tridimensionnel. Un ensemble de trois points en trois dimensions ou plus (appelés sommets dans OpenGL) a une face avant et une face arrière. Comment savoir quel visage est à l'avant et lequel est à l'arrière ? Bonne question. La réponse concerne le tracé, c'est-à-dire la direction dans laquelle vous définissez les points d'une forme.

Les coordonnées au
sommet d&#39;un triangle

Figure 1 : Illustration d'une liste de coordonnées se traduisant dans un ordre de traçage dans le sens inverse des aiguilles d'une montre.

Dans cet exemple, les points du triangle sont définis dans l'ordre de façon à ce qu'ils soient dessinés dans le sens inverse des aiguilles d'une montre. L'ordre dans lequel ces coordonnées sont tracées définit la direction du tracé de la forme. Par défaut, dans OpenGL, la face avant est dessinée dans le sens inverse des aiguilles d'une montre. Le triangle de la figure 1 est défini de manière à regarder la face avant de la forme (interprétée par OpenGL), et l'autre côté est la face arrière.

Pourquoi est-il important de savoir quelle face d'une forme est la face avant ? La réponse porte sur une fonctionnalité couramment utilisée d'OpenGL : la sélection de visages. La sélection de visages est une option de l'environnement OpenGL qui permet au pipeline de rendu d'ignorer (et non de calculer ni de dessiner) la face arrière d'une forme, ce qui permet de gagner du temps, d'économiser de la mémoire et des cycles de traitement:

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 vous essayez d'utiliser la fonctionnalité de sélection des visages sans savoir quels côtés de vos formes figurent à l'avant et à l'arrière, vos graphiques OpenGL seront un peu minces, voire ne s'afficheront pas du tout. Par conséquent, définissez toujours les coordonnées de vos formes OpenGL dans l'ordre inverse des aiguilles d'une montre.

Remarque:Il est possible de configurer un environnement OpenGL pour qu'il traite la clock face comme étant la face avant, mais cela nécessite plus de code et risque de perturber les développeurs OpenGL expérimentés lorsque vous leur demandez de l'aide. Alors ne le faites pas.

Versions d'OpenGL et compatibilité des appareils

Les spécifications de l'API OpenGL ES 1.0 et 1.1 sont compatibles depuis Android 1.0. À partir d'Android 2.2 (niveau d'API 8), le framework est compatible avec la spécification de l'API OpenGL ES 2.0. OpenGL ES 2.0 est compatible avec la plupart des appareils Android et est recommandé pour les nouvelles applications développées avec OpenGL. OpenGL ES 3.0 est compatible avec Android 4.3 (niveau d'API 18) ou version ultérieure sur les appareils fournissant une implémentation de l'API OpenGL ES 3.0. Pour en savoir plus sur le nombre relatif d'appareils Android compatibles avec une version donnée d'OpenGL ES, consultez le tableau de bord des versions OpenGL ES.

La programmation graphique avec l'API OpenGL ES 1.0/1.1 est très différente de celle des versions 2.0 et ultérieures. La version 1.x de l'API propose des méthodes plus pratiques et un pipeline graphique fixe, tandis que les API OpenGL ES 2.0 et 3.0 offrent un contrôle plus direct du pipeline grâce à l'utilisation des nuanceurs OpenGL. Vous devez bien prendre en compte les exigences graphiques et choisir la version d'API la plus adaptée à votre application. Pour en savoir plus, consultez Choisir une version d'API OpenGL.

L'API OpenGL ES 3.0 offre des fonctionnalités supplémentaires et de meilleures performances que l'API 2.0. Elle est également rétrocompatible. Cela signifie que vous pouvez potentiellement écrire votre application ciblant OpenGL ES 2.0 et inclure sous conditions les fonctionnalités graphiques OpenGL ES 3.0 si elles sont disponibles. Pour en savoir plus sur la vérification de la disponibilité de l'API 3.0, consultez la section Vérifier la version d'OpenGL ES.

Prise en charge de la compression de texture

La compression de texture peut améliorer considérablement les performances de votre application OpenGL en réduisant les besoins en mémoire et en utilisant plus efficacement la bande passante mémoire. Le framework Android est compatible avec le format de compression ETC1 en tant que fonctionnalité standard, y compris une classe utilitaire ETC1Util et l'outil de compression etc1tool (situé dans le SDK Android sous <sdk>/tools/). Pour obtenir un exemple d'application Android utilisant la compression de texture, consultez l'exemple de code CompressedTextureActivity dans le SDK Android (<sdk>/samples/<version>/ApiDemos/src/com/example/android/apis/graphics/).

Attention:Le format ETC1 est compatible avec la plupart des appareils Android, mais sa disponibilité n'est pas garantie. Pour vérifier si le format ETC1 est compatible avec un appareil, appelez la méthode ETC1Util.isETC1Supported().

Remarque:Le format de compression de texture ETC1 n'est pas compatible avec les textures avec une transparence (canal alpha). Si votre application nécessite des textures avec transparence, vous devez étudier d'autres formats de compression de texture disponibles sur vos appareils cibles.

La disponibilité des formats de compression de texture ETC2/EAC est garantie lorsque vous utilisez l'API OpenGL ES 3.0. Ce format de texture offre d'excellents taux de compression avec une haute qualité visuelle. Le format prend également en charge la transparence (canal alpha).

Au-delà des formats ETC, les appareils Android offrent une compatibilité différente pour la compression de texture en fonction de leurs chipsets GPU et de leurs implémentations OpenGL. Vous devez étudier la prise en charge de la compression de texture sur les appareils que vous ciblez pour déterminer les types de compression que votre application doit prendre en charge. Pour déterminer les formats de texture compatibles avec un appareil donné, vous devez interroger l'appareil et examiner les noms des extensions OpenGL, qui identifient les formats de compression de texture (et les autres fonctionnalités OpenGL) compatibles avec l'appareil. Voici quelques formats de compression de texture couramment acceptés:

  • ATITC (ATC) : la compression de texture ATI (ATITC ou ATC) est disponible sur une grande variété d'appareils et est compatible avec la compression à taux fixe pour les textures RVB avec et sans canal alpha. Ce format peut être représenté par plusieurs noms d'extension OpenGL, par exemple :
    • GL_AMD_compressed_ATC_texture
    • GL_ATI_texture_compression_atitc
  • PVRTC : la compression de texture PowerVR (PVRTC) est disponible sur une grande variété d'appareils et est compatible avec les textures 2 bits et 4 bits par pixel, avec ou sans canal alpha. Ce format est représenté par le nom d'extension OpenGL suivant :
    • GL_IMG_texture_compression_pvrtc
  • S3TC (DXTn/DXTC) : la compression de texture S3 (S3TC) présente plusieurs variantes de format (DXT1 à DXT5) et est moins largement disponible. Le format prend en charge les textures RVB avec des canaux alpha 4 bits ou 8 bits. Ces formats sont représentés par le nom d'extension OpenGL suivant :
    • GL_EXT_texture_compression_s3tc
    Certains appareils ne sont compatibles qu'avec le format DXT1. Cette compatibilité limitée est représentée par le nom de l'extension OpenGL suivante :
    • GL_EXT_texture_compression_dxt1
  • 3DC : la compression de texture 3DC (3DC) est un format moins largement disponible qui prend en charge les textures RVB avec un canal alpha. Ce format est représenté par le nom d'extension OpenGL suivant :
    • GL_AMD_compressed_3DC_texture

Avertissement:Ces formats de compression de texture ne sont pas compatibles avec tous les appareils. La prise en charge de ces formats peut varier selon le fabricant et l'appareil. Pour savoir comment déterminer les formats de compression de texture sur un appareil particulier, consultez la section suivante.

Remarque:Une fois que vous avez choisi les formats de compression de texture compatibles avec votre application, veillez à les déclarer dans votre fichier manifeste à l'aide de <supports-gl-texture> . L'utilisation de cette déclaration permet de filtrer par services externes tels que Google Play, afin que votre application ne soit installée que sur les appareils compatibles avec les formats requis. Pour en savoir plus, consultez la section Déclarations de fichier manifeste OpenGL.

Déterminer les extensions OpenGL

Les implémentations d'OpenGL varient selon l'appareil Android en termes d'extensions compatibles avec l'API OpenGL ES. Ces extensions incluent des compressions de texture, mais elles incluent généralement d'autres extensions à l'ensemble de fonctionnalités OpenGL.

Pour déterminer les formats de compression de texture et les autres extensions OpenGL compatibles avec un appareil particulier:

  1. Exécutez le code suivant sur vos appareils cibles pour déterminer les formats de compression de texture acceptés:

    Kotlin

    var extensions = gl.glGetString(GL10.GL_EXTENSIONS)
    

    Java

    String extensions = gl.glGetString(GL10.GL_EXTENSIONS);
    

    Avertissement:Les résultats de cet appel varient selon le modèle de l'appareil. Vous devez exécuter cet appel sur plusieurs appareils cibles pour déterminer les types de compression couramment acceptés.

  2. Examinez le résultat de cette méthode pour déterminer quelles extensions OpenGL sont compatibles avec l'appareil.

Pack d'extensions Android (AEP)

L'AEP garantit que votre application est compatible avec un ensemble standardisé d'extensions OpenGL, en plus de l'ensemble de base décrit dans la spécification OpenGL 3.1. Le packaging de ces extensions favorise un ensemble cohérent de fonctionnalités sur tous les appareils, tout en permettant aux développeurs de tirer pleinement parti de la dernière génération d'appareils mobiles GPU.

L'AEP améliore également la prise en charge des images, des tampons de stockage des nuanceurs et des compteurs atomiques dans les nuanceurs de fragments.

Pour que votre application puisse utiliser l'AEP, le fichier manifeste de l'application doit déclarer que l'AEP est obligatoire. De plus, la version de la plate-forme doit être compatible.

Déclarez l'exigence AEP dans le fichier manifeste comme suit:

<uses-feature android:name="android.hardware.opengles.aep"
              android:required="true" />

Pour vérifier que la version de la plate-forme est compatible avec l'AEP, utilisez la méthode hasSystemFeature(String), en transmettant FEATURE_OPENGLES_EXTENSION_PACK comme argument. L'extrait de code suivant montre comment procéder:

Kotlin

var deviceSupportsAEP: Boolean =
        packageManager.hasSystemFeature(PackageManager.FEATURE_OPENGLES_EXTENSION_PACK)

Java

boolean deviceSupportsAEP = getPackageManager().hasSystemFeature
     (PackageManager.FEATURE_OPENGLES_EXTENSION_PACK);

Si la méthode renvoie la valeur "true", AEP est pris en charge.

Pour en savoir plus sur l'AEP, consultez sa page dans le registre Khronos OpenGL ES.

Vérifier la version d'OpenGL ES

Plusieurs versions d'OpenGL ES sont disponibles sur les appareils Android. Vous pouvez spécifier la version minimale de l'API requise par votre application dans votre fichier manifeste, mais vous pouvez également profiter des fonctionnalités d'une API plus récente. Par exemple, l'API OpenGL ES 3.0 est rétrocompatible avec la version 2.0 de l'API. Vous pouvez donc écrire votre application de sorte qu'elle utilise les fonctionnalités OpenGL ES 3.0, mais qu'elle utilise l'API 2.0 si l'API 3.0 n'est pas disponible.

Avant d'utiliser les fonctionnalités d'OpenGL ES à partir d'une version supérieure à la version minimale requise dans le fichier manifeste de votre application, celle-ci doit vérifier la version de l'API disponible sur l'appareil. Pour cela, deux possibilités s'offrent à vous :

  1. Essayez de créer le contexte OpenGL ES de niveau supérieur (EGLContext) et vérifiez le résultat.
  2. Créez un contexte OpenGL ES compatible avec la version minimale et vérifiez la valeur de la version.

L'exemple de code suivant montre comment vérifier la version d'OpenGL ES disponible en créant un EGLContext et en vérifiant le résultat. Cet exemple montre comment vérifier la version d'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 la méthode createContext() ci-dessus renvoie la valeur "null", votre code doit créer un contexte OpenGL ES 2.0 et utiliser uniquement cette API.

L'exemple de code suivant montre comment vérifier la version d'OpenGL ES en créant d'abord un contexte minimal compatible, puis en vérifiant la chaîne de version:

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.

Avec cette approche, si vous découvrez que l'appareil est compatible avec une version d'API de niveau supérieur, vous devez détruire le contexte OpenGL ES minimal et créer un contexte avec la version d'API supérieure disponible.

Choisir une version d'API OpenGL

Les versions 2.0 et 3.0 de l'API OpenGL ES 1.0 (ainsi que les extensions 1.1), les versions 2.0 et 3.0 offrent toutes des interfaces graphiques hautes performances pour la création de jeux, de visualisations et d'interfaces utilisateur en 3D. La programmation graphique pour OpenGL ES 2.0 et 3.0 est très similaire, la version 3.0 représentant un sur-ensemble de l'API 2.0 avec des fonctionnalités supplémentaires. La programmation de l'API OpenGL ES 1.0/1.1 et d'OpenGL ES 2.0 et 3.0 diffère considérablement. Les développeurs doivent donc bien prendre en compte les facteurs suivants avant de commencer le développement avec ces API:

  • Performances : en général, OpenGL ES 2.0 et 3.0 offrent des performances graphiques plus rapides que les API ES 1.0/1.1. Toutefois, la différence de performances peut varier selon l'appareil Android sur lequel votre application OpenGL est exécutée, en raison des différences d'implémentation du pipeline graphique OpenGL ES par le fabricant du matériel.
  • Compatibilité des appareils : les développeurs doivent prendre en compte les types d'appareils, les versions d'Android et les versions d'OpenGL ES disponibles pour leurs clients. Pour en savoir plus sur la compatibilité d'OpenGL entre les appareils, consultez la section Versions OpenGL et compatibilité des appareils.
  • Commodité de codage : l'API OpenGL ES 1.0/1.1 fournit un pipeline de fonctions fixes et des fonctions pratiques qui ne sont pas disponibles dans les API OpenGL ES 2.0 ou 3.0. Les développeurs qui débutent avec OpenGL ES peuvent trouver le codage pour la version 1.0/1.1 plus rapide et plus pratique.
  • Contrôle graphique : les API OpenGL ES 2.0 et 3.0 offrent un niveau de contrôle plus élevé en fournissant un pipeline entièrement programmable grâce à l'utilisation de nuanceurs. Grâce à un contrôle plus direct du pipeline de traitement graphique, les développeurs peuvent créer des effets très difficiles à générer avec l'API 1.0/1.1.
  • Prise en charge des textures : l'API OpenGL ES 3.0 offre la meilleure prise en charge de la compression de texture, car elle garantit la disponibilité du format de compression ETC2, qui prend en charge la transparence. Les implémentations d'API 1.x et 2.0 sont généralement compatibles avec ETC1, mais ce format de texture n'est pas compatible avec la transparence. Vous devez donc généralement fournir des ressources dans d'autres formats de compression compatibles avec les appareils que vous ciblez. Pour en savoir plus, consultez Compatibilité avec la compression de texture.

Bien que les performances, la compatibilité, la commodité, le contrôle et d'autres facteurs puissent influencer votre décision, vous devez choisir une version d'API OpenGL en fonction de ce qui, selon vous, offre la meilleure expérience utilisateur.