OpenGL ES

Android unterstützt über die Open Graphics Library (OpenGL®), insbesondere die OpenGL ES API, 2D- und 3D-Hochleistungsgrafiken. OpenGL ist eine plattformübergreifende Grafik-API, die eine Standard-Softwareschnittstelle für 3D-Grafikverarbeitungshardware angibt. OpenGL ES ist eine Variante der OpenGL-Spezifikation für eingebettete Geräte. Android unterstützt mehrere Versionen der OpenGL ES API:

  • OpenGL ES 2.0: Diese API-Spezifikation wird von Android 2.2 (API-Level 8) und höher unterstützt.
  • OpenGL ES 3.0: Diese API-Spezifikation wird von Android 4.3 (API-Level 18) und höher unterstützt.
  • OpenGL ES 3.1: Diese API-Spezifikation wird von Android 5.0 (API-Level 21) und höher unterstützt.
  • OpenGL ES 3.2: Diese API-Spezifikation wird von Android 7.0 (API-Level 24) und höher unterstützt.

Achtung:Unabhängig von der Android-Plattformversion kann ein Gerät die OpenGL ES 3.0 API nicht unterstützen, es sei denn, der Gerätehersteller bietet eine Implementierung dieser Grafikpipeline. Wenn Sie im Manifest angeben, dass OpenGL ES 3.0 erforderlich ist, wird diese Version auf dem Gerät vorhanden sein. Wenn du angibst, dass eine niedrigere Version erforderlich ist, du aber 3.0-Funktionen nutzen möchtest, sofern diese verfügbar sind, solltest du bei der Laufzeit prüfen, welche OpenGL-Version das Gerät unterstützt. Informationen dazu findest du unter OpenGL ES-Version prüfen.

Hinweis:Android unterstützt OpenGL ES 1.0 und 1.1. Diese Versionen der API wurden jedoch eingestellt und sollten nicht von modernen Anwendungen verwendet werden.

Hinweis:Die vom Android-Framework bereitgestellte API ähnelt der J2ME JSR239 OpenGL ES API, ist aber nicht identisch. Wenn Sie mit der J2ME JSR239-Spezifikation vertraut sind, achten Sie auf Abweichungen.

Siehe auch

Grundlagen

Android unterstützt OpenGL sowohl über seine Framework API als auch über das Native Development Kit (NDK). In diesem Thema geht es um die Android-Framework-Oberflächen. Weitere Informationen zum NDK finden Sie im Android-NDK.

Im Android-Framework gibt es zwei grundlegende Klassen, mit denen Sie Grafiken mit der OpenGL ES API erstellen und bearbeiten können: GLSurfaceView und GLSurfaceView.Renderer. Wenn Sie OpenGL in Ihrer Android-App verwenden möchten, sollte Ihr erstes Ziel darin bestehen, zu verstehen, wie diese Klassen in einer Aktivität implementiert werden.

GLSurfaceView
Diese Klasse ist eine View, mit der Sie Objekte mithilfe von OpenGL API-Aufrufen zeichnen und bearbeiten können. Ihre Funktion ähnelt einer SurfaceView. Sie können diese Klasse verwenden, indem Sie eine Instanz von GLSurfaceView erstellen und ihr Renderer hinzufügen. Wenn du Touchscreen-Ereignisse erfassen möchtest, solltest du die GLSurfaceView-Klasse erweitern, um die Touch-Listener zu implementieren, wie in der OpenGL-Schulungslektion Auf Touch-Ereignisse reagieren gezeigt.
GLSurfaceView.Renderer
Diese Schnittstelle definiert die Methoden, die zum Zeichnen von Grafiken in einem GLSurfaceView erforderlich sind. Sie müssen eine Implementierung dieser Schnittstelle als separate Klasse bereitstellen und sie mit GLSurfaceView.setRenderer() an Ihre GLSurfaceView-Instanz anhängen.

Für die GLSurfaceView.Renderer-Schnittstelle müssen die folgenden Methoden implementiert werden:

  • onSurfaceCreated(): Das System ruft diese Methode beim Erstellen von GLSurfaceView einmal auf. Verwenden Sie diese Methode, um Aktionen auszuführen, die nur einmal ausgeführt werden müssen, z. B. OpenGL-Umgebungsparameter festlegen oder OpenGL-Grafikobjekte initialisieren.
  • onDrawFrame(): Das System ruft diese Methode bei jeder Neuzeichnung von GLSurfaceView auf. Verwenden Sie diese Methode als primären Ausführungspunkt zum Zeichnen (und erneuten Zeichnen) von Grafikobjekten.
  • onSurfaceChanged(): Das System ruft diese Methode auf, wenn sich die GLSurfaceView-Geometrie ändert, einschließlich Änderungen der GLSurfaceView-Größe oder der Ausrichtung des Gerätebildschirms. Diese Methode wird beispielsweise im System aufgerufen, wenn das Gerät vom Hochformat ins Querformat wechselt. Verwenden Sie diese Methode, um auf Änderungen im Container GLSurfaceView zu reagieren.

OpenGL ES-Pakete

Nachdem Sie mit GLSurfaceView und GLSurfaceView.Renderer eine Containeransicht für OpenGL ES eingerichtet haben, können Sie OpenGL APIs mit den folgenden Klassen aufrufen:

  • OpenGL ES 2.0 API-Klasse
    • android.opengl.GLES20: Dieses Paket bietet die Schnittstelle zu OpenGL ES 2.0 und ist ab Android 2.2 (API-Level 8) verfügbar.
  • OpenGL ES 3.0/3.1/3.2 API-Pakete

Wenn Sie sofort damit beginnen möchten, eine App mit OpenGL ES zu erstellen, folgen Sie der Anleitung in der Klasse Grafiken mit OpenGL ES anzeigen.

OpenGL-Anforderungen deklarieren

Wenn Ihre App OpenGL-Funktionen nutzt, die nicht auf allen Geräten verfügbar sind, müssen Sie diese Anforderungen in die Datei AndroidManifest.xml aufnehmen. Hier sind die häufigsten OpenGL-Manifestdeklarationen:

  • OpenGL ES-Versionsanforderungen: Wenn für Ihre App eine bestimmte Version von OpenGL ES erforderlich ist, müssen Sie diese Anforderung ausweisen, indem Sie Ihrem Manifest die folgenden Einstellungen hinzufügen, wie unten gezeigt.

    OpenGL ES 2.0:

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

    Wenn du diese Deklaration hinzufügst, kann Google Play die Installation deiner App auf Geräten einschränken, die OpenGL ES 2.0 nicht unterstützen. Wenn deine App ausschließlich für Geräte vorgesehen ist, die OpenGL ES 3.0 unterstützen, kannst du dies auch in deinem Manifest angeben:

    OpenGL ES 3.0:

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

    OpenGL ES 3.1:

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

    OpenGL ES 3.2:

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

    Hinweis:Die OpenGL ES 3.x API ist abwärtskompatibel mit der API 2.0. Das bedeutet, dass Sie bei der Implementierung von OpenGL ES in Ihrer App flexibler sein können. Wenn du die OpenGL ES 2.0 API in deinem Manifest als Anforderung festlegst, kannst du diese API-Version als Standard verwenden, die Verfügbarkeit der 3.x API zur Laufzeit prüfen und dann die OpenGL ES 3.x-Funktionen verwenden, wenn das Gerät dies unterstützt. Weitere Informationen zum Prüfen der von einem Gerät unterstützten OpenGL ES-Version findest du unter OpenGL ES-Version prüfen.

  • Anforderungen an die Texturkomprimierung – Wenn in deiner App Texturkomprimierungsformate verwendet werden, musst du die Formate, die deine App unterstützt, in deiner Manifestdatei mit <supports-gl-texture> deklarieren. Weitere Informationen zu verfügbaren Texturkomprimierungsformaten finden Sie unter Unterstützung der Texturkomprimierung.

    Wenn Sie in Ihrem Manifest Anforderungen an die Texturkomprimierung angeben, wird Ihre App für Nutzer mit Geräten ausgeblendet, die mindestens einen Ihrer deklarierten Komprimierungstypen nicht unterstützen. Weitere Informationen dazu, wie die Google Play-Filterung bei Texturkomprimierungen funktioniert, finden Sie in der Dokumentation zu <supports-gl-texture> im Abschnitt Google Play- und Texturkomprimierungsfilterung.

Koordinaten für gezeichnete Objekte zuordnen

Eines der grundlegenden Probleme beim Anzeigen von Grafiken auf Android-Geräten besteht darin, dass ihre Bildschirme in Größe und Form variieren können. OpenGL setzt ein quadratisches, einheitliches Koordinatensystem voraus und zeichnet diese Koordinaten standardmäßig so auf Ihren normalerweise nicht quadratischen Bildschirm, als ob dieser perfekt quadratisch wäre.

Abbildung 1: Das OpenGL-Koordinatensystem (links), das einem typischen Android-Gerätebildschirm zugeordnet ist (rechts)

Die obige Abbildung zeigt das einheitliche Koordinatensystem, das links für einen OpenGL-Frame angenommen wurde. Außerdem wird gezeigt, wie diese Koordinaten einem typischen Gerätebildschirm im Querformat rechts zugeordnet werden. Zur Lösung dieses Problems können Sie OpenGL-Projektionsmodi und Kameraansichten anwenden, um Koordinaten so umzuwandeln, dass Ihre Grafikobjekte auf jedem Bildschirm die richtigen Proportionen haben.

Um Projektions- und Kameraansichten anzuwenden, erstellen Sie eine Projektionsmatrix und eine Kameraansichtsmatrix und wenden diese auf die OpenGL-Rendering-Pipeline an. Die Projektionsmatrix berechnet die Koordinaten Ihrer Grafiken so neu, dass sie den Bildschirmen von Android-Geräten korrekt zugeordnet werden. Die Kameraansichtsmatrix erzeugt eine Transformation, bei der Objekte ab einer bestimmten Augenposition gerendert werden.

Projektion und Kameraansicht in OpenGL ES 2.0 und höher

In den ES 2.0 und 3.0 APIs wenden Sie Projektion und Kameraansicht an, indem Sie zuerst ein Matrixmitglied zu den Vertex-Shadern Ihrer Grafikobjekte hinzufügen. Nachdem Sie dieses Matrixmitglied hinzugefügt haben, können Sie Projektions- und Kamerabetrachtungsmatrizen generieren und auf Ihre Objekte anwenden.

  1. Matrix zu Vertex-Shadern hinzufügen: Erstellen Sie eine Variable für die Ansichtsprojektionsmatrix und fügen Sie diese als Multiplikator für die Position des Shaders ein. Im folgenden beispielhaften Vertex-Shader-Code können Sie mit dem enthaltenen uMVPMatrix-Mitglied Projektions- und Kamerabetrachtungsmatrizen auf die Koordinaten von Objekten anwenden, die diesen Shader verwenden.

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

    Hinweis:Im obigen Beispiel wird ein einzelnes Transformationsmatrix-Element im Vertex-Shader definiert, auf das Sie eine kombinierte Projektions- und Kameraansichtsmatrix anwenden. Abhängig von Ihren Anwendungsanforderungen können Sie separate Projektionsmatrix und Mitglieder der Kameraanzeige-Matrix in Ihren Vertex-Shadern definieren, um sie unabhängig voneinander zu ändern.

  2. Auf die Shader-Matrix zugreifen: Nachdem Sie in Ihren Vertex-Shadern einen Hook für die Projektion und die Kameraansicht erstellt haben, können Sie auf diese Variable zugreifen, um Projektions- und Kameraanzeigematrizen anzuwenden. Der folgende Code zeigt, wie Sie die Methode onSurfaceCreated() einer GLSurfaceView.Renderer-Implementierung ändern, um auf die im obigen Vertex-Shader definierte Matrixvariable zuzugreifen.

    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. Projektions- und Kameraanzeigematrizen erstellen: Generieren Sie die Projektions- und Anzeigematrizen, auf die die Grafikobjekte angewendet werden sollen. Der folgende Beispielcode zeigt, wie die Methoden onSurfaceCreated() und onSurfaceChanged() einer GLSurfaceView.Renderer-Implementierung geändert werden können, um eine Kameraansichtsmatrix und eine Projektionsmatrix basierend auf dem Bildschirmseitenverhältnis des Geräts zu erstellen.

    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. Projektions- und Kameraanzeigematrizen anwenden: Um die Transformationen von Projektion und Kameraansicht anzuwenden, multiplizieren Sie die Matrizen und legen Sie sie im Scheitelpunkt-Shader ein. Der folgende Beispielcode zeigt, wie die Methode onDrawFrame() einer GLSurfaceView.Renderer-Implementierung geändert wird, um die im obigen Code erstellte Projektionsmatrix und Kameraansicht zu kombinieren und sie dann auf die Grafikobjekte anzuwenden, die von OpenGL gerendert werden.

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

Ein vollständiges Beispiel für die Anwendung von Projektion und Kameraansicht mit OpenGL ES 2.0 finden Sie in der Klasse Grafiken mit OpenGL ES anzeigen.

Zifferblätter und Windungen

In OpenGL ist die Fläche einer Form eine Oberfläche, die durch drei oder mehr Punkte in einem dreidimensionalen Raum definiert ist. Eine Gruppe von drei oder mehr dreidimensionalen Punkten (bei OpenGL als Eckpunkte bezeichnet) hat eine Vorder- und eine Rückseite. Woher weiß man, welches Gesicht vorne und welches die hintere ist? Das ist eine gute Frage. Die Antwort hat mit der Windung zu tun, also der Richtung, in der Sie die Punkte einer Form definieren.

Koordinaten der Eckpunkte
eines Dreiecks

Abbildung 1: Abbildung einer Koordinatenliste, die sich in eine Zeichnungsreihenfolge gegen den Uhrzeigersinn übersetzt

In diesem Beispiel sind die Punkte des Dreiecks so definiert, dass sie gegen den Uhrzeigersinn gezeichnet werden. Die Reihenfolge, in der diese Koordinaten gezeichnet werden, definiert die Windrichtung der Form. Standardmäßig wird bei OpenGL die Fläche, die gegen den Uhrzeigersinn gezeichnet wird, die Vorderseite verwendet. Das in Abbildung 1 gezeigte Dreieck ist so definiert, dass die Vorderseite der Form (wie von OpenGL interpretiert) und die andere Seite die Rückseite ist.

Warum ist es wichtig zu wissen, welche Fläche einer Form die Vorderseite ist? Die Antwort hat mit einer gängigen OpenGL-Funktion namens Face Culling zu tun. Face Culling ist eine Option für die OpenGL-Umgebung, mit der die Rendering-Pipeline die Rückseite einer Form ignorieren (nicht berechnen oder zeichnen) kann, was Zeit, Speicher und Verarbeitungszyklen spart:

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

Wenn Sie versuchen, die Gesichtserkennung zu verwenden, ohne zu wissen, welche Seiten der Formen die Vorder- und Rückseite sind, sieht Ihre OpenGL-Grafik etwas zu dünn aus oder wird möglicherweise gar nicht angezeigt. Definieren Sie die Koordinaten Ihrer OpenGL-Formen also immer in Zeichenreihenfolge gegen den Uhrzeigersinn.

Hinweis:Es ist möglich, eine OpenGL-Umgebung festzulegen, die den Uhrzeigersinn als Vorderseite behandelt. Dies erfordert jedoch mehr Code und ist wahrscheinlich für erfahrene OpenGL-Entwickler verwirrend, wenn Sie sie um Hilfe bitten. Tun Sie das also nicht.

OpenGL-Versionen und Gerätekompatibilität

Die OpenGL ES 1.0- und 1.1-API-Spezifikationen werden seit Android 1.0 unterstützt. Die Grafikprogrammierung mit der OpenGL ES 1.0/1.1 API unterscheidet sich erheblich von der Version 2.0 und höher. OpenGL ES 2.0 wird von allen Android-Geräten ab Android 2.2 (API-Level 8) unterstützt und ist die früheste Version, die für neue Apps empfohlen wird, die mit OpenGL ES entwickelt werden. OpenGL ES 3.0 wird ab Android 4.3 (API-Level 18) auf Geräten mit einer Implementierung der OpenGL ES 3.0 API unterstützt. Informationen zur relativen Anzahl von Android-Geräten, die eine bestimmte Version von OpenGL ES unterstützen, finden Sie im OpenGL ES-Versionsdashboard.

Sie sollten die Grafikanforderungen sorgfältig berücksichtigen und die API-Version auswählen, die für Ihre App am besten geeignet ist. Weitere Informationen finden Sie unter OpenGL API-Version auswählen.

Die OpenGL ES 3.0 API bietet zusätzliche Funktionen, eine bessere Leistung als die 2.0 API und ist abwärtskompatibel. Das bedeutet, dass Sie Ihre Anwendung möglicherweise auf OpenGL ES 2.0 ausrichten und OpenGL ES 3.0-Grafikfunktionen bedingt einschließen können, sofern diese verfügbar sind. Weitere Informationen zum Prüfen der Verfügbarkeit der API 3.0 finden Sie unter OpenGL ES-Version prüfen.

Unterstützung für Texturkomprimierung

Durch die Texturkomprimierung kann die Leistung Ihrer OpenGL-Anwendung erheblich gesteigert werden, da weniger Arbeitsspeicher benötigt und die Speicherbandbreite effizienter genutzt wird. Das Android-Framework unterstützt das ETC1-Komprimierungsformat als Standardfunktion, einschließlich der Dienstprogrammklasse ETC1Util und des Komprimierungstool etc1tool (im Android SDK unter <sdk>/tools/). Ein Beispiel für eine Android-Anwendung mit Texturkomprimierung finden Sie im Codebeispiel CompressedTextureActivity im Android SDK (<sdk>/samples/<version>/ApiDemos/src/com/example/android/apis/graphics/).

Das ETC1-Format wird von allen Android-Geräten unterstützt, die OpenGL ES 2.0 oder höher unterstützen.

Hinweis:Das ETC1-Texturkomprimierungsformat unterstützt keine Texturen mit Transparenz (Alphakanal). Wenn Ihre Anwendung Texturen mit Transparenz erfordert, sollten Sie andere Texturkomprimierungsformate prüfen, die auf Ihren Zielgeräten verfügbar sind. Eine Methode zum Rendern von Alphakanal-Texturen mit ETC1 besteht darin, zwei ETC1-Texturobjekte zu binden: das erste mit Farbdaten, das zweite mit Alphakanaldaten und dann die Werte der beiden Texturen im Fragment-Shader kombiniert.

Die ETC2/EAC-Texturkomprimierungsformate sind garantiert verfügbar, wenn die OpenGL ES 3.0 API verwendet wird. Dieses Texturformat bietet hervorragende Komprimierungsverhältnisse mit hoher visueller Qualität. Außerdem unterstützt das Format Transparenz (Alphakanal).

Neben den ETC-Formaten bieten Android-Geräte auf Grundlage ihrer GPU-Chipsätze und OpenGL-Implementierungen unterschiedliche Unterstützung für die Texturkomprimierung. Informieren Sie sich über die Unterstützung der Texturkomprimierung auf den Zielgeräten, um festzustellen, welche Komprimierungstypen Ihre Anwendung unterstützen soll. Wenn Sie herausfinden möchten, welche Texturformate auf einem bestimmten Gerät unterstützt werden, müssen Sie das Gerät abfragen und sich die OpenGL-Erweiterungsnamen ansehen. Diese geben an, welche Texturkomprimierungsformate und andere OpenGL-Funktionen vom Gerät unterstützt werden. Im Folgenden werden einige häufig unterstützte Texturkomprimierungsformate unterstützt:

  • Anpassbare skalierbare Texturkomprimierung (ASTC): Ein Texturkomprimierungsformat, das frühere Formate ersetzen soll. Flexibler als vorherige Formate aufgrund der Unterstützung verschiedener Blockgrößen.
    • GL_KHR_texture_compression_astc_ldr
    • GL_KHR_texture_compression_astc_hdr(High Dynamic Range)
  • S3TC (DXTn/DXTC): Die S3-Texturkomprimierung (S3TC) hat verschiedene Formatvariationen (DXT1 bis DXT5) und ist weniger allgemein verfügbar. Das Format unterstützt RGB-Texturen mit 4-Bit-Alpha- oder 8-Bit-Alphakanälen. Diese Formate werden durch den folgenden Namen der OpenGL-Erweiterung dargestellt:
    • GL_EXT_texture_compression_s3tc
    Einige Geräte unterstützen nur die DXT1-Formatvariation. Dies wird durch den folgenden Namen der OpenGL-Erweiterung gekennzeichnet:
    • GL_EXT_texture_compression_dxt1

Die folgenden Texturkomprimierungsformate gelten als Legacy-Formate und werden nicht für die Verwendung in neuen Anwendungen empfohlen:

  • ATITC (ATC): Die ATI-Texturkomprimierung (ATITC oder ATC) ist auf einer Vielzahl von Geräten verfügbar und unterstützt die Komprimierung mit fester Rate für RGB-Texturen mit und ohne Alphakanal. Dieses Format kann durch verschiedene OpenGL-Erweiterungsnamen dargestellt werden, zum Beispiel:
    • GL_AMD_compressed_ATC_texture
    • GL_ATI_texture_compression_atitc
  • PVRTC: PowerVR-Texturkomprimierung (PVRTC) ist auf einer Vielzahl von Geräten verfügbar und unterstützt 2-Bit- und 4-Bit-Texturen pro Pixel mit oder ohne Alphakanal. Dieses Format wird durch den folgenden Namen der OpenGL-Erweiterung dargestellt:
    • GL_IMG_texture_compression_pvrtc
  • 3DC: Die 3DC-Texturkomprimierung ist ein weniger weit verbreitetes Format, das RGB-Texturen mit einem Alphakanal unterstützt. Dieses Format wird durch den folgenden Namen der OpenGL-Erweiterung dargestellt:
    • GL_AMD_compressed_3DC_texture

Warnung:Diese Texturkomprimierungsformate werden nicht auf allen Geräten unterstützt. Diese Formate können je nach Hersteller und Gerät variieren. Wie Sie bestimmen, welche Texturkomprimierungsformate auf einem bestimmten Gerät verwendet werden, finden Sie im nächsten Abschnitt.

Hinweis:Wenn Sie entschieden haben, welche Texturkomprimierungsformate Ihre Anwendung unterstützt, sollten Sie sie in Ihrem Manifest mit <supports-gl-texture> deklarieren. Die Verwendung dieser Deklaration ermöglicht das Filtern nach externen Diensten wie Google Play, sodass deine App nur auf Geräten installiert wird, die die für deine App erforderlichen Formate unterstützen. Weitere Informationen finden Sie unter OpenGL-Manifestdeklarationen.

OpenGL-Erweiterungen ermitteln

Die Implementierungen von OpenGL unterscheiden sich je nach Android-Gerät in Bezug auf die unterstützten Erweiterungen der OpenGL ES API. Diese Erweiterungen umfassen Texturkomprimierungen, umfassen aber normalerweise auch andere Erweiterungen des OpenGL-Funktionssatzes.

So findest du heraus, welche Texturkomprimierungsformate und andere OpenGL-Erweiterungen auf einem bestimmten Gerät unterstützt werden:

  1. Führen Sie den folgenden Code auf Ihren Zielgeräten aus, um festzustellen, welche Texturkomprimierungsformate unterstützt werden:

    Kotlin

    var extensions = gl.glGetString(GL10.GL_EXTENSIONS)
    

    Java

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

    Warnung:Das Ergebnis dieses Aufrufs variiert je nach Gerätemodell. Sie müssen diesen Aufruf auf mehreren Zielgeräten ausführen, um festzustellen, welche Komprimierungstypen üblicherweise unterstützt werden.

  2. Sehen Sie sich die Ausgabe dieser Methode an, um herauszufinden, welche OpenGL-Erweiterungen auf dem Gerät unterstützt werden.

Android Extension Pack (AEP)

Mit AEP wird sichergestellt, dass Ihre Anwendung einen standardisierten Satz von OpenGL-Erweiterungen unterstützt, der über den in der OpenGL 3.1-Spezifikation beschriebenen Kernsatz hinaus unterstützt. Durch die Kombination dieser Erweiterungen wird eine einheitliche Funktionalität für alle Geräte ermöglicht, während Entwickler gleichzeitig die Vorteile der neuesten Version von mobilen GPU-Geräten nutzen können.

Der AEP verbessert auch die Unterstützung für Bilder, Shader-Speicherpuffer und atomare Zähler in Fragment-Shadern.

Damit Ihre App AEP verwenden kann, muss im Manifest der App angegeben werden, dass die AEP erforderlich ist. Außerdem muss die Plattformversion dies unterstützen.

Alle in AEP angegebenen zusätzlichen Funktionen sind in der Basisspezifikation von OpenGL ES 3.2 enthalten. Wenn Ihre App OpenGL ES 3.2 erfordert, ist AEP nicht erforderlich.

Deklarieren Sie die AEP-Anforderung im Manifest so:

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

Wenn Sie prüfen möchten, ob die Plattformversion AEP unterstützt, verwenden Sie die Methode hasSystemFeature(String) und übergeben Sie FEATURE_OPENGLES_EXTENSION_PACK als Argument. Das folgende Code-Snippet zeigt ein Beispiel dafür:

Kotlin

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

Java

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

Wenn die Methode „true“ zurückgibt, wird AEP unterstützt.

Weitere Informationen zu AEP finden Sie auf der zugehörigen Seite in der Khronos OpenGL ES Registry.

OpenGL ES-Version prüfen

Auf Android-Geräten sind mehrere Versionen von OpenGL ES verfügbar. Du kannst in deinem Manifest die Mindestversion der API angeben, die für deine Anwendung erforderlich ist. Dabei kannst du aber auch gleichzeitig die Funktionen einer neueren API nutzen. Die OpenGL ES 3.0 API ist beispielsweise abwärtskompatibel mit Version 2.0 der API. Sie sollten Ihre Anwendung daher so schreiben, dass sie OpenGL ES 3.0-Funktionen verwendet, aber auf Version 2.0 API zurückgreift, wenn die API 3.0 nicht verfügbar ist.

Bevor Sie OpenGL ES-Funktionen mit einer Version verwenden, die höher als die in Ihrem App-Manifest erforderliche Mindestversion ist, sollte Ihre App die auf dem Gerät verfügbare API-Version prüfen. Dazu haben Sie zwei Möglichkeiten:

  1. Versuchen Sie, den übergeordneten OpenGL ES-Kontext (EGLContext) zu erstellen, und prüfen Sie das Ergebnis.
  2. Erstellen Sie einen mindestens unterstützten OpenGL ES-Kontext und prüfen Sie den Versionswert.

Der folgende Beispielcode zeigt, wie du die verfügbare OpenGL ES-Version prüfen kannst, indem du eine EGLContext erstellst und das Ergebnis prüfst. Dieses Beispiel zeigt, wie Sie nach OpenGL ES 3.0-Version suchen:

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

Wenn die oben gezeigte createContext()-Methode null zurückgibt, sollte Ihr Code stattdessen einen OpenGL ES 2.0-Kontext erstellen und ausschließlich diese API verwenden.

Das folgende Codebeispiel zeigt, wie Sie die OpenGL ES-Version prüfen, indem Sie zuerst einen unterstützten Mindestkontext erstellen und dann den Versionsstring prüfen:

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.

Wenn Sie bei diesem Ansatz feststellen, dass das Gerät eine höhere API-Version unterstützt, müssen Sie den OpenGL ES-Mindestkontext löschen und einen neuen Kontext mit der höheren verfügbaren API-Version erstellen.

OpenGL API-Version auswählen

OpenGL ES Version 2.0 und Version 3.0 bieten leistungsstarke Grafikoberflächen zum Erstellen von 3D-Spielen, -Visualisierungen und -Benutzeroberflächen. Die Grafikprogrammierung für OpenGL ES 2.0 und 3.0 ist weitgehend ähnlich, wobei Version 3.0 eine Obermenge der API 2.0 mit zusätzlichen Funktionen darstellt. Die Programmierung für die OpenGL ES 1.0/1.1 API im Vergleich zu OpenGL ES 2.0 und 3.0 unterscheidet sich erheblich und wird für neue Anwendungen nicht empfohlen. Entwickler sollten die folgenden Faktoren sorgfältig berücksichtigen, bevor sie mit der Entwicklung mit diesen APIs beginnen:

  • Gerätekompatibilität – Entwickler sollten die Gerätetypen, Android-Versionen und die OpenGL ES-Versionen berücksichtigen, die ihren Kunden zur Verfügung stehen. Weitere Informationen zur OpenGL-Kompatibilität auf verschiedenen Geräten finden Sie im Abschnitt OpenGL-Versionen und Gerätekompatibilität.
  • Texturunterstützung: Die OpenGL ES 3.0 API bietet die beste Unterstützung für die Texturkomprimierung, da sie die Verfügbarkeit des ETC2-Komprimierungsformats garantiert, das Transparenz unterstützt. Die 2.0-API-Implementierungen unterstützen ETC1, dieses Texturformat unterstützt jedoch keine Transparenz. Um Transparenz mit komprimierten Texturen zu implementieren, müssen Sie entweder zwei ETC1-Texturen verwenden (aufgeteilt zwischen Farbe und Alpha) oder Ressourcen in anderen Komprimierungsformaten bereitstellen, die von den Zielgeräten unterstützt werden. Weitere Informationen finden Sie unter Unterstützung der Texturkomprimierung.

Auch wenn Kompatibilität und Texturunterstützung Ihre Entscheidung beeinflussen können, sollten Sie eine OpenGL API-Version auf Basis derjenigen wählen, die Ihrer Meinung nach die beste Erfahrung für Ihre Nutzer bietet.