OpenGL ES

Android supporta la 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 è una versione della specifica OpenGL per i dispositivi incorporati. Android supporta diverse versioni dell'API OpenGL ES:

  • 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.
  • OpenGL ES 3.2: questa specifica API è supportata da Android 7.0 (livello API 24) 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 nel manifest specifichi che è necessario OpenGL ES 3.0, puoi assicurarti che quella versione sarà presente sul dispositivo. Se specifichi che è necessaria 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 Verifica della versione di OpenGL ES.

Nota: Android include il supporto per OpenGL ES 1.0 e 1.1, ma queste versioni dell'API sono deprecate e non devono essere utilizzate dalle applicazioni moderne.

Nota: l'API specifica fornita dal framework Android è simile all'API J2ME JSR239 OpenGL ES, ma non è identica. Se conosci la specifica J2ME JSR239, presta 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 la sezione NDK di Android.

Il framework Android offre due classi di base che ti 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 quello di capire come implementare queste classi in un'attività.

GLSurfaceView
Questa classe è una classe View in cui puoi disegnare e manipolare oggetti mediante chiamate API OpenGL ed è simile nella funzione a SurfaceView. Puoi utilizzare questa classe creando un'istanza di GLSurfaceView e aggiungendo il tuo 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 necessari per disegnare elementi grafici in un GLSurfaceView. Devi fornire un'implementazione di questa interfaccia come classe separata e collegarla alla tua 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 solo una volta, ad esempio l'impostazione di parametri di ambiente OpenGL o l'inizializzazione di oggetti grafici OpenGL.
  • onDrawFrame(): il sistema chiama questo metodo a ogni nuovo disegno di 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:

  • Classe API OpenGL ES 2.0
    • android.opengl.GLES20: questo pacchetto fornisce l'interfaccia a OpenGL ES 2.0 ed è disponibile a partire da Android 2.2 (livello API 8).
  • Pacchetti API OpenGL ES 3.0/3.1/3.2
    • android.opengl: questo pacchetto fornisce l'interfaccia per le classi OpenGL ES 3.0/3.1. La versione 3.0 è disponibile a partire da Android 4.3 (livello API 18). La versione 3.1 è disponibile a partire da Android 5.0 (livello API 21). La versione 3.2 è disponibile a partire da Android 7.0 (livello API 24).

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

Dichiarazione dei requisiti OpenGL

Se l'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 del file manifest OpenGL più comuni:

  • Requisiti della versione di OpenID 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 impedisce l'installazione della tua applicazione su dispositivi che non supportano OpenGL ES 2.0. Se la tua applicazione è destinata esclusivamente a dispositivi che supportano OpenGL ES 3.0, puoi specificarlo 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" />
    

    Per OpenGL ES 3.2:

    <!-- Tell the system this app requires OpenGL ES 3.2. -->
    <uses-feature android:glEsVersion="0x00030002" 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 nell'applicazione con maggiore flessibilità. Se dichiari l'API OpenGL ES 2.0 come requisito nel file manifest, puoi utilizzare questa versione dell'API come predefinita, verificare la disponibilità dell'API 3.x in fase di esecuzione e utilizzare le funzionalità di 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 Verifica della 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 la pagina Supporto della compressione delle texture.

    La dichiarazione dei requisiti di compressione delle texture nel file manifest nasconde la tua 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 relativa a Google Play e al filtro della compressione delle texture nella documentazione relativa a <supports-gl-texture>.

Mappatura delle coordinate per gli oggetti disegnati

Uno dei problemi di base nella visualizzazione di 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, trascina felicemente queste coordinate su uno schermo tipicamente non quadrato come se fosse perfettamente quadrato.

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

L'illustrazione sopra mostra il sistema di coordinate uniformi previsto per un frame OpenGL a sinistra e come queste coordinate vengano effettivamente mappate sullo schermo di un tipico dispositivo con orientamento orizzontale a destra. Per risolvere il problema, puoi applicare modalità di proiezione OpenGL e le visualizzazioni della videocamera 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 di visualizzazione della videocamera e applicarle alla pipeline di rendering OpenGL. La matrice di proiezione ricalcola le coordinate delle immagini per renderle mappate correttamente agli schermi dei dispositivi Android. La matrice delle immagini della videocamera crea una trasformazione che mostra gli oggetti da una posizione specifica dell'occhio.

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

Nelle API ES 2.0 e 3.0, per applicare proiezione e visualizzazione videocamera devi prima aggiungere un membro della matrice ai vertici Shaker degli oggetti grafici. Aggiungendo questo membro della matrice, puoi quindi generare e applicare matrici di proiezione e visualizzazione della videocamera ai tuoi oggetti.

  1. Aggiungi la matrice ai vertici Shaker - Crea una variabile per la matrice di proiezione della vista e includila come moltiplicatore della posizione dello Shader. Nel seguente esempio di codice Vertex Shadr, il membro uMVPMatrix incluso ti consente di applicare le matrici di proiezione e visualizzazione della videocamera alle coordinate degli oggetti che utilizzano questo Shadr.

    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 Shader a cui applichi una combinazione di matrice di proiezione e matrice della vista videocamera. A seconda dei requisiti dell'applicazione, è possibile definire membri distinti della matrice di proiezione e della matrice di visualizzazione della videocamera nei vertex shabby, in modo da poterli modificare in modo indipendente.

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

    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 della 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. Applicazione delle matrici di proiezione e visualizzazione della videocamera: per applicare le trasformazioni di proiezione e visualizzazione della videocamera, moltiplica le matrici e impostale nell'ombreggiatura dei vertici. Il codice di esempio riportato di seguito 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 proiezione e visualizzazione della videocamera con OpenGL ES 2.0, consulta la classe Display grafica con OpenGL ES.

Forma le facce e i torsione

In OpenGL, la faccia di una forma è una superficie definita da tre o più punti nello spazio tridimensionale. Un insieme di tre o più punti tridimensionali (chiamati vertici in OpenGL) hanno una faccia anteriore e una faccia posteriore. Come fai a sapere quale volto è davanti e quale posteriore? Ottima domanda. La risposta riguarda la torsione, ovvero 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 secondo l'ordine in cui sono disegnati in senso antiorario. L'ordine in cui vengono tracciate le coordinate definisce la direzione di torsione 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 faccia posteriore.

Perché è importante sapere quale faccia di una forma corrisponde a quella anteriore? La risposta ha a che fare con una funzionalità di uso comune di OpenGL, chiamata Face culling. Il Face culling è un'opzione per l'ambiente OpenGL che consente alla pipeline di rendering di ignorare (non calcolare né 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 usare la funzione di selezione facciale senza sapere quali lati delle forme sono la parte anteriore e posteriore, la grafica OpenGL apparirà un po' sottile o forse non verrà visualizzata affatto. Quindi, definisci sempre le coordinate delle forme OpenGL in ordine di disegno in senso antiorario.

Nota: è possibile impostare un ambiente OpenGL in modo da trattare il quadrante in senso orario come quello anteriore, ma questa operazione richiede più codice e può confondere gli sviluppatori OpenGL esperti quando chiedi loro assistenza. Non farlo.

Versioni OpenGL e compatibilità del dispositivo

Le specifiche API OpenGL ES 1.0 e 1.1 sono supportate da Android 1.0. La programmazione di grafica con l'API OpenGL ES 1.0/1.1 è molto diversa rispetto all'utilizzo della versione 2.0 e successive. OpenGL ES 2.0 è supportato da tutti i dispositivi Android a partire da Android 2.2 (livello API 8) ed è la prima versione consigliata per nuove applicazioni sviluppate con OpenGL ES. 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 Android che supportano una determinata versione di OpenGL ES, consulta la dashboard della versione di OpenID ES.

Devi valutare attentamente i requisiti di grafica e scegliere la versione API più adatta alla tua applicazione. Per ulteriori informazioni, 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. Questo significa che puoi potenzialmente scrivere il targeting della tua applicazione 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 Verifica della versione OpenGL ES.

Supporto della compressione delle texture

La compressione delle texture può aumentare significativamente le prestazioni dell'applicazione OpenGL riducendo i requisiti di memoria e utilizzando in modo più efficiente la larghezza di banda della memoria. Il framework Android supporta 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 app per Android che utilizza la compressione della texture, consulta l'esempio di codice CompressedTextureActivity nell'SDK Android (<sdk>/samples/<version>/ApiDemos/src/com/example/android/apis/graphics/).

Il formato ETC1 è supportato da tutti i dispositivi Android che supportano OpenGL ES 2.0 o versioni successive.

Nota: il formato di compressione delle texture ETC1 non supporta le texture con una trasparenza (canale alfa). Se la tua applicazione richiede texture trasparenti, devi analizzare altri formati di compressione delle texture disponibili sui dispositivi di destinazione. Un metodo per eseguire il rendering delle texture del canale alfa utilizzando ETC1 consiste nell'associare due oggetti texture ETC1: il primo con i dati sui colori, il secondo con i dati del canale alfa, quindi combinando i valori delle due texture nello strumento di ombreggiatura dei frammenti.

La disponibilità dei formati di compressione delle texture ETC2/EAC è garantita quando si utilizza l'API OpenGL ES 3.0. 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 dalla tua 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 OpenID, che identificano i formati di compressione delle texture (e altre funzionalità OpenGL) supportati dal dispositivo. Ecco alcuni formati di compressione delle texture comunemente supportati:

  • ASTC (Adaptable Scalable Texture Compression): un formato di compressione delle texture progettato per sostituire i formati precedenti. Più flessibile rispetto ai formati precedenti grazie al supporto di varie dimensioni di blocco.
    • GL_KHR_texture_compression_astc_ldr
    • GL_KHR_texture_compression_astc_hdr(High Dynamic Range)
  • S3TC (DXTn/DXTC): la compressione delle texture S3 (S3TC) ha diverse variazioni di formato (da DXT1 a DXT5) ed è meno ampiamente disponibile. Il formato supporta le texture RGB con canali alfa a 4 bit o alfa a 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

I seguenti formati di compressione delle texture sono considerati formati precedenti e non sono consigliati per l'utilizzo in nuove applicazioni:

  • ATITC (ATC): la compressione delle texture ATI (ATITC o ATC) è disponibile su un'ampia gamma di dispositivi e supporta la compressione a frequenza 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
  • 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 che segue:
    • 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 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 sia installata solo su dispositivi che supportano i formati richiesti dalla tua app. Per maggiori dettagli, consulta le dichiarazioni del file manifest OpenID.

Stabilire le estensioni OpenGL

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

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

  1. Esegui questo codice 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);
    

    Avviso: i risultati della chiamata variano a seconda del modello del 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 rispetto al set di base descritto nella specifica OpenGL 3.1. La combinazione di queste estensioni incoraggia un insieme coerente di funzionalità su tutti i dispositivi, consentendo allo stesso tempo agli sviluppatori di sfruttare appieno l'ultima versione di dispositivi GPU mobili.

L'AEP migliora anche il supporto per le immagini, i buffer di archiviazione delloshar e i 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.

Tutte le funzionalità aggiuntive specificate nell'AEP sono incluse nella specifica di base di OpenGL ES 3.2. Se l'app richiede OpenGL ES 3.2, non è necessario utilizzare AEP.

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 sull'AEP, visita la relativa pagina nel registro OpenGL ES Khronos.

Controllo della versione OpenGL ES

Sui dispositivi Android sono disponibili diverse versioni di OpenGL ES. Puoi specificare la versione minima dell'API richiesta dalla tua applicazione nel file manifest, ma puoi anche sfruttare contemporaneamente le funzionalità di un'API più recente. Ad esempio, l'API OpenGL ES 3.0 è retrocompatibile con la versione 2.0 dell'API, ti consigliamo di scrivere l'applicazione in modo che utilizzi le funzionalità OpenGL ES 3.0, ma torni a utilizzare 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 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 minimo supportato 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 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 poi 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 OpenGL ES minimo e crearne uno nuovo con la versione API disponibile più alta.

Scelta della versione dell'API OpenGL

Sia OpenGL ES versione 2.0 che 3.0 offrono interfacce grafiche ad alte prestazioni per la creazione di giochi, visualizzazioni e interfacce utente 3D. La programmazione della grafica per OpenGL ES 2.0 e 3.0 è molto 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 in modo significativo e non è consigliata per nuove applicazioni. Gli sviluppatori devono valutare attentamente i fattori riportati di seguito prima di iniziare lo sviluppo con queste API:

  • Compatibilità dei dispositivi: gli sviluppatori dovrebbero 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.
  • Supporto texture: l'API OpenGL ES 3.0 offre il miglior supporto per la compressione delle texture in quanto garantisce la disponibilità del formato di compressione ETC2, che supporta la trasparenza. Le implementazioni dell'API 2.0 includono il supporto per ETC1, ma questo formato di texture non supporta la trasparenza. Per implementare la trasparenza con le texture compresse, devi utilizzare due texture ETC1 (divise tra colore e alfa) o 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 la compatibilità e il supporto delle texture possono influenzare la tua decisione, ti consigliamo di scegliere una versione dell'API OpenGL in base a ciò che ritieni offra la migliore esperienza agli utenti.