构建 OpenGL ES 环境

为了在 Android 应用中使用 OpenGL ES 绘制图形,您必须为它们创建一个视图容器。最直接的方法之一是同时实现 GLSurfaceViewGLSurfaceView.Renderer。其中 GLSurfaceView 是用于 OpenGL 绘制图形的视图容器,而 GLSurfaceView.Renderer 则控制在该视图内绘制的内容。有关这些类的更多信息,请参阅 OpenGL ES 开发者指南。

GLSurfaceView 只是将 OpenGL ES 图形集成到应用中的一种方式。对于全屏或接近全屏的图形视图,它是一个合理的选择。希望在布局的一小部分中集成 OpenGL ES 图形的开发者可以查看 TextureView。对于追求完全自定义的开发者,也可以使用 SurfaceView 构建 OpenGL ES 视图,但这需要编写相当多额外的代码。

本节课将介绍如何在简单的应用 Activity 中完成 GLSurfaceViewGLSurfaceView.Renderer 的最小化实现。

在清单文件中声明使用 OpenGL ES

为了使您的应用能够使用 OpenGL ES 2.0 API,您必须在清单文件中添加以下声明:

<uses-feature android:glEsVersion="0x00020000" android:required="true" />

如果您的应用使用了纹理压缩,您还必须声明应用支持的压缩格式,以便它仅安装在兼容的设备上。

<supports-gl-texture android:name="GL_OES_compressed_ETC1_RGB8_texture" />
<supports-gl-texture android:name="GL_OES_compressed_paletted_texture" />

有关纹理压缩格式的更多信息,请参阅 OpenGL 开发者指南。

为 OpenGL ES 图形创建 Activity

使用 OpenGL ES 的 Android 应用与其他具有用户界面的应用一样,拥有 Activity。与其他应用的主要区别在于您在 Activity 布局中放置的内容。虽然在许多应用中您可能会使用 TextViewButtonListView,但在使用 OpenGL ES 的应用中,您还可以添加 GLSurfaceView

以下代码示例展示了使用 GLSurfaceView 作为主要视图的 Activity 的最小化实现。

Kotlin

class OpenGLES20Activity : Activity() {

    private lateinit var gLView: GLSurfaceView

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Create a GLSurfaceView instance and set it
        // as the ContentView for this Activity.
        gLView = MyGLSurfaceView(this)
        setContentView(gLView)
    }
}

Java

public class OpenGLES20Activity extends Activity {

    private GLSurfaceView gLView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Create a GLSurfaceView instance and set it
        // as the ContentView for this Activity.
        gLView = new MyGLSurfaceView(this);
        setContentView(gLView);
    }
}

注意: OpenGL ES 2.0 需要 Android 2.2 (API Level 8) 或更高版本,因此请确保您的 Android 项目的目标 API 版本不低于此要求。

构建 GLSurfaceView 对象

GLSurfaceView 是一个专门用于绘制 OpenGL ES 图形的视图。它本身的功能有限。对象的实际绘制由您设置到此视图的 GLSurfaceView.Renderer 控制。实际上,该对象的代码非常精简,您可能很想直接使用未修改的 GLSurfaceView 实例而不去继承它,但请不要这样做。您需要继承此类以便捕获触摸事件,具体内容将在响应触摸事件一课中介绍。

GLSurfaceView 的核心代码极少,因此为了快速实现,通常只需在 Activity 中创建一个内部类即可。

Kotlin

import android.content.Context
import android.opengl.GLSurfaceView

class MyGLSurfaceView(context: Context) : GLSurfaceView(context) {

    private val renderer: MyGLRenderer

    init {

        // Create an OpenGL ES 2.0 context
        setEGLContextClientVersion(2)

        renderer = MyGLRenderer()

        // Set the Renderer for drawing on the GLSurfaceView
        setRenderer(renderer)
    }
}

Java

import android.content.Context;
import android.opengl.GLSurfaceView;

class MyGLSurfaceView extends GLSurfaceView {

    private final MyGLRenderer renderer;

    public MyGLSurfaceView(Context context){
        super(context);

        // Create an OpenGL ES 2.0 context
        setEGLContextClientVersion(2);

        renderer = new MyGLRenderer();

        // Set the Renderer for drawing on the GLSurfaceView
        setRenderer(renderer);
    }
}

GLSurfaceView 实现的另一个可选补充是设置渲染模式,使用 GLSurfaceView.RENDERMODE_WHEN_DIRTY 设置,仅在绘制数据发生变化时才重绘视图。

Kotlin

// Render the view only when there is a change in the drawing data
renderMode = GLSurfaceView.RENDERMODE_WHEN_DIRTY

Java

// Render the view only when there is a change in the drawing data
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);

此设置可以防止 GLSurfaceView 帧在您调用 requestRender() 之前被重绘,这对本示例应用而言效率更高。

构建渲染器类

在使用 OpenGL ES 的应用中,GLSurfaceView.Renderer 类(或称渲染器)的实现是整个过程的核心。此类控制在该关联的 GLSurfaceView 上绘制的内容。渲染器中有三个方法由 Android 系统调用,以确定如何以及在 GLSurfaceView 上绘制什么:

以下是一个最基本的 OpenGL ES 渲染器实现,它除了在 GLSurfaceView 中绘制黑色背景外,什么也不做。

Kotlin

import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.opengles.GL10

import android.opengl.GLES20
import android.opengl.GLSurfaceView

class MyGLRenderer : GLSurfaceView.Renderer {

    override fun onSurfaceCreated(unused: GL10, config: EGLConfig) {
        // Set the background frame color
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f)
    }

    override fun onDrawFrame(unused: GL10) {
        // Redraw background color
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
    }

    override fun onSurfaceChanged(unused: GL10, width: Int, height: Int) {
        GLES20.glViewport(0, 0, width, height)
    }
}

Java

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.opengl.GLES20;
import android.opengl.GLSurfaceView;

public class MyGLRenderer implements GLSurfaceView.Renderer {

    public void onSurfaceCreated(GL10 unused, EGLConfig config) {
        // Set the background frame color
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    }

    public void onDrawFrame(GL10 unused) {
        // Redraw background color
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
    }

    public void onSurfaceChanged(GL10 unused, int width, int height) {
        GLES20.glViewport(0, 0, width, height);
    }
}

这就是全部内容!上述代码示例创建了一个简单的 Android 应用,它使用 OpenGL 显示一个黑色屏幕。虽然这段代码本身并没有执行什么非常有趣的操作,但通过创建这些类,您已经为开始使用 OpenGL 绘制图形元素奠定了基础。

注意: 您可能会好奇,既然使用的是 OpenGL ES 2.0 API,为什么这些方法中包含一个 GL10 参数。这些方法签名只是为了保持 Android 框架代码的简洁而被 2.0 API 复用了。

如果您熟悉 OpenGL ES API,现在应该能够在应用中设置 OpenGL ES 环境并开始绘制图形了。但是,如果您在入门 OpenGL 时还需要更多帮助,请继续学习后续课程以获取更多提示。