构建 OpenGL ES 环境

如需在 Android 应用中使用 OpenGL ES 绘制图形,您必须为它们创建一个视图容器。其中一种更直接的方法就是同时实现 GLSurfaceViewGLSurfaceView.RendererGLSurfaceView 是使用 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 级别 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);

此设置可防止系统在您调用 requestRender() 之前重新绘制 GLSurfaceView 帧,这对此示例应用而言更为高效。

构建渲染程序类

在使用 OpenGL ES 的应用中,GLSurfaceView.Renderer 类(或渲染程序)的实现开始变得有趣起来。此类可控制在与其关联的 GLSurfaceView 上绘制的内容。Android 系统会调用渲染程序中的以下三种方法来确定在 GLSurfaceView 上绘制什么内容以及如何绘制:

  • onSurfaceCreated() - 调用一次以设置视图的 OpenGL ES 环境。
  • onDrawFrame() - 每次重新绘制视图时调用。
  • onSurfaceChanged() - 在视图的几何图形发生变化(例如,当设备的屏幕方向发生变化)时调用。

以下是 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);
    }
}

就是这么简单!上面的代码示例使用 OpenGL 创建了一个显示黑屏的简单 Android 应用。虽然此代码不会执行任何非常有趣的操作,但通过创建这些类,您已经为开始使用 OpenGL 绘制图形元素奠定了基础。

注意:当您使用 OpengGL ES 2.0 API 时,您可能想知道为什么这些方法具有 GL10 参数。 这些方法签名直接重复用于 2.0 API,使 Android 框架代码更简单。

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