Android 中OpenGL的使用

android为openGL ES支持提供了GLSurfaceView组件, 这个组件用于显示3D图形。GLSufaceView本身并不提供绘制3D图形的功能,而是由GLSurfaceView.Renderer来完成了SurfaceView中3D图形的绘制。
归纳起来,在android中使用openGl ES需要三个步骤:

1,创建GLSurfaceView组件,使用activity来显示GlSufaceView组件
2. 为GLSufaceView组件创建GLSufaceView.Renderer实例,实现GLSurfaceView.Renderer类时需要实现接口里的三个方法。
    (1) abstract void onDrawFrame(GL10 gl): Renderer对象调用该方法绘制GLSurfaceView的当前帧。
    (2)abstract void onSurfaceChanged(GL10 gl, int width, int height):当GLSurfaceView的大小改变时回调该方法。
    (3)abstract void onSufaceCreated(GL10 gl, EGLConfig config):当GLSurfaceView被创建时回调该方法。
3.调用GLSurfaceView组件的setRender()方法指定Renderer对象。该Renderer对象完成GLSurfaceView里3D图形的绘制。


从上面的介绍不难看出,实际上绘制3D图像的难点不是如何使用GLSurface组件,而是如何实现Renderer类。是想Renderer类时需要三个方法。这三个方法都有一个GL10形参,他就代表了GLOpen ES的“绘制画笔”, 读者可以把它想象成Swing 2D绘图中的Graphics,也就是想象成android2D绘图中的Canvas组件-当我们希望Renderer绘制3D图像时,实际上是调用GL10的方法来进行绘制的。
  当SurfaceView被创建时,系统会回调Rnderer对象的onSurfaceCreated()方法,该方法可以对OpenGL ES执行一些无须任何改变的初始化,例如如下代码:
  @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就是OpenGL ES的绘图接口,虽然这里看到的是一个GL10,但实际上它也是GL11的实例,读者可通过(gl instandeof GL11)判断他是否为GL11接口的实例。
上面的方法中用到了一些初始化方法,关于这些方法的说明如下:
(1)glDisable(int cap) : 该方法用于禁用OpenGL ES某个方面的特性。 该方法中第一行代码用于关闭抗抖动,这样可以提高性能。
(2)glHint(int target, int mode):该方法用于对OpenGL ES某方面进行校正。
(3)clearColor(float red, float green, float alpha):该方法设置OpenGl ES"清屏"所用的颜色,四个参数分别设置红、绿、蓝、透明值:0为最小值,1为最大值。例如gl.glClearColor(0, 0, 0, 0);就是用黑色“清屏”。
(4) glShadeModel(int mode): 该方法用于设置OpenGl ES的阴影模式。此处设置为平滑模式。
  (5) glEnable(int cap): 该方法与glDisable(int cap)方法相对, 用于启用OpenGL ES某些特性。此处用于启动OpenGL ES的深度测试。所谓深度测试。就是让OpenGL ES负责跟踪每个物体在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(int x, int y, int width, int height): 设置3D视窗的位置与大小,其中前两个参数指定该视窗的位置,后面两个参数指定该视窗的宽、高。
(2) glMatrixMode(int mode): 设置视窗的矩阵模型,通常可接受GL10.GL_PROJECTION、 GL10.GL_MODELVIEW两个常量值。
当调用gl.glMatrixMode(GL10.GL_PROJECTION);代码后,指定将屏幕设为透视图(要想看到逼真的三维物体,这是必要的), 这意味着越远的东西看起来越小;当调用gl.glMatrixMode(GL10.GL_MODELVIEW);代码后,即将当前矩阵模式设为模型视图矩阵,这意味着任何新的变换都会影响该矩阵的所有物体。
  (3)glLoaddentity():相当于reset()方法,用于初始化单位矩阵。
  (4)glFrustumfglFrustumf(float left, float right, float bottom, float top, float zNear, float zFar): 用于设置透视投影的空间大小,前面两个参数用于设置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(GL10 gl)方法绘制出来的,重写该方法时就要把所有的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(int size, int type, int stride, Buffer pointer)方法

设置顶点的位置数据。这个方法中pointer参数用于指定顶点坐标值,但这里并未使用三维数组来指定每个顶点X、Y、Z坐标值,point依然是一个一维数组,也就是该数组将会包含3N个数值,每三个值指定一个顶点的X、Y、Z坐标值。 第一个参数size指定多少个元素指定一个顶点位置,该size参数通常总是3;type参数指定顶点值的类型,如果顶点坐标值为float类型,则指定为GL10.GL_FLOAT;如果顶点坐标值为整数,则指定为GL10.GL_FIXED.
(4)调用GL10的glColorPoint(int size, int type, int stride, Buffer pointer)方法设置顶点的颜色数据。 point依然是一维数组,每四个值指定一个顶点的红、绿、蓝、透明度的颜色值。第一个参数size指定多少个元素指定一个顶点位置,该size参数通常总是4, type参数指定顶点坐标值的类型,如果顶点坐标值为float类型,则指定为GL10.GL_FLOAT;如果顶点坐标值为整数,则指定为GL10.GL_FIXED.
(5),调用GL10的glDrawArrays(int mode, int first, int count)方法绘制平面,该方法第一个参数用于指定绘制图形的类型,第二个参数指定从哪个顶点开始绘制,第三个参数指定总共绘制的顶点数量。
(6),绘制完成后,调用GL10的glFinish()方法结束绘制;并调用glDisableClientState(int)方法来停用顶点坐标数据、顶点颜色数据。

猜你喜欢

转载自fuchangle.iteye.com/blog/1888962