1.4 创建Renderer类
现在要定义一个渲染器,以便我们开始清空屏幕。
让我们快速浏览一下渲染器接口定义的方法:
onSurfaceCreated(GL10 glUnused, EGLConfig config)
当Surface被创建的时候,GLSurfaceView会调用这个方法;这发生在应用程序第一次运行的时候,并且,当设备被唤醒或者用户从其他activity切换回来时,这个方法也可能会被调用。在实践中,这意味着,当应用程序运行时,本方法可能会被调用多次。
onSurfaceChanged(GL10 glUnused, int width, int height)
在Surface被创建以后,每次Surface尺寸变化时,这个方法都会被GLSurfaceView调用到。在横屏、竖屏来回切换的时候,Surface尺寸会发生变化。
onDrawFrame(GL10 glUnused)
当绘制一帧时,这个方法会被GLSurfaceView调用。在这个方法中,我们一定要绘制一些东西,即使只是清空屏幕;因为,在这个方法返回后,渲染缓冲区会被交换并显示在屏幕上,如果什么都没画,可能会看到糟糕的闪烁效果。
怎么会有一个未被使用的参数类型GL10呢?它是OpenGL ES 1.0的API(应用程序编程接口)遗留下来的;如果要编写使用OpenGL ES 1.0的渲染器,就要使用这个参数;但是,对于OpenGL ES 2.0,GLES20类提供了静态方法来存取。
在后台线程中渲染
GLSurfaceView会在一个单独的线程中调用渲染器的方法。默认情况下,GLSurfaceView会以显示设备的刷新频率不断地渲染,当然,它也可以配置为按请求渲染,只需要用
GlSurfaceView.RENDERMODE_WHEN_DIRTY作为参数调用GLSurfaceView.setRenderMode()即可。
既然Android的GLSurfaceView在后台线程中执行渲染,就必须要小心,只能在这个渲染线程中调用OpenGL,在Android主线程中使用UI(用户界面)相关的调用;两个线程之间的通信可以用如下方法:在主线程中的GLSurfaceView实例可以调用queueEvent()方法传递一个Runnable给后台渲染线程,渲染线程可以调用Activity的runOnUIThread()来传递事件(event)给主线程。
新建渲染器
在同一个包里创建一个各为FirstOpenGLProjectRender的新类,用来实现Renderer接口;为了创建这个新类,在包浏览器(package Explorer)里,鼠标右键单击“com.firstopenglproject.android”,接着选择“New→Class”;在弹出的“New Java Class”窗口中输入“FirstOpenGLProjectRenderer”作为名字,并单击“Finish”按钮。
我们会以下面的代码作为开始,并加入我们的第一个方法OnSurfaceCreated():
首先,在onSurfaceCreated()中调用glClearColor(1.0f, 0.0f, 0.0f, 0.0f)设置清空屏幕用的颜色;前三个参数分别对应红色、绿色和蓝色,最后的参数对应一个特殊的分量,称为阿尔法(alpha),它经常用来表示半透明度或透明度。通过把第一个分量设为1,其余设为0,我们把红色设置为最大强度,当屏幕被清空时,它就会显示红色。2.6节会更详细地讨论这个颜色模型。
下一步就是设置视口(viewport)尺寸了,让我们加入如下代码:
在onSurfaceChanged()方法中,调用glViewPort(0, 0, width, height)设置了视口尺寸,这就告诉了OpenGL可以用来渲染的surface的大小。
要用如下代码完成这个渲染器类:
在onDrawFame()中调用glClear(GL_COLOR_BUFFER_BIT)清空屏幕;这会擦除屏幕上的所有颜色,并用之前glClearColor()调用定义的颜色填充整个屏幕。
现在测试一下代码,看看会发生什么。按“Ctrl+F11”键运行这个程序。你会看到一个空白的红色屏幕,如图1-4所示。
尝试改变清空的颜色,然后再运行程序看看会发生什么!你应该看到屏幕上的颜色与代码的改动完全匹配。
如果你使用的是模拟器,且程序不工作,而你也检查过模拟器的配置选项“Use Host GPU”已经被勾选了,那就试试在glSurfaceView.setRenderer()调用之前加入glSurfaceView.setEGLConfigChooser(8,8,8,8,16,0)的调用。