OpenGL ЕС

Android включает поддержку высокопроизводительной 2D- и 3D-графики с помощью открытой графической библиотеки (OpenGL®), в частности OpenGL ES API. OpenGL — это кроссплатформенный графический API, определяющий стандартный программный интерфейс для аппаратного обеспечения обработки 3D-графики. OpenGL ES — это разновидность спецификации OpenGL, предназначенная для встраиваемых устройств. Android поддерживает несколько версий OpenGL ES API:

  • OpenGL ES 2.0 — эта спецификация API поддерживается Android 2.2 (уровень API 8) и выше.
  • OpenGL ES 3.0 — эта спецификация API поддерживается Android 4.3 (уровень API 18) и выше.
  • OpenGL ES 3.1. Эта спецификация API поддерживается Android 5.0 (уровень API 21) и выше.
  • OpenGL ES 3.2. Эта спецификация API поддерживается Android 7.0 (уровень API 24) и выше.

Внимание: независимо от версии платформы Android устройство не может поддерживать API OpenGL ES 3.0, если производитель устройства не предоставит реализацию этого графического конвейера. Если вы укажете в манифесте, что требуется OpenGL ES 3.0, вы можете быть уверены, что эта версия будет присутствовать на устройстве. Если вы указываете, что требуется версия более низкого уровня, но хотите использовать функции 3.0, если они доступны, вам следует проверить во время выполнения, какую версию OpenGL поддерживает устройство. Информацию о том, как это сделать, см. в разделе Проверка версии OpenGL ES .

Примечание. Android включает поддержку OpenGL ES 1.0 и 1.1, но эти версии API устарели и не должны использоваться современными приложениями.

Примечание. Конкретный API, предоставляемый платформой Android, аналогичен API J2ME JSR239 OpenGL ES, но не идентичен. Если вы знакомы со спецификацией J2ME JSR239, будьте внимательны к вариациям.

Также см.

Основы

Android поддерживает OpenGL как через API-интерфейс платформы, так и через Native Development Kit (NDK). В этой теме основное внимание уделяется интерфейсам платформы Android. Дополнительные сведения о NDK см. в Android NDK .

В платформе Android есть два основных класса, которые позволяют создавать графику и манипулировать ею с помощью API OpenGL ES: GLSurfaceView и GLSurfaceView.Renderer . Если ваша цель — использовать OpenGL в приложении Android, вашей первой целью должно быть понимание того, как реализовать эти классы в действии.

GLSurfaceView
Этот класс представляет собой View , в котором вы можете рисовать объекты и манипулировать ими с помощью вызовов API OpenGL, и по функциям он аналогичен SurfaceView . Вы можете использовать этот класс, создав экземпляр GLSurfaceView и добавив к нему свой Renderer . Однако если вы хотите перехватывать события сенсорного экрана, вам следует расширить класс GLSurfaceView для реализации прослушивателей касаний, как показано в обучающем уроке OpenGL « Реагирование на события касания» .
GLSurfaceView.Renderer
Этот интерфейс определяет методы, необходимые для рисования графики в GLSurfaceView . Вы должны предоставить реализацию этого интерфейса как отдельный класс и прикрепить его к вашему экземпляру GLSurfaceView с помощью GLSurfaceView.setRenderer() .

Интерфейс GLSurfaceView.Renderer требует реализации следующих методов:

  • onSurfaceCreated() : система вызывает этот метод один раз при создании GLSurfaceView . Используйте этот метод для выполнения действий, которые необходимо выполнить только один раз, например установки параметров среды OpenGL или инициализации графических объектов OpenGL.
  • onDrawFrame() : система вызывает этот метод при каждой перерисовке GLSurfaceView . Используйте этот метод в качестве основной точки выполнения для рисования (и повторного рисования) графических объектов.
  • onSurfaceChanged() : система вызывает этот метод при изменении геометрии GLSurfaceView , включая изменения размера GLSurfaceView или ориентации экрана устройства. Например, система вызывает этот метод, когда устройство меняет ориентацию с книжной на альбомную. Используйте этот метод для реагирования на изменения в контейнере GLSurfaceView .

OpenGL ES-пакеты

После того как вы установили представление контейнера для OpenGL ES с помощью GLSurfaceView и GLSurfaceView.Renderer , вы можете начать вызывать API OpenGL, используя следующие классы:

  • Класс API OpenGL ES 2.0
    • android.opengl.GLES20 — этот пакет предоставляет интерфейс для OpenGL ES 2.0 и доступен, начиная с Android 2.2 (уровень API 8).
  • Пакеты API OpenGL ES 3.0/3.1/3.2
    • android.opengl — этот пакет предоставляет интерфейс для классов OpenGL ES 3.0/3.1. Версия 3.0 доступна начиная с Android 4.3 (уровень API 18). Версия 3.1 доступна начиная с Android 5.0 (уровень API 21). Версия 3.2 доступна начиная с Android 7.0 (уровень API 24).

Если вы хотите сразу начать создавать приложение с использованием OpenGL ES, следуйте инструкциям в классе «Отображение графики с помощью OpenGL ES» .

Объявление требований OpenGL

Если ваше приложение использует функции OpenGL, которые доступны не на всех устройствах, вы должны включить эти требования в файл AndroidManifest.xml . Вот наиболее распространенные объявления манифеста OpenGL:

  • Требования к версии OpenGL ES . Если вашему приложению требуется определенная версия OpenGL ES, вы должны объявить это требование, добавив в манифест следующие параметры, как показано ниже.

    Для OpenGL ES 2.0:

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

    Добавление этого объявления приведет к тому, что Google Play запретит установку вашего приложения на устройства, которые не поддерживают OpenGL ES 2.0. Если ваше приложение предназначено исключительно для устройств, поддерживающих OpenGL ES 3.0, вы также можете указать это в своем манифесте:

    Для 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" />
    

    Примечание. API OpenGL ES 3.x обратно совместим с API 2.0, что означает, что вы можете быть более гибкими при реализации OpenGL ES в своем приложении. Объявив API OpenGL ES 2.0 обязательным в своем манифесте, вы можете использовать эту версию API по умолчанию, проверять доступность API 3.x во время выполнения, а затем использовать функции OpenGL ES 3.x, если устройство поддерживает это. Дополнительные сведения о проверке версии OpenGL ES, поддерживаемой устройством, см. в разделе Проверка версии OpenGL ES .

  • Требования к сжатию текстур . Если ваше приложение использует форматы сжатия текстур, вы должны объявить форматы, которые поддерживает ваше приложение, в файле манифеста, используя <supports-gl-texture> . Дополнительные сведения о доступных форматах сжатия текстур см. в разделе Поддержка сжатия текстур .

    Объявление требований к сжатию текстур в манифесте скроет ваше приложение от пользователей устройств, которые не поддерживают хотя бы один из объявленных вами типов сжатия. Дополнительную информацию о том, как работает фильтрация Google Play для сжатия текстур, см. в разделе «Google Play и фильтрация сжатия текстур» документации <supports-gl-texture> .

Сопоставление координат нарисованных объектов

Одна из основных проблем отображения графики на устройствах Android заключается в том, что их экраны могут различаться по размеру и форме. OpenGL предполагает квадратную единую систему координат и по умолчанию с удовольствием рисует эти координаты на обычно неквадратном экране, как если бы он был идеально квадратным.

Рис. 1. Система координат OpenGL по умолчанию (слева), сопоставленная с типичным экраном устройства Android (справа).

На рисунке выше показана единая система координат, предполагаемая для кадра OpenGL слева, и то, как эти координаты фактически отображаются на типичном экране устройства в альбомной ориентации справа. Чтобы решить эту проблему, вы можете применить режимы проекции OpenGL и виды камеры для преобразования координат, чтобы ваши графические объекты имели правильные пропорции на любом дисплее.

Чтобы применить представления проекции и камеры, вы создаете матрицу проекции и матрицу вида камеры и применяете их к конвейеру рендеринга OpenGL. Матрица проекции пересчитывает координаты вашей графики, чтобы они правильно отображались на экранах устройств Android. Матрица вида камеры создает преобразование, которое визуализирует объекты с определенной позиции глаза.

Вид проекции и камеры в OpenGL ES 2.0 и выше

В API ES 2.0 и 3.0 вы применяете проекцию и вид камеры, сначала добавляя элемент матрицы в вершинные шейдеры ваших графических объектов. Добавив этот элемент матрицы, вы можете затем генерировать и применять к своим объектам матрицы проекции и просмотра камеры.

  1. Добавить матрицу в вершинные шейдеры . Создайте переменную для матрицы проекции вида и включите ее в качестве множителя позиции шейдера. В следующем примере кода вершинного шейдера включенный элемент uMVPMatrix позволяет применять матрицы проекции и просмотра камеры к координатам объектов, использующих этот шейдер.

    Котлин

    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"
    

    Ява

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

    Примечание. В приведенном выше примере определяется один элемент матрицы преобразования в вершинном шейдере, к которому вы применяете объединенную матрицу проекции и матрицу обзора камеры. В зависимости от требований вашего приложения вы можете определить отдельные элементы матрицы проекции и матрицы обзора камеры в ваших вершинных шейдерах, чтобы вы могли изменять их независимо.

  2. Доступ к матрице шейдера . После создания перехватчика в вершинных шейдерах для применения проекции и вида с камеры вы можете получить доступ к этой переменной, чтобы применить матрицы проекции и просмотра с камеры. В следующем коде показано, как изменить метод onSurfaceCreated() реализации GLSurfaceView.Renderer для доступа к матричной переменной, определенной в вершинном шейдере выше.

    Котлин

    override fun onSurfaceCreated(gl: GL10, config: EGLConfig) {
        ...
        muMVPMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix")
        ...
    }
    

    Ява

    public void onSurfaceCreated(GL10 unused, EGLConfig config) {
        ...
        muMVPMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix");
        ...
    }
    
  3. Создание матриц проекции и просмотра камеры — создание матриц проекции и просмотра для применения к графическим объектам. В следующем примере кода показано, как изменить методы onSurfaceCreated() и onSurfaceChanged() реализации GLSurfaceView.Renderer для создания матрицы обзора камеры и матрицы проекции на основе соотношения сторон экрана устройства.

    Котлин

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

    Ява

    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. Применение матриц проекции и просмотра камеры . Чтобы применить преобразования проекции и вида камеры, умножьте матрицы вместе, а затем поместите их в вершинный шейдер. В следующем примере кода показано, как изменить метод onDrawFrame() реализации GLSurfaceView.Renderer , чтобы объединить матрицу проекции и вид камеры, созданные в приведенном выше коде, а затем применить его к графическим объектам, отображаемым с помощью OpenGL.

    Котлин

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

    Ява

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

Полный пример применения проекции и вида камеры с помощью OpenGL ES 2.0 см. в разделе Отображение графики с помощью класса OpenGL ES .

Форма граней и намотка

В OpenGL грань фигуры — это поверхность, определяемая тремя или более точками в трехмерном пространстве. Набор из трех или более трехмерных точек (называемых вершинами в OpenGL) имеет переднюю и заднюю грань. Как узнать, какое лицо спереди, а какое сзади? Хороший вопрос. Ответ связан с намоткой или направлением, в котором вы определяете точки фигуры.

Координаты вершин треугольника

Рисунок 1. Иллюстрация списка координат, который преобразуется в порядок рисования против часовой стрелки.

В этом примере точки треугольника определены в таком порядке, что они рисуются против часовой стрелки. Порядок, в котором рисуются эти координаты, определяет направление извилины фигуры. По умолчанию в OpenGL лицевой стороной является грань, нарисованная против часовой стрелки. Треугольник, показанный на рисунке 1, определен так, что вы смотрите на переднюю грань фигуры (как интерпретируется OpenGL), а другая сторона — это задняя грань.

Почему важно знать, какая грань фигуры является лицевой? Ответ связан с широко используемой функцией OpenGL, называемой отсечением лиц. Отсечение граней — это опция среды OpenGL, которая позволяет конвейеру рендеринга игнорировать (не вычислять и не рисовать) заднюю грань фигуры, экономя время, память и циклы обработки:

Котлин

gl.apply {
    // enable face culling feature
    glEnable(GL10.GL_CULL_FACE)
    // specify which faces to not draw
    glCullFace(GL10.GL_BACK)
}

Ява

// enable face culling feature
gl.glEnable(GL10.GL_CULL_FACE);
// specify which faces to not draw
gl.glCullFace(GL10.GL_BACK);

Если вы попытаетесь использовать функцию отсечения граней, не зная, какие стороны ваших фигур являются передней и задней, ваша графика OpenGL будет выглядеть немного тонкой или, возможно, вообще не будет отображаться. Поэтому всегда определяйте координаты фигур OpenGL в порядке рисования против часовой стрелки.

Примечание. Можно настроить среду OpenGL так, чтобы грань по часовой стрелке рассматривалась как передняя грань, но для этого потребуется больше кода и это может сбить с толку опытных разработчиков OpenGL, когда вы попросите их о помощи. Так что не делайте этого.

Версии OpenGL и совместимость устройств

Спецификации API OpenGL ES 1.0 и 1.1 поддерживаются начиная с Android 1.0. Графическое программирование с использованием API OpenGL ES 1.0/1.1 существенно отличается от использования версий 2.0 и более поздних версий. OpenGL ES 2.0 поддерживается всеми устройствами Android, начиная с Android 2.2 (уровень API 8), и является самой ранней версией, рекомендуемой для новых приложений, разрабатываемых с помощью OpenGL ES. OpenGL ES 3.0 поддерживается Android 4.3 (уровень API 18) и выше на устройствах, которые обеспечивают реализацию API OpenGL ES 3.0. Информацию об относительном количестве устройств под управлением Android, поддерживающих данную версию OpenGL ES, см. на информационной панели версий OpenGL ES .

Вам следует внимательно рассмотреть требования к графике и выбрать версию API, которая лучше всего подходит для вашего приложения. Дополнительные сведения см. в разделе Выбор версии OpenGL API .

API OpenGL ES 3.0 предоставляет дополнительные функции и более высокую производительность, чем API 2.0, а также обратно совместим. Это означает, что вы потенциально можете написать свое приложение, ориентированное на OpenGL ES 2.0, и при определенных условиях включить графические функции OpenGL ES 3.0, если они доступны. Дополнительную информацию о проверке доступности API 3.0 см. в разделе Проверка версии OpenGL ES.

Поддержка сжатия текстур

Сжатие текстур может значительно повысить производительность вашего приложения OpenGL за счет снижения требований к памяти и более эффективного использования пропускной способности памяти. Платформа Android обеспечивает поддержку формата сжатия ETC1 в качестве стандартной функции, включая служебный класс ETC1Util и инструмент сжатия etc1tool (находится в Android SDK по адресу <sdk>/tools/ ). Пример приложения Android, использующего сжатие текстур, см. в примере кода CompressedTextureActivity в Android SDK ( <sdk>/samples/<version>/ApiDemos/src/com/example/android/apis/graphics/ ).

Формат ETC1 поддерживается всеми устройствами Android, поддерживающими OpenGL ES 2.0 или выше.

Примечание. Формат сжатия текстур ETC1 не поддерживает текстуры с прозрачностью (альфа-канал). Если вашему приложению требуются текстуры с прозрачностью, вам следует изучить другие форматы сжатия текстур, доступные на ваших целевых устройствах. Метод рендеринга текстур альфа-канала с использованием ETC1 заключается в связывании двух объектов текстуры ETC1: первого с данными цвета, второго с данными альфа-канала, а затем объединения значений из двух текстур во фрагментном шейдере.

Форматы сжатия текстур ETC2/EAC гарантированно будут доступны при использовании API OpenGL ES 3.0. Этот формат текстур обеспечивает превосходную степень сжатия с высоким визуальным качеством, а также поддерживает прозрачность (альфа-канал).

Помимо форматов ETC, устройства Android имеют разнообразную поддержку сжатия текстур на основе чипсетов графических процессоров и реализаций OpenGL. Вам следует изучить поддержку сжатия текстур на целевых устройствах, чтобы определить, какие типы сжатия должно поддерживать ваше приложение. Чтобы определить, какие форматы текстур поддерживаются на данном устройстве, необходимо запросить устройство и просмотреть имена расширений OpenGL , которые определяют, какие форматы сжатия текстур (и другие функции OpenGL) поддерживаются устройством. Ниже приведены некоторые широко поддерживаемые форматы сжатия текстур:

  • Адаптируемое масштабируемое сжатие текстур (ASTC) — формат сжатия текстур, предназначенный для замены предыдущих форматов. Более гибкий, чем предыдущие форматы, благодаря поддержке блоков различных размеров.
    • GL_KHR_texture_compression_astc_ldr
    • GL_KHR_texture_compression_astc_hdr (расширенный динамический диапазон)
  • S3TC (DXT n /DXTC) — сжатие текстур S3 (S3TC) имеет несколько вариантов формата (от DXT1 до DXT5) и менее широко доступно. Формат поддерживает текстуры RGB с 4-битными или 8-битными альфа-каналами. Эти форматы представлены следующим именем расширения OpenGL:
    • GL_EXT_texture_compression_s3tc
    Некоторые устройства поддерживают только вариант формата DXT1; эта ограниченная поддержка представлена ​​следующим именем расширения OpenGL:
    • GL_EXT_texture_compression_dxt1

Следующие форматы сжатия текстур считаются устаревшими форматами и не рекомендуются для использования в новых приложениях:

  • ATITC (ATC) — сжатие текстур ATI (ATITC или ATC) доступно на самых разных устройствах и поддерживает сжатие с фиксированной скоростью для текстур RGB с альфа-каналом и без него. Этот формат может быть представлен несколькими именами расширений OpenGL, например:
    • GL_AMD_compressed_ATC_texture
    • GL_ATI_texture_compression_atitc
  • PVRTC — сжатие текстур PowerVR (PVRTC) доступно на самых разных устройствах и поддерживает 2-битные и 4-битные текстуры на пиксель с альфа-каналом или без него. Этот формат представлен следующим именем расширения OpenGL:
    • GL_IMG_texture_compression_pvrtc
  • 3DC — сжатие текстур 3DC (3DC) — менее широко доступный формат, поддерживающий текстуры RGB с альфа-каналом. Этот формат представлен следующим именем расширения OpenGL:
    • GL_AMD_compressed_3DC_texture

Предупреждение. Эти форматы сжатия текстур поддерживаются не всеми устройствами. Поддержка этих форматов зависит от производителя и устройства. Информацию о том, как определить, какие форматы сжатия текстур установлены на конкретном устройстве, смотрите в следующем разделе.

Примечание. После того, как вы решите, какие форматы сжатия текстур будет поддерживать ваше приложение, обязательно объявите их в своем манифесте с помощью <supports-gl-texture> . Использование этого объявления позволяет фильтровать внешние службы, такие как Google Play, поэтому ваше приложение устанавливается только на устройства, поддерживающие форматы, необходимые вашему приложению. Подробности см. в разделе «Объявления манифеста OpenGL» .

Определение расширений OpenGL

Реализации OpenGL различаются в зависимости от устройства Android с точки зрения поддерживаемых расширений OpenGL ES API. Эти расширения включают сжатие текстур, но обычно также включают в себя другие расширения набора функций OpenGL.

Чтобы определить, какие форматы сжатия текстур и другие расширения OpenGL поддерживаются на конкретном устройстве:

  1. Запустите следующий код на целевых устройствах, чтобы определить, какие форматы сжатия текстур поддерживаются:

    Котлин

    var extensions = gl.glGetString(GL10.GL_EXTENSIONS)
    

    Ява

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

    Внимание: результаты этого вызова зависят от модели устройства! Вам необходимо запустить этот вызов на нескольких целевых устройствах, чтобы определить, какие типы сжатия обычно поддерживаются.

  2. Просмотрите выходные данные этого метода, чтобы определить, какие расширения OpenGL поддерживаются на устройстве.

Пакет расширений Android (AEP)

AEP гарантирует, что ваше приложение поддерживает стандартизированный набор расширений OpenGL, помимо основного набора, описанного в спецификации OpenGL 3.1. Объединение этих расширений вместе обеспечивает единообразный набор функций на всех устройствах, позволяя разработчикам в полной мере использовать преимущества новейших мобильных устройств с графическим процессором.

AEP также улучшает поддержку изображений, буферов хранения шейдеров и атомарных счетчиков во фрагментных шейдерах.

Чтобы ваше приложение могло использовать AEP, в манифесте приложения должно быть указано, что AEP требуется. Кроме того, версия платформы должна его поддерживать.

Все дополнительные функции, указанные в AEP, включены в базовую спецификацию OpenGL ES 3.2. Если вашему приложению требуется OpenGL ES 3.2, вам не требуется AEP.

Объявите требование AEP в манифесте следующим образом:

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

Чтобы убедиться, что версия платформы поддерживает AEP, используйте метод hasSystemFeature(String) , передав FEATURE_OPENGLES_EXTENSION_PACK в качестве аргумента. В следующем фрагменте кода показан пример того, как это сделать:

Котлин

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

Ява

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

Если метод возвращает true, AEP поддерживается.

Для получения дополнительной информации об AEP посетите его страницу в реестре Khronos OpenGL ES .

Проверка версии OpenGL ES

На устройствах Android доступно несколько версий OpenGL ES. Вы можете указать минимальную версию API, требуемую вашему приложению, в своем манифесте , но в то же время вы также можете захотеть воспользоваться преимуществами более нового API. Например, API OpenGL ES 3.0 обратно совместим с версией API 2.0, поэтому вы можете написать свое приложение так, чтобы оно использовало функции OpenGL ES 3.0, но возвращалось к API 2.0, если API 3.0 не поддерживается. доступный.

Прежде чем использовать функции OpenGL ES из версии выше минимальной, требуемой в манифесте вашего приложения, ваше приложение должно проверить версию API, доступную на устройстве. Вы можете сделать это одним из двух способов:

  1. Попытайтесь создать контекст OpenGL ES более высокого уровня ( EGLContext ) и проверьте результат.
  2. Создайте минимально поддерживаемый контекст OpenGL ES и проверьте значение версии.

В следующем примере кода показано, как проверить доступную версию OpenGL ES, создав EGLContext и проверив результат. В этом примере показано, как проверить версию OpenGL ES 3.0:

Котлин

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

Ява

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

Если показанный выше метод createContext() возвращает значение null, ваш код должен вместо этого создать контекст OpenGL ES 2.0 и вернуться к использованию только этого API.

В следующем примере кода показано, как проверить версию OpenGL ES, сначала создав минимальный поддерживаемый контекст, а затем проверив строку версии:

Котлин

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

Ява

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

При таком подходе, если вы обнаружите, что устройство поддерживает версию API более высокого уровня, вы должны уничтожить минимальный контекст OpenGL ES и создать новый контекст с более доступной версией API.

Выбор версии OpenGL API

OpenGL ES версии 2.0 и версии 3.0 предоставляют высокопроизводительные графические интерфейсы для создания 3D-игр, визуализаций и пользовательских интерфейсов. Графическое программирование для OpenGL ES 2.0 и 3.0 во многом схоже: версия 3.0 представляет собой расширенный набор API 2.0 с дополнительными функциями. Программирование API OpenGL ES 1.0/1.1 и OpenGL ES 2.0 и 3.0 существенно различается и не рекомендуется для новых приложений. Прежде чем начинать разработку с использованием этих API, разработчикам следует внимательно учитывать следующие факторы:

  • Совместимость устройств . Разработчикам следует учитывать типы устройств, версии Android и версии OpenGL ES, доступные их клиентам. Дополнительные сведения о совместимости OpenGL на разных устройствах см. в разделе «Версии OpenGL и совместимость устройств» .
  • Поддержка текстур . API OpenGL ES 3.0 обеспечивает лучшую поддержку сжатия текстур, поскольку гарантирует доступность формата сжатия ETC2, который поддерживает прозрачность. Реализации API 2.0 включают поддержку ETC1, однако этот формат текстур не поддерживает прозрачность. Чтобы реализовать прозрачность с помощью сжатых текстур, вы должны либо использовать две текстуры ETC1 (разделенные между цветом и альфа-каналом), либо предоставить ресурсы в других форматах сжатия, поддерживаемых целевыми устройствами. Дополнительные сведения см. в разделе Поддержка сжатия текстур .

Хотя совместимость и поддержка текстур могут повлиять на ваше решение, вам следует выбрать версию OpenGL API на основе того, что, по вашему мнению, обеспечивает наилучшие возможности для ваших пользователей.