OpenGL ES

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

  • 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, устройство не может поддерживать OpenGL ES 3.0 API, если производитель устройства не предоставляет реализацию этого графического конвейера. Если в манифесте указано, что требуется OpenGL ES 3.0, вы можете быть уверены, что эта версия будет на устройстве. Если вы укажете, что требуется более ранняя версия, но хотите использовать функции версии 3.0, когда они доступны, вам следует проверять во время выполнения, какую версию OpenGL поддерживает устройство. Подробнее о том, как проверить версию OpenGL ES…

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

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

См. также

Основные сведения

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

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

GLSurfaceView
Этот класс представляет собой View, в котором можно рисовать объекты и управлять ими с помощью вызовов OpenGL API. По своим функциям он похож на 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, поддерживаемую устройством…

  • Требования к сжатию текстур. Если в вашем приложении используются форматы сжатия текстур, вы должны указать поддерживаемые форматы в файле манифеста с помощью <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 позволяет применять матрицы проекции и просмотра камеры к координатам объектов, использующих этот шейдер.

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

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

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

    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. Создайте матрицы проекции и просмотра. Сгенерируйте матрицы проекции и просмотра, которые будут применены к графическим объектам. В приведенном ниже примере кода показано, как изменить методы onSurfaceCreated() и onSurfaceChanged() реализации GLSurfaceView.Renderer, чтобы создать матрицу вида камеры и матрицу проекции на основе соотношения сторон экрана устройства.

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

Полный пример того, как применить проекцию и вид камеры с помощью OpenGL ES 2.0, можно найти в классе Displaying graphics with OpenGL ES.

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

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

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

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

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

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

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

Если вы попытаетесь использовать функцию отсечения граней, не зная, какие стороны ваших фигур являются передними и задними, ваша графика 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 с версией 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…

OpenGL ES 3.0 API предлагает дополнительные функции и более высокую производительность по сравнению с версией 2.0, а также обратную совместимость. Это означает, что вы можете написать приложение, ориентированное на OpenGL ES 2.0, и условно включить графические функции OpenGL ES 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 гарантированно доступны при использовании OpenGL ES 3.0 API. Этот формат текстур обеспечивает отличную степень сжатия при высоком качестве изображения и поддерживает прозрачность (альфа-канал).

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

  • Adaptable Scalable Texture Compression (ASTC) – формат сжатия текстур, который должен заменить предыдущие форматы. Более гибкий формат по сравнению с предыдущими, поскольку поддерживает разные размеры блоков.
    • GL_KHR_texture_compression_astc_ldr
    • GL_KHR_texture_compression_astc_hdr(расширенный динамический диапазон)
  • S3TC (DXTn/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, который поддерживается не так широко, как другие, но позволяет использовать текстуры RGB с альфа-каналом. Этот формат представлен следующим названием расширения OpenGL:
    • GL_AMD_compressed_3DC_texture

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

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

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

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

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

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

    Kotlin

    var extensions = gl.glGetString(GL10.GL_EXTENSIONS)

    Java

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

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

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

Android Extension Pack (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. Ниже приведен пример фрагмента кода, в котором показано, как это сделать:

Kotlin

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

Java

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

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

Дополнительную информацию о профиле AEP можно найти на странице реестра Khronos OpenGL ES.

Как проверить версию OpenGL ES

На устройствах Android доступно несколько версий OpenGL ES. Вы можете указать минимальную версию 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:

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

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

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

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.

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

Как выбрать версию API OpenGL

Версии 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 значительно различается, поэтому не рекомендуется использовать OpenGL ES 1.0/1.1 для новых приложений. Прежде чем начинать разработку с использованием этих API, разработчикам следует внимательно изучить следующие факторы:

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

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