构建 OpenGL ES 环境

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

GLSurfaceView 只是将 OpenGL ES 图形整合到您的应用程序中的方法之一。对于全屏或近乎全屏的图形视图,这是一个合理的选择。希望将 OpenGL ES 图形整合到布局中一小部分的开发者应该看一下 TextureView。对于真正的 DIY 开发者,也可以使用 SurfaceView 构建 OpenGL ES 视图,但这需要编写很多额外的代码。

本课程介绍了如何在简单的应用程序活动中完成 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 图形创建活动

使用 OpenGL ES 的 Android 应用程序具有与任何其他具有用户界面的应用程序相同的活动。与其他应用程序的主要区别在于您将什么放入活动的布局中。虽然在许多应用程序中您可能会使用 TextViewButtonListView,但在使用 OpenGL ES 的应用程序中,您还可以添加 GLSurfaceView

以下代码示例显示了使用 GLSurfaceView 作为其主视图的活动的最小实现

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 的基本代码非常少,因此对于快速实现,通常只需在使用它的活动中创建一个内部类

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 上绘制什么以及如何绘制

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

就是这样!上面的代码示例创建了一个简单的 Android 应用程序,它使用 OpenGL 显示黑屏。虽然此代码没有做任何非常有趣的事情,但通过创建这些类,您已经奠定了开始使用 OpenGL 绘制图形元素所需的基礎。

注意:您可能想知道为什么这些方法有一个 GL10 参数,而您正在使用 OpengGL ES 2.0 API。这些方法签名只是为了 2.0 API 重新使用,以使 Android 框架代码更简单。

如果您熟悉 OpenGL ES API,那么您现在应该能够在您的应用程序中设置 OpenGL ES 环境并开始绘制图形。但是,如果您需要更多帮助才能开始使用 OpenGL,请继续学习下一节课,获取更多提示。