Android 中OpenGL的使用
android为openGLES支持提供了GLSurfaceView组件,这个组件用于显示3D图形。GLSufaceView本身并不提供绘制3D图形的功能,而是由GLSurfaceView.Renderer来完成了SurfaceView中3D图形的绘制。
归纳起来,在android中使用openGlES需要三个步骤:
1,创建GLSurfaceView组件,使用activity来显示GlSufaceView组件
2.为GLSufaceView组件创建GLSufaceView.Renderer实例,实现GLSurfaceView.Renderer类时需要实现接口里的三个方法。
(1)abstractvoidonDrawFrame(GL10gl):Renderer对象调用该方法绘制GLSurfaceView的当前帧。
(2)abstractvoidonSurfaceChanged(GL10gl,intwidth,intheight):当GLSurfaceView的大小改变时回调该方法。
(3)abstractvoidonSufaceCreated(GL10gl,EGLConfigconfig):当GLSurfaceView被创建时回调该方法。
3.调用GLSurfaceView组件的setRender()方法指定Renderer对象。该Renderer对象完成GLSurfaceView里3D图形的绘制。
从上面的介绍不难看出,实际上绘制3D图像的难点不是如何使用GLSurface组件,而是如何实现Renderer类。是想Renderer类时需要三个方法。这三个方法都有一个GL10形参,他就代表了GLOpenES的“绘制画笔”,读者可以把它想象成Swing2D绘图中的Graphics,也就是想象成android2D绘图中的Canvas组件-当我们希望Renderer绘制3D图像时,实际上是调用GL10的方法来进行绘制的。
当SurfaceView被创建时,系统会回调Rnderer对象的onSurfaceCreated()方法,该方法可以对OpenGLES执行一些无须任何改变的初始化,例如如下代码:
@Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { //关闭抗抖动 gl.glDisable(GL10.GL_DITHER); //设置系统对透视进行修正 gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST); gl.glClearColor(0, 0, 0, 0); //设置阴影平滑模式 gl.glShadeModel(GL10.GL_SMOOTH); //启用深度测试 gl.glEnable(GL10.GL_DEPTH_TEST); //设置深度测试的类型 gl.glDepthFunc(GL10.GL_LEQUAL); }
Gl10就是OpenGLES的绘图接口,虽然这里看到的是一个GL10,但实际上它也是GL11的实例,读者可通过(glinstandeofGL11)判断他是否为GL11接口的实例。
上面的方法中用到了一些初始化方法,关于这些方法的说明如下:
(1)glDisable(intcap):该方法用于禁用OpenGLES某个方面的特性。该方法中第一行代码用于关闭抗抖动,这样可以提高性能。
(2)glHint(inttarget,intmode):该方法用于对OpenGLES某方面进行校正。
(3)clearColor(floatred,floatgreen,floatalpha):该方法设置OpenGlES"清屏"所用的颜色,四个参数分别设置红、绿、蓝、透明值:0为最小值,1为最大值。例如gl.glClearColor(0,0,0,0);就是用黑色“清屏”。
(4)glShadeModel(intmode):该方法用于设置OpenGlES的阴影模式。此处设置为平滑模式。
(5)glEnable(intcap):该方法与glDisable(intcap)方法相对,用于启用OpenGLES某些特性。此处用于启动OpenGLES的深度测试。所谓深度测试。就是让OpenGLES负责跟踪每个物体在Z轴的深度,这样就可避免后面的物体遮挡前面的物体。
当SurfaceView组件的大小发生改变时,系统会回调Renderer对象的onSurfaceChanged()方法,因此该方法通常用于初始化3D场景,例如如下初始化代码:
@Override public void onSurfaceChanged(GL10 gl, int width, int height) { //设置3D视窗的大小及位置 gl.glViewport(0, 0, width, height); //将当前矩阵模式设置为投影矩阵 gl.glMatrixMode(GL10.GL_PROJECTION); //初始化单位矩阵 gl.glLoadIdentity(); //计算透视视窗的高度、高度比 float ratio = (float)width / height; //调用此方法设置透视窗视窗的空间大小 gl.glFrustumf(-ratio, ratio, -1, 0, 1, 10); }
上面的方法中用到了GL10的一些初始化方法,关于这些方法的说明如下。
(1)glViewport(intx,inty,intwidth,intheight):设置3D视窗的位置与大小,其中前两个参数指定该视窗的位置,后面两个参数指定该视窗的宽、高。
(2)glMatrixMode(intmode):设置视窗的矩阵模型,通常可接受GL10.GL_PROJECTION、GL10.GL_MODELVIEW两个常量值。
当调用gl.glMatrixMode(GL10.GL_PROJECTION);代码后,指定将屏幕设为透视图(要想看到逼真的三维物体,这是必要的),这意味着越远的东西看起来越小;当调用gl.glMatrixMode(GL10.GL_MODELVIEW);代码后,即将当前矩阵模式设为模型视图矩阵,这意味着任何新的变换都会影响该矩阵的所有物体。
(3)glLoaddentity():相当于reset()方法,用于初始化单位矩阵。
(4)glFrustumfglFrustumf(floatleft,floatright,floatbottom,floattop,floatzNear,floatzFar):用于设置透视投影的空间大小,前面两个参数用于设置X轴上的最小坐标值、最大坐标值,中间的两个参数用于设置Y轴的最小坐标值、最大坐标值;后面两个参数用于设置Z轴上所能绘制的场景的深度的最小值、最大值。
例如我们调用如下代码:
gl.glFrustumf(-0.8f, 0.8f, -1f, 1f, 1f, 10f);
这意味着如果有一个二维矩形,它的四个顶点的坐标分别为:(-0.8,1)、(0.8,1)、(0.8,-1)、(-0.8,-1),这个矩形将会占满整个视窗。
提示:前面已经指出:三维坐标系统与二维坐标系统并不相同,二维坐标系统上的坐标值通常就直接使用系统的像素数量;但三维坐标系统的坐标值则取决于glFrustumf()方法的设置,当我们调用gl.glFrustumf(-0.8f,0.8f,-1f,1f,1f,10f);方法时,意味着该三维坐标系统的最左边的坐标值为-0.8,最右边的坐标值为0.8;Y轴最上面的坐标值为1.0,最下面的坐标值为-1.0
GlSurfaceView上的所有3D图形都是由Renderer的onDrawFrame(GL10gl)方法绘制出来的,重写该方法时就要把所有的3D图形都绘制出来,该方法通常如下形式开始:
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); ...
接下来在onDrawFrame方法中就可以调用GL10的方法开始绘制了。
绘制平面上的多边形
调用GL10图形绘制2D图形的步骤如下:
(1)调用GL10的glEnableClientState(GL10.GL_VERTEX_ARRAY);方法启用顶点坐标数组。
(2)调用GL10的glEnableClientState(GL10.GL_COLOR_ARRAY);方法启用顶点颜色数组。
(3)调用GL10的glVertexPointer(intsize,inttype,intstride,Bufferpointer)方法
设置顶点的位置数据。这个方法中pointer参数用于指定顶点坐标值,但这里并未使用三维数组来指定每个顶点X、Y、Z坐标值,point依然是一个一维数组,也就是该数组将会包含3N个数值,每三个值指定一个顶点的X、Y、Z坐标值。第一个参数size指定多少个元素指定一个顶点位置,该size参数通常总是3;type参数指定顶点值的类型,如果顶点坐标值为float类型,则指定为GL10.GL_FLOAT;如果顶点坐标值为整数,则指定为GL10.GL_FIXED.
(4)调用GL10的glColorPoint(intsize,inttype,intstride,Bufferpointer)方法设置顶点的颜色数据。point依然是一维数组,每四个值指定一个顶点的红、绿、蓝、透明度的颜色值。第一个参数size指定多少个元素指定一个顶点位置,该size参数通常总是4,type参数指定顶点坐标值的类型,如果顶点坐标值为float类型,则指定为GL10.GL_FLOAT;如果顶点坐标值为整数,则指定为GL10.GL_FIXED.
(5),调用GL10的glDrawArrays(intmode,intfirst,intcount)方法绘制平面,该方法第一个参数用于指定绘制图形的类型,第二个参数指定从哪个顶点开始绘制,第三个参数指定总共绘制的顶点数量。
(6),绘制完成后,调用GL10的glFinish()方法结束绘制;并调用glDisableClientState(int)方法来停用顶点坐标数据、顶点颜色数据。