OpenGL ES

Android 通过开放图形库支持高性能 2D 和 3D 图形 (OpenGL®),具体而言是 OpenGL ES API。OpenGL 是一种跨平台的图形 API 指定 标准软件接口。OpenGL ES 是 适用于嵌入式设备的规范。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 平台版本是什么,设备都不支持 OpenGL ES 3.0 API,除非设备制造商提供 该图形管道的实现。如果您在清单中指定 需要 OpenGL ES 3.0,您可以放心使用该版本 。如果您指定需要较低级别的版本,但您 想要使用 3.0 功能(如果可用),则应在运行时进行检查 查看该设备支持的 OpenGL 版本。如需了解如何 请参见检查 OpenGL ES 版本

注意: Android 支持 OpenGL ES 1.0 和 1.1,但这些版本的 API 已弃用,不应用于现代应用。

注意: Android 框架提供的特定 API 类似于 J2ME JSR239 OpenGL ES API, 但不完全相同如果您熟悉 J2ME JSR239 规范,请注意以下事项: 变体。

另请参阅

基础知识

Android 通过其框架 API 和原生开发来支持 OpenGL 套件 (NDK)。本主题侧重于介绍 Android 框架接口。如需详细了解 NDK,请参阅 Android NDK

Android 框架中有两个基础类,可用于创建和操控 支持 OpenGL ES API 的图形:GLSurfaceViewGLSurfaceView.Renderer。如果您的目标是在 Android 应用中使用 OpenGL 了解如何在 activity 中实现这些类应该是您的首要目标。

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 软件包

使用 GLSurfaceViewGLSurfaceView.Renderer 为 OpenGL ES 建立容器视图后,您就可以开始 使用以下类调用 OpenGL API:

  • OpenGL ES 2.0 API 类 <ph type="x-smartling-placeholder">
      </ph>
    • android.opengl.GLES20 - 此软件包提供 接口,从 Android 2.2(API 级别 8)开始提供。
  • OpenGL ES 3.0/3.1/3.2 API 软件包 <ph type="x-smartling-placeholder">

如果您想立即开始使用 OpenGL ES 构建应用,请按照 使用 OpenGL ES 显示图形 类。

声明 OpenGL 要求

如果您的应用使用的 OpenGL 功能并非在所有设备上都可用,则必须将 AndroidManifest.xml 中的这些要求 文件。以下是最常见的 OpenGL 清单声明:

  • 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" />
    

    注意: OpenGL ES 3.x API 向后兼容 2.0 API,这意味着您可以 您可以灵活地在应用中实现 OpenGL ES。通过声明 OpenGL ES 2.0 API 作为清单中的一项要求,您可以使用该 API 版本作为默认版本,请查看 以了解 3.x API 在运行时是否可用,然后使用 OpenGL ES 3.x 功能,如果 设备支持该功能。如需详细了解如何查看 请参阅检查 OpenGL ES 版本

  • 纹理压缩要求 - 如果您的应用使用纹理 压缩格式,因此您必须在清单文件中声明应用支持的格式 使用<supports-gl-texture>。 如需详细了解可用的纹理压缩 格式,请参阅纹理压缩支持

    如果在清单中声明纹理压缩要求,则用户看不到您的应用 设备不支持您声明的压缩类型中的至少一种。有关 有关 Google Play 过滤如何对纹理压缩进行压缩的信息,请参阅 <ph type="x-smartling-placeholder"></ph> <supports-gl-texture> 文档的 Google Play 和纹理压缩过滤部分。

映射已绘制对象的坐标

在 Android 设备上显示图形的一个基本问题是,设备的屏幕 大小和形状各不相同。OpenGL 假定一个方形、统一的坐标系,并且默认情况下, 会将这些坐标绘制到通常非方形的屏幕上,就像是完全正方形的屏幕一样。

图 1. 映射到典型 Android 的默认 OpenGL 坐标系(左侧) 设备屏幕(右)。

上图显示了为视图上的 OpenGL 帧假定的统一坐标系 以及这些坐标在横向模式下实际是如何映射到典型设备屏幕上的 。要解决此问题,您可以将 OpenGL 投影模式和相机视图应用于 转换坐标,以使您的图形对象在任何显示设备上都保持正确的比例。

为了应用投影和相机视图,您可以创建投影矩阵和相机视图 并将它们应用到 OpenGL 渲染管道。投影矩阵重新计算 坐标,使图形正确映射到 Android 设备屏幕上。相机视图 矩阵会创建一个转换,从特定眼睛位置渲染对象。

OpenGL ES 2.0 及更高版本中的投影和相机视图

在 ES 2.0 和 3.0 API 中,要应用投影和相机视图,首先添加一个矩阵成员 应用到图形对象的顶点着色器中。添加此矩阵成员后,您可以 生成投影和相机查看矩阵并将其应用到您的对象。

  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. 访问着色器矩阵 - 在顶点着色器中创建钩子机制后, 应用投影和相机视图,您便可访问该变量以应用投影和 相机观看矩阵。以下代码展示了如何修改 GLSurfaceView.Renderer 实现的 onSurfaceCreated() 方法来访问矩阵 变量。

    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. 应用投影和相机查看矩阵 - 要应用投影和相机查看矩阵, 将矩阵相乘,然后将它们设为顶点 着色器。以下示例代码展示了如何修改 GLSurfaceView.Renderer 实现的 onDrawFrame() 方法以组合 在上述代码中创建的投影矩阵和相机视图,然后将其应用到图形 将对象提供给 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 应用投影和相机视图的完整示例,请参阅使用 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 版本和设备兼容性

从 Android 1.0 开始,OpenGL ES 1.0 和 1.1 API 规范均受支持。 使用 OpenGL ES 1.0/1.1 API 的图形编程明显不同于使用 OpenGL ES 2.0 的 及更高版本。 所有从 Android 2.2(API 级别 8)开始的 Android 设备均支持 OpenGL ES 2.0, 为使用 OpenGL ES 开发的新应用推荐的最早版本。 Android 4.3(API 级别 18)及更高版本支持 OpenGL ES 3.0,这些设备提供 OpenGL ES 3.0 API 的实现。 关于相对数量的 Android 设备的信息 支持指定版本的 OpenGL ES 的应用,请参阅 OpenGL ES 版本信息中心

您应仔细考虑图形要求并选择 API 最适合您的应用的版本。如需了解详情,请参阅 选择 OpenGL API 版本

与 OpenGL ES 2.0 API 相比,OpenGL ES 3.0 API 提供了更多功能和更出色的性能, 也向后兼容这意味着您可以编写针对 OpenGL ES 2.0,并且有条件地包含 OpenGL ES 3.0 图形功能(如果可用)。对于 请参阅 检查 OpenGL ES 版本

纹理压缩支持

纹理压缩可显著提高 OpenGL 应用的性能, 从而减少内存需求,更有效地利用内存带宽。Android 框架支持将 ETC1 压缩格式作为标准功能,其中包括 ETC1Util 实用程序类和 etc1tool 压缩工具(位于 Android SDK (<sdk>/tools/)。有关使用 纹理压缩,请参阅 Android SDK 中的 CompressedTextureActivity 代码示例 (<sdk>/samples/<version>/ApiDemos/src/com/example/android/apis/graphics/)。

所有支持 OpenGL ES 2.0 或更高版本的 Android 设备均支持 ETC1 格式。

注意:ETC1 纹理压缩格式不支持 透明度(alpha 通道)。如果您的应用需要具有透明度的纹理,您应该 调查目标设备上可用的其他纹理压缩格式。答 使用 ETC1 渲染 alpha 通道纹理的方法是绑定两个 ETC1 纹理对象: 第一个使用颜色数据,第二个使用 Alpha 通道数据,然后将两个值 fragment 着色器中的纹理。

使用 OpenGL ES 时,ETC2/EAC 纹理压缩格式保证可用 3.0 API。这种纹理格式可提供极佳的压缩比和较高的视觉效果, 格式也支持透明度(alpha 通道)。

除了 ETC 格式之外,Android 设备还针对纹理压缩提供各种支持,具体取决于 GPU 芯片组和 OpenGL 实现。您应该研究 您的目标设备,以确定您的应用应该使用的压缩类型 联系。要确定指定设备上支持的纹理格式,您必须 查询设备并查看 OpenGL 扩展名称, 用于确定 设备。一些受支持的常用纹理压缩格式如下:

  • 自适应可缩放纹理压缩 (ASTC) - 一种纹理压缩格式 旨在取代之前的格式比以前的格式更加灵活,因为它支持各种 块规模。
    • GL_KHR_texture_compression_astc_ldr
    • GL_KHR_texture_compression_astc_hdr(高动态范围)
  • S3TC (DXTn/DXTC) - S3 纹理压缩 (S3TC) 具有多种格式变体(DXT1 至 DXT5),它并非广泛适用。该格式支持具有 4 位 Alpha 通道或 8 位 Alpha 通道的 RGB 纹理。这些格式由以下 OpenGL 扩展表示 名称: <ph type="x-smartling-placeholder">
      </ph>
    • GL_EXT_texture_compression_s3tc
    。 某些设备仅支持 DXT1 格式变体;这种有限的支持由 以下 OpenGL 扩展名称: <ph type="x-smartling-placeholder">
      </ph>
    • GL_EXT_texture_compression_dxt1

以下纹理压缩格式被视为旧格式,不推荐使用 以便用于新应用:

  • ATITC (ATC) - ATI 纹理压缩(ATITC 或 ATC)适用于 支持对 RGB 纹理进行固定速率压缩,无论有无 也就是 Alpha 通道此格式可以由多个 OpenGL 扩展名称表示,例如: <ph type="x-smartling-placeholder">
      </ph>
    • GL_AMD_compressed_ATC_texture
    • GL_ATI_texture_compression_atitc
  • PVRTC - PowerVR 纹理压缩 (PVRTC) 适用于 各种设备,并且支持 2 位和 4 位/像素纹理(无论是否有 alpha 通道)。 此格式由以下 OpenGL 扩展名称表示: <ph type="x-smartling-placeholder">
      </ph>
    • GL_IMG_texture_compression_pvrtc
  • 3DC - 3DC 纹理压缩 (3DC) 是一种广泛使用的格式, 支持具有 alpha 通道的 RGB 纹理。此格式由以下 OpenGL 表示 扩展程序名称: <ph type="x-smartling-placeholder">
      </ph>
    • GL_AMD_compressed_3DC_texture

警告:这些纹理压缩格式不受 支持所有设备。对这些格式的支持因制造商和设备而异。对于 有关如何确定特定设备上有哪些纹理压缩格式的信息,请参见 下一部分。

注意:在确定要使用哪些纹理压缩格式后, 请确保使用以下代码在清单中声明它们 <supports-gl-texture> 。使用此声明支持按 Google Play 等外部服务进行过滤, 您的应用只能安装在支持该应用所需格式的设备上。有关详情,请参阅 OpenGL 清单声明

确定 OpenGL 扩展

在 OpenGL ES API 扩展方面,OpenGL 的实现因 Android 设备而异 模型。这些扩展包括纹理压缩,但通常还包括其他 OpenGL 功能集的扩展。

为了确定 Google Cloud 上支持哪些纹理压缩格式和其他 OpenGL 扩展, 特定设备:

  1. 在目标设备上运行以下代码,以确定哪种纹理压缩 支持的格式:

    Kotlin

    var extensions = gl.glGetString(GL10.GL_EXTENSIONS)
    

    Java

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

    警告:此调用的结果因设备型号而异!您 必须在多个目标设备上运行此调用,以确定常见的压缩类型 支持。

  2. 查看此方法的输出,以确定 设备。

Android Extension Pack (AEP)

AEP 可确保您的应用支持上述一组标准化的 OpenGL 扩展。 甚至更多 OpenGL 3.1 规范中描述的核心集。将这些扩展程序打包在一起 鼓励开发者在各种设备上提供一致的功能,同时又能让开发者全面 充分利用最新的移动 GPU 设备。

AEP 还改进了对图像、着色器存储缓冲区和 fragment 着色器。

为了让您的应用能够使用 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 的详情,请访问 <ph type="x-smartling-placeholder"></ph> Khronos OpenGL ES Registry

检查 OpenGL ES 版本

Android 设备上提供了多个版本的 OpenGL ES。您可以指定 清单中注明了应用所需的最低 API 版本,但是 您可能还希望同时利用较新 API 中的功能。例如: OpenGL ES 3.0 API 向后兼容 2.0 版 API,因此您可能需要 编写应用,使其使用 OpenGL ES 3.0 功能,但如果 3.0 API 不可用。

如果 OpenGL ES 功能的版本高于您的 应用清单中,那么您的应用应检查设备上可用的 API 版本。 为此,您可以采用下列两种方式之一:

  1. 尝试创建更高级别的 OpenGL ES 上下文 (EGLContext), 检查结果。
  2. 创建支持的最低级别的 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。

以下代码示例演示了如何通过创建 支持的上下文,然后检查版本字符串:

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 版本。

选择 OpenGL API 版本

OpenGL ES 2.0 版和 3.0 版都提供较高的 高性能图形界面 - 用于制作 3D 游戏、可视化内容和用户界面。图形 OpenGL ES 2.0 和 3.0 的编程基本相似,其中版本 3.0 表示一个超集 2.0 API 的新增功能。OpenGL ES 1.0/1.1 API 与 OpenGL ES 编程 2.0 和 3.0 差别很大,不建议在新应用中使用。 在开始开发应用之前,开发者应仔细考虑以下因素 这些 API:

  • 设备兼容性 - 开发者应考虑设备类型、 Android 版本和 OpenGL ES 版本。更多信息 请参阅 OpenGL 版本和 设备兼容性部分。
  • 纹理支持 - OpenGL ES 3.0 API 对纹理有最佳支持 因为它能保证 ETC2 压缩格式的可用性, 透明度。不过,2.0 API 实现包括对 ETC1 的支持。 这种纹理格式不支持透明度。为了实现透明度,使用压缩 必须使用两个 ETC1 纹理(在颜色和 alpha 之间拆分)或提供资源, 采用您定位的设备支持的其他压缩格式。如需更多信息 请参阅纹理压缩支持

尽管兼容性和纹理支持可能会影响您的 您应根据自己认为能提供最佳体验的 OpenGL API 版本 。