OpenGL ES

Android include il supporto per grafica 2D e 3D ad alte prestazioni con Open Graphics Library (OpenGL®), in particolare l'API OpenGL ES. OpenGL è un'API grafica multipiattaforma che specifica un'interfaccia software standard per l'hardware di elaborazione della grafica 3D. OpenGL ES è un modello della specifica OpenGL dedicato ai dispositivi incorporati. Android supporta diverse versioni dell'API OpenGL ES:

  • OpenGL ES 1.0 e 1.1: questa specifica API è supportata da Android 1.0 e versioni successive.
  • OpenGL ES 2.0: questa specifica API è supportata da Android 2.2 (livello API 8) e versioni successive.
  • OpenGL ES 3.0: questa specifica API è supportata da Android 4.3 (livello API 18) e versioni successive.
  • OpenGL ES 3.1: questa specifica API è supportata da Android 5.0 (livello API 21) e versioni successive.

Attenzione: indipendentemente dalla versione della piattaforma Android, un dispositivo non può supportare l'API OpenGL ES 3.0 a meno che il produttore del dispositivo non fornisca un'implementazione di questa pipeline grafica. Se specifichi nel manifest che è necessario OpenGL ES 3.0, puoi assicurarti che quella versione sia presente sul dispositivo. Se specifichi che è richiesta una versione di livello inferiore, ma vuoi utilizzare le funzionalità 3.0, se disponibili, ti consigliamo di controllare in fase di esecuzione per verificare quale versione di OpenGL è supportata dal dispositivo. Per informazioni su come eseguire questa operazione, consulta la sezione Verificare la versione di OpenGL ES.

Nota: l'API specifica fornita dal framework Android è simile all'API J2ME JSR239 OpenGL ES, ma non è identica. Se conosci la specifica J2ME JSR239, fai attenzione alle variazioni.

Vedi anche

Nozioni di base

Android supporta OpenGL sia tramite l'API framework sia tramite il kit di sviluppo nativo (NDK). Questo argomento è incentrato sulle interfacce del framework Android. Per ulteriori informazioni sull'NDK, consulta l'articolo NDK di Android.

Il framework Android prevede due classi di base che consentono di creare e manipolare le immagini con l'API OpenGL ES: GLSurfaceView e GLSurfaceView.Renderer. Se il tuo obiettivo è utilizzare OpenGL nella tua applicazione Android, il tuo primo obiettivo dovrebbe essere capire come implementare queste classi in un'attività.

GLSurfaceView
Questa classe è una classe View in cui puoi disegnare e manipolare oggetti utilizzando le chiamate API OpenGL ed è simile nella funzione a SurfaceView. Puoi utilizzare questa classe creando un'istanza di GLSurfaceView e aggiungendovi Renderer. Tuttavia, se vuoi acquisire eventi touchscreen, devi estendere la classe GLSurfaceView per implementare i listener touch, come mostrato nella lezione di formazione OpenGL, Risposta agli eventi tocco.
GLSurfaceView.Renderer
Questa interfaccia definisce i metodi richiesti per disegnare grafici in un GLSurfaceView. Devi fornire un'implementazione di questa interfaccia come classe separata e collegarla all'istanza GLSurfaceView utilizzando GLSurfaceView.setRenderer().

L'interfaccia GLSurfaceView.Renderer richiede l'implementazione dei seguenti metodi:

  • onSurfaceCreated(): il sistema chiama questo metodo una volta, durante la creazione di GLSurfaceView. Utilizza questo metodo per eseguire azioni che devono essere eseguite una sola volta, come l'impostazione di parametri di ambiente OpenGL o l'inizializzazione di oggetti grafici OpenGL.
  • onDrawFrame(): il sistema chiama questo metodo a ogni rielaborazione del GLSurfaceView. Utilizza questo metodo come punto di esecuzione principale per disegnare (e ridisegnare) oggetti grafici.
  • onSurfaceChanged(): il sistema chiama questo metodo quando cambia la geometria di GLSurfaceView, incluse le modifiche alle dimensioni dello GLSurfaceView o all'orientamento dello schermo del dispositivo. Ad esempio, il sistema chiama questo metodo quando il dispositivo passa dall'orientamento verticale a quello orizzontale. Utilizza questo metodo per rispondere alle modifiche nel container GLSurfaceView.

Pacchetti OpenGL ES

Dopo aver stabilito una visualizzazione container per OpenGL ES utilizzando GLSurfaceView e GLSurfaceView.Renderer, puoi iniziare a chiamare le API OpenGL utilizzando le seguenti classi:

Se vuoi iniziare subito a creare un'app con OpenGL ES, segui la lezione Visualizzazione di grafica con OpenGL ES.

Dichiarazione dei requisiti OpenGL

Se la tua applicazione utilizza funzionalità OpenGL che non sono disponibili su tutti i dispositivi, devi includere questi requisiti nel file AndroidManifest.xml. Di seguito sono riportate le dichiarazioni più comuni relative al file manifest OpenGL:

  • Requisiti per la versione di OpenGL ES: se la tua applicazione richiede una versione specifica di OpenGL ES, devi dichiarare questo requisito aggiungendo le seguenti impostazioni al file manifest, come mostrato di seguito.

    Per OpenGL ES 2.0:

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

    Se aggiungi questa dichiarazione, Google Play limiterà l'installazione della tua applicazione sui dispositivi che non supportano OpenGL ES 2.0. Se l'applicazione è destinata esclusivamente ai dispositivi che supportano OpenGL ES 3.0, puoi specificare quanto segue nel file manifest:

    Per OpenGL ES 3.0:

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

    Per OpenGL ES 3.1:

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

    Nota: l'API OpenGL ES 3.x è compatibile con le versioni precedenti dell'API 2.0, il che significa che puoi implementare OpenGL ES nella tua applicazione in modo più flessibile. Dichiarando l'API OpenGL ES 2.0 come requisito nel file manifest, puoi utilizzare quella versione API come predefinita, verificare la disponibilità dell'API 3.x in fase di esecuzione e poi utilizzare le funzionalità OpenGL ES 3.x, se il dispositivo la supporta. Per ulteriori informazioni su come verificare la versione OpenGL ES supportata da un dispositivo, consulta la pagina Verificare la versione OpenGL ES.

  • Requisiti di compressione delle texture - Se l'applicazione utilizza formati di compressione delle texture, devi dichiarare i formati supportati dall'applicazione nel file manifest utilizzando <supports-gl-texture>. Per ulteriori informazioni sui formati di compressione delle texture disponibili, consulta Supporto della compressione delle texture.

    La dichiarazione dei requisiti di compressione delle texture nel file manifest nasconde l'applicazione agli utenti con dispositivi che non supportano almeno uno dei tipi di compressione dichiarati. Per ulteriori informazioni sul funzionamento dei filtri di Google Play per le compresse delle texture, consulta la sezione Google Play e filtri di compressione delle texture nella documentazione relativa al <supports-gl-texture>.

Mappatura delle coordinate per gli oggetti disegnati

Uno dei problemi fondamentali nella visualizzazione della grafica sui dispositivi Android è che gli schermi possono variare per dimensioni e forma. OpenGL presuppone un sistema di coordinate quadrato e uniforme e, per impostazione predefinita, disegna le coordinate sullo schermo tipicamente non quadrato come se fossero perfettamente quadrate.

Figura 1. Sistema di coordinate OpenGL predefinito (a sinistra) mappato sullo schermo di un tipico dispositivo Android (a destra).

L'illustrazione sopra mostra il sistema di coordinate uniforme utilizzato per un frame OpenGL a sinistra e come queste coordinate vengono effettivamente mappate allo schermo di un tipico dispositivo con orientamento orizzontale a destra. Per risolvere il problema, puoi applicare le modalità di proiezione OpenGL e le visualizzazioni della fotocamera per trasformare le coordinate in modo che gli oggetti grafici abbiano le proporzioni corrette su qualsiasi display.

Per applicare le visualizzazioni di proiezione e videocamera, devi creare una matrice di proiezione e una matrice di visualizzazione della videocamera e applicarle alla pipeline di rendering OpenGL. La matrice di proiezione ricalcola le coordinate della grafica in modo che vengano mappate correttamente sugli schermi dei dispositivi Android. La matrice crea una trasformazione che mostra gli oggetti da una posizione specifica dell'occhio.

Proiezione e visualizzazione della fotocamera in OpenGL ES 1.0

Nell'API ES 1.0, puoi applicare proiezione e visualizzazione della videocamera creando ogni matrice e poi aggiungendola all'ambiente OpenGL.

  1. Matrice di proiezione - Crea una matrice di proiezione utilizzando la geometria dello schermo del dispositivo per ricalcolare le coordinate degli oggetti in modo che vengano disegnate con le proporzioni corrette. Il codice di esempio seguente mostra come modificare il metodo onSurfaceChanged() di un'implementazione GLSurfaceView.Renderer per creare una matrice di proiezione basata sulle proporzioni dello schermo e applicarla all'ambiente di rendering 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 di trasformazione della videocamera: una volta regolato il sistema di coordinate utilizzando una matrice di proiezione, devi anche applicare una vista telecamera. Il codice di esempio seguente mostra come modificare il metodo onDrawFrame() di un'implementazione GLSurfaceView.Renderer per applicare una vista del modello e utilizzare l'utilità GLU.gluLookAt() per creare una trasformazione di visualizzazione che simula la posizione di una telecamera.

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

Proiezione e visualizzazione della fotocamera in OpenGL ES 2.0 e versioni successive

Nelle API ES 2.0 e 3.0, puoi applicare la proiezione e la visualizzazione fotocamera aggiungendo prima un membro della matrice ai Vertex Shaper degli oggetti grafici. Dopo aver aggiunto questo membro della matrice, puoi generare e applicare matrici di proiezione e visualizzazione della telecamera ai tuoi oggetti.

  1. Aggiungi la matrice ai Vertex Shaper - Crea una variabile per la matrice di proiezione della vista e includila come moltiplicatore della posizione delloshadowr. Nell'esempio seguente, il membro uMVPMatrix incluso consente di applicare le matrici di proiezione e visualizzazione da fotocamera alle coordinate degli oggetti che utilizzano questo ombreggiatore.

    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: l'esempio precedente definisce un singolo membro della matrice di trasformazione nel Vertex Shaper a cui applichi una matrice di proiezione combinata e matrice della visualizzazione della videocamera. A seconda dei requisiti della tua applicazione, puoi definire membri separati per la matrice di proiezione e la matrice di visualizzazione della videocamera nei tuoi Vertex Shader, in modo da poterli modificare in modo indipendente.

  2. Accedi alla matrice mesh: dopo aver creato un hook nei Vertex Shaper per applicare proiezione e visualizzazione della videocamera, puoi accedere a quella variabile per applicare le matrici di proiezione e visualizzazione della videocamera. Il codice seguente mostra come modificare il metodo onSurfaceCreated() di un'implementazione GLSurfaceView.Renderer per accedere alla variabile della matrice definita nel vertex Shader sopra.

    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. Crea matrici di proiezione e visualizzazione della videocamera - Genera le matrici di proiezione e visualizzazione da applicare agli oggetti grafici. Il codice di esempio seguente mostra come modificare i metodi onSurfaceCreated() e onSurfaceChanged() di un'implementazione GLSurfaceView.Renderer per creare una matrice di visualizzazione della videocamera e una matrice di proiezione basata sulle proporzioni dello schermo 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);
    }
    
  4. Applica le matrici di proiezione e visualizzazione della videocamera - Per applicare le trasformazioni di proiezione e visualizzazione della videocamera, moltiplica tra loro le matrici e impostale nell'ombreggiatura dei vertici. Il codice di esempio seguente mostra come modificare il metodo onDrawFrame() di un'implementazione GLSurfaceView.Renderer per combinare la matrice di proiezione e la visualizzazione della videocamera create nel codice precedente e quindi applicarla agli oggetti grafici di cui eseguire il rendering da 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
        ...
    }
    

Per un esempio completo su come applicare la proiezione e la visualizzazione dalla fotocamera con OpenGL ES 2.0, consulta la classe Visualizzazione di grafica con OpenGL ES.

Dai forma alle facce e avvolgimento

In OpenGL, la faccia di una forma è una superficie definita da tre o più punti in uno spazio tridimensionale. Un insieme di tre o più punti tridimensionali (chiamati vertici in OpenGL) hanno una faccia anteriore e una posteriore. Come fai a sapere quale volto è davanti e quale posteriore? Ottima domanda. La risposta riguarda l'avvolgimento o la direzione in cui definisci i punti di una forma.

Coordinate ai vertici di un triangolo

Figura 1. Illustrazione di un elenco di coordinate che si traduce in un ordine di disegno in senso antiorario.

In questo esempio, i punti del triangolo sono definiti in un ordine in modo da essere disegnati in senso antiorario. L'ordine in cui vengono tracciate le coordinate definisce la direzione di avvolgimento della forma. Per impostazione predefinita, in OpenGL, il volto disegnato in senso antiorario è quello anteriore. Il triangolo mostrato nella Figura 1 è definito in modo da visualizzare la faccia anteriore della forma (come interpretata da OpenGL) e l'altro lato è la parte posteriore.

Perché è importante sapere quale faccia di una forma corrisponde a quella anteriore? La risposta riguarda una funzione comunemente usata di OpenGL, chiamata Face culling. Il Face culling è un'opzione per l'ambiente OpenGL che consente alla pipeline di rendering di ignorare (non calcolare o disegnare) il retro di una forma, risparmiando tempo, memoria e cicli di elaborazione:

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

Se provi a utilizzare la funzionalità di selezione facciale senza sapere quali lati delle forme sono fronte e retro, la grafica OpenGL sembrerà un po' sottile o potrebbe non essere visualizzata affatto. Pertanto, definisci sempre le coordinate delle forme OpenGL in ordine di disegno in senso antiorario.

Nota: è possibile impostare un ambiente OpenGL in modo da considerare il volto in senso orario come quello anteriore, ma questa operazione richiede più codice ed è probabile che confonda gli sviluppatori OpenGL esperti quando chiedi loro assistenza. Non farlo.

Versioni OpenGL e compatibilità del dispositivo

Le specifiche dell'API OpenGL ES 1.0 e 1.1 sono supportate a partire da Android 1.0. A partire da Android 2.2 (livello API 8), il framework supporta la specifica dell'API OpenGL ES 2.0. OpenGL ES 2.0 è supportato dalla maggior parte dei dispositivi Android ed è consigliato per nuove applicazioni sviluppate con OpenGL. OpenGL ES 3.0 è supportato con Android 4.3 (livello API 18) e versioni successive sui dispositivi che forniscono un'implementazione dell'API OpenGL ES 3.0. Per informazioni sul numero relativo di dispositivi basati su Android che supportano una determinata versione di OpenGL ES, consulta la dashboard della versione di OpenGL ES.

La programmazione di grafica con l'API OpenGL ES 1.0/1.1 è notevolmente diversa rispetto all'uso della 2.0 e delle versioni successive. La versione 1.x dell'API offre metodi più pratici e una pipeline grafica fissa, mentre le API OpenGL ES 2.0 e 3.0 offrono un controllo più diretto della pipeline tramite l'uso di Shader OpenGL. Valuta attentamente i requisiti di grafica e scegli la versione dell'API più adatta alla tua applicazione. Per saperne di più, consulta la sezione Scegliere una versione dell'API OpenGL.

L'API OpenGL ES 3.0 offre funzionalità aggiuntive e prestazioni migliori rispetto all'API 2.0 ed è anche compatibile con le versioni precedenti. Ciò significa che potenzialmente puoi scrivere la tua applicazione che ha come target OpenGL ES 2.0 e includere in modo condizionale le funzionalità grafiche OpenGL ES 3.0, se disponibili. Per ulteriori informazioni sul controllo della disponibilità dell'API 3.0, consulta la pagina Controllo della versione OpenGL ES

Supporto per la compressione delle texture

La compressione delle texture può aumentare notevolmente le prestazioni della tua applicazione OpenGL riducendo i requisiti di memoria e utilizzando in modo più efficiente la larghezza di banda della memoria. Il framework Android fornisce supporto per il formato di compressione ETC1 come funzionalità standard, inclusi una classe di utilità ETC1Util e lo strumento di compressione etc1tool (disponibile nell'SDK Android all'indirizzo <sdk>/tools/). Per un esempio di applicazione Android che utilizza la compressione delle texture, vedi l'esempio di codice CompressedTextureActivity nell'SDK Android (<sdk>/samples/<version>/ApiDemos/src/com/example/android/apis/graphics/).

Attenzione: il formato ETC1 è supportato dalla maggior parte dei dispositivi Android, ma non è garantito che sia disponibile. Per verificare se il formato ETC1 è supportato su un dispositivo, chiama il metodo ETC1Util.isETC1Supported().

Nota: il formato di compressione delle texture ETC1 non supporta le texture con trasparenza (canale alfa). Se la tua applicazione richiede texture con trasparenza, devi esaminare altri formati di compressione delle texture disponibili sui dispositivi di destinazione.

Quando si utilizza l'API OpenGL ES 3.0, i formati di compressione delle texture ETC2/EAC sono garantiti. Questo formato di texture offre eccellenti rapporti di compressione con un'alta qualità visiva e supporta anche la trasparenza (canale alfa).

Oltre ai formati ETC, i dispositivi Android hanno diversificato il supporto per la compressione delle texture in base ai chipset GPU e alle implementazioni OpenGL. Dovresti esaminare il supporto della compressione delle texture sui dispositivi scelti come target per determinare i tipi di compressione supportati dall'applicazione. Per determinare quali formati di texture sono supportati su un determinato dispositivo, devi eseguire una query sul dispositivo ed esaminare i nomi delle estensioni OpenGL, che identificano i formati di compressione delle texture (e altre funzionalità OpenGL) supportati dal dispositivo. Di seguito sono riportati alcuni formati di compressione delle texture comunemente supportati:

  • ATITC (ATC): la compressione delle texture ATI (ATITC o ATC) è disponibile su un'ampia gamma di dispositivi e supporta la compressione a velocità fissa per le texture RGB con e senza un canale alfa. Questo formato può essere rappresentato da diversi nomi di estensioni OpenGL, ad esempio:
    • GL_AMD_compressed_ATC_texture
    • GL_ATI_texture_compression_atitc
  • PVRTC: la compressione delle texture PowerVR (PVRTC) è disponibile su un'ampia gamma di dispositivi e supporta texture a 2 e 4 bit per pixel con o senza un canale alfa. Questo formato è rappresentato dal seguente nome dell'estensione OpenGL:
    • GL_IMG_texture_compression_pvrtc
  • S3TC (DXTn/DXTC): la compressione delle texture S3 (S3TC) presenta diverse variazioni di formato (da DXT1 a DXT5) ed è meno ampiamente disponibile. Il formato supporta texture RGB con canali alfa a 4 bit o 8 bit. Questi formati sono rappresentati dal seguente nome dell'estensione OpenGL:
    • GL_EXT_texture_compression_s3tc
    Alcuni dispositivi supportano solo la variazione del formato DXT1; questo supporto limitato è rappresentato dal seguente nome dell'estensione OpenGL:
    • GL_EXT_texture_compression_dxt1
  • 3DC: la compressione delle texture 3DC (3DC) è un formato meno ampiamente disponibile che supporta le texture RGB con un canale alfa. Questo formato è rappresentato dal nome dell'estensione OpenGL seguente:
    • GL_AMD_compressed_3DC_texture

Avviso: questi formati di compressione delle texture non sono supportati su tutti i dispositivi. Il supporto di questi formati può variare in base al produttore e al dispositivo. Per informazioni su come determinare quali formati di compressione delle texture sono disponibili su un determinato dispositivo, consulta la sezione successiva.

Nota: dopo aver deciso quali formati di compressione delle texture saranno supportati dalla tua applicazione, assicurati di dichiararli nel file manifest utilizzando <supports-gl-texture> . L'utilizzo di questa dichiarazione consente di filtrare in base a servizi esterni come Google Play, in modo che la tua app venga installata soltanto sui dispositivi che supportano i formati richiesti dall'app. Per maggiori dettagli, consulta Dichiarazioni del file manifest OpenID.

Determinazione delle estensioni OpenGL

Le implementazioni di OpenGL variano a seconda del dispositivo Android in termini di estensioni supportate per l'API OpenGL ES. Queste estensioni includono compresse delle texture, ma in genere includono anche altre estensioni per il set di funzionalità OpenGL.

Per determinare quali formati di compressione delle texture e altre estensioni OpenGL sono supportati su un determinato dispositivo:

  1. Esegui il codice seguente sui dispositivi di destinazione per determinare quali formati di compressione delle texture sono supportati:

    Kotlin

    var extensions = gl.glGetString(GL10.GL_EXTENSIONS)
    

    Java

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

    Attenzione: i risultati della chiamata variano a seconda del modello di dispositivo. Devi eseguire questa chiamata su diversi dispositivi di destinazione per determinare quali tipi di compressione sono comunemente supportati.

  2. Esamina l'output di questo metodo per determinare quali estensioni OpenGL sono supportate sul dispositivo.

Pacchetto di estensioni Android (AEP)

L'AEP garantisce che la tua applicazione supporti un set standardizzato di estensioni OpenGL oltre il set di base descritto nella specifica OpenGL 3.1. La combinazione di queste estensioni favorisce un insieme coerente di funzionalità su tutti i dispositivi, consentendo allo stesso tempo agli sviluppatori di sfruttare appieno l'ultima versione di dispositivi GPU per dispositivi mobili.

L'AEP migliora anche il supporto di immagini, buffer di archiviazione dello ombreggiatore e contatori atomici negli ombreggiatori dei frammenti.

Affinché l'app possa utilizzare l'AEP, il relativo file manifest deve dichiarare che l'AEP è obbligatorio. Inoltre, la versione della piattaforma deve supportarlo.

Dichiara il requisito AEP nel file manifest come segue:

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

Per verificare che la versione della piattaforma supporti l'AEP, utilizza il metodo hasSystemFeature(String), passando FEATURE_OPENGLES_EXTENSION_PACK come argomento. Il seguente snippet di codice mostra un esempio di come eseguire questa operazione:

Kotlin

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

Java

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

Se il metodo restituisce true, AEP è supportato.

Per ulteriori informazioni su AEP, visita la relativa pagina nel registro Khronos OpenGL ES.

Controllo della versione OpenGL ES

Sui dispositivi Android sono disponibili diverse versioni di OpenGL ES. Puoi specificare nel manifest la versione minima dell'API richiesta dall'applicazione, ma puoi anche usufruire contemporaneamente delle funzionalità di un'API più recente. Ad esempio, l'API OpenGL ES 3.0 è compatibile con la versione 2.0 dell'API, pertanto potresti voler scrivere la tua applicazione in modo che utilizzi le funzionalità OpenGL ES 3.0, ma restituisce l'API 2.0 se l'API 3.0 non è disponibile.

Prima di utilizzare le funzionalità OpenGL ES da una versione superiore a quella minima richiesta nel file manifest dell'applicazione, l'applicazione deve controllare la versione dell'API disponibile sul dispositivo. Puoi farlo in due modi:

  1. Prova a creare il contesto OpenGL ES di livello superiore (EGLContext) e controlla il risultato.
  2. Crea un contesto OpenGL ES supportato come minimo e controlla il valore della versione.

Il codice di esempio riportato di seguito mostra come verificare la versione OpenGL ES disponibile creando un EGLContext e controllando il risultato. Questo esempio mostra come verificare la versione di 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;
  }
}

Se il metodo createContext() mostrato sopra restituisce null, il codice dovrebbe creare un contesto OpenGL ES 2.0 e tornare a utilizzare solo quell'API.

Il seguente esempio di codice mostra come verificare la versione OpenGL ES creando prima un contesto minimo supportato, quindi controllando la stringa di versione:

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 questo approccio, se scopri che il dispositivo supporta una versione API di livello superiore, devi eliminare il contesto minimo OpenGL ES e crearne uno nuovo con la versione API più alta disponibile.

Scelta di una versione dell'API OpenGL

Le versioni dell'API OpenGL ES 1.0 (e le estensioni 1.1), la versione 2.0 e la versione 3.0 offrono tutte interfacce grafiche ad alte prestazioni per la creazione di giochi 3D, visualizzazioni e interfacce utente. La programmazione grafica per OpenGL ES 2.0 e 3.0 è sostanzialmente simile, con la versione 3.0 che rappresenta un soprainsieme dell'API 2.0 con funzionalità aggiuntive. La programmazione dell'API OpenGL ES 1.0/1.1 rispetto a OpenGL ES 2.0 e 3.0 varia notevolmente, pertanto gli sviluppatori devono valutare attentamente i fattori riportati di seguito prima di iniziare a sviluppare le API:

  • Prestazioni: in generale, OpenGL ES 2.0 e 3.0 offrono prestazioni grafiche più veloci rispetto alle API ES 1.0/1.1. Tuttavia, la differenza di prestazioni può variare a seconda del dispositivo Android su cui è in esecuzione l'applicazione OpenGL, a causa delle differenze nell'implementazione della pipeline grafica OpenGL ES da parte del produttore dell'hardware.
  • Compatibilità dei dispositivi: gli sviluppatori devono prendere in considerazione i tipi di dispositivi, le versioni Android e le versioni OpenGL ES disponibili per i propri clienti. Per ulteriori informazioni sulla compatibilità OpenGL tra i dispositivi, consulta la sezione Versioni OpenGL e compatibilità dei dispositivi.
  • Praticità della programmazione: l'API OpenGL ES 1.0/1.1 offre una pipeline di funzioni fisse e funzioni di convenienza che non sono disponibili nelle API OpenGL ES 2.0 o 3.0. Gli sviluppatori che non hanno mai utilizzato OpenGL ES potrebbero trovare la codifica per la versione 1.0/1.1 più veloce e comoda.
  • Controllo grafico: le API OpenGL ES 2.0 e 3.0 offrono un livello di controllo superiore fornendo una pipeline completamente programmabile tramite l'uso di Shader. Con un controllo più diretto della pipeline di elaborazione grafica, gli sviluppatori possono creare effetti che sarebbero molto difficili da generare utilizzando l'API 1.0/1.1.
  • Supporto texture: l'API OpenGL ES 3.0 supporta al meglio la compressione delle texture perché garantisce la disponibilità del formato di compressione ETC2, che supporta la trasparenza. Le implementazioni delle API 1.x e 2.0 di solito includono il supporto per ETC1, tuttavia questo formato di texture non supporta la trasparenza, pertanto in genere devi fornire risorse in altri formati di compressione supportati dai dispositivi scelti come target. Per ulteriori informazioni, consulta la sezione Supporto della compressione delle texture.

Anche se prestazioni, compatibilità, praticità, controllo e altri fattori possono influire sulla tua decisione, ti consigliamo di scegliere una versione dell'API OpenGL in base a ciò che ritieni offra la migliore esperienza agli utenti.