OpenGL  ES 简介    

Android 3D 引擎采用的是OpenGL ES。OpenGL ES是一套为手持和嵌入式系统设计的3D引擎API,由Khronos公司维护。在PC领域,一直有两种标准的3D API进行竞争,OpenGL 和 DirectX。一般主流的游戏和显卡都支持这两种渲染方式,DirectX在Windows平台上有很大的优势,但是 OpenGL 具有更好的跨平台性。
由于嵌入式系统和PC相比,一般说来,CPU、内存等都比PC差很多,而且对能耗有着特殊的要求,许多嵌入式设备并没有浮点运算协处理器,针对嵌入式系统的以上特点,Khronos对标准的 OpenGL 系统进行了维护和改动,以期望满足嵌入式设备对3D绘图的要求。

Android系统使用 OpenGL 的标准接口来支持3D图形功能,android 3D 图形系统也分为 java 框架和本地代码两部分。本地代码主要实现的 OpenGL 接口的库,在 Java 框架层,javax.microedition.khronos.opengles 是 java 标准的 OpenGL 包,android.opengl包提供了 OpenGL 系统和 Android GUI 系统之间的联系。

OpenGL绘图

      从0开始,Android的OpenGL只是对OpenGL ES API的简单封装,Google的文档里没有提供函数的说明,可以去OpenGL ES的官网 查询。我使用的参考书是《Android应用开发揭秘》,其OpenGL基础部分基本上是抄的周炜的NeHe中文教程 ,只是做了一下对Android移植。这本书里的例子一个很别扭的地方是,他描述一个三角形的坐标时使用了IntBuffer,一个单位值是0x10000,但是OpenGL的函数使用的都是浮点数,跟这个0x10000完全不是一个量级的,很难理解。所以我该用了FloatBuffer,相应的glVertexPointer函数使用GL10.GL_FLOAT,这样整个坐标量度就能统一了。

一步一步实现自己的 Renderer 类



在 Android 中我们使用 GLSurfaceView 来显示 OpenGL 视图,该类位于 android.opengl 包里面。它提供了一个专门用于渲染3D 的接口 Renderer 。接下来我们就来一步步构建自己的 Renderer 类。



1、为 Renderer 类赶回命名空间


import android.opengl.GLSurfaceView.Renderer;


 



2、新建一个类来实现 Renderer 接口,代码如下:


public class ThreeDGl implements Renderer


{


}


复制代码


 



3、如上代码所写,程序实现了 Renderer 类,则必须重写以下方法


public void onDrawFrame(GL10 gl)


{


}


public void onSurfaceChanged(GL10 gl, int width, int height)


{}


public void onSurfaceCreated(GL10 gl, EGLConfig config)


{}


复制代码


 



4、当窗口被创建时需要调用 onSurfaceCreate ,我们可以在这里对 OpenGL 做一些初始化工作,例如:



        


// 启用阴影平滑 

         gl.glShadeModel(GL10.GL_SMOOTH); 

          

         // 黑色背景 

         gl.glClearColor(0, 0, 0, 0); 

          

         // 设置深度缓存 

         gl.glClearDepthf(1.0f);                             

         // 启用深度测试 

         gl.glEnable(GL10.GL_DEPTH_TEST);                         

         // 所作深度测试的类型 

         gl.glDepthFunc(GL10.GL_LEQUAL);                             

          

         // 告诉系统对透视进行修正 

         gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST); 

 复制代码 

   


 glHint 用于告诉 OpenGL 我们希望进行最好的透视修正,这会轻微地影响性能,但会使得透视图更好看。 

 glClearColor 设置清除屏幕时所用的颜色,色彩值的范围从 0.0f~1.0f 大小从暗到这的过程。 

 glShadeModel 用于启用阴影平滑度。阴影平滑通过多边形精细地混合色彩,并对外部光进行平滑。 

 glDepthFunc 为将深度缓存设想为屏幕后面的层,它不断地对物体进入屏幕内部的深度进行跟踪。 

 glEnable 启用深度测试。 

 5、当窗口大小发生改变时系统将调用 onSurfaceChange 方法,可以在该方法中设置 OpenGL 场景大小 ,代码如下: 

 //设置OpenGL场景的大小 

 gl.glViewport(0, 0, width, height); 

 复制代码 

   


 6、场景画出来了,接下来我们就要实现场景里面的内容,比如:设置它的透视图,让它有种越远的东西看起来越小的感觉,代码如下: 


 //设置投影矩阵  
托福代攷  

         gl.glMatrixMode(GL10.GL_PROJECTION); 

         //重置投影矩阵 

         gl.glLoadIdentity(); 

         // 设置视口的大小 

         gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10); 

         // 选择模型观察矩阵 

         gl.glMatrixMode(GL10.GL_MODELVIEW);     

         // 重置模型观察矩阵 

         gl.glLoadIdentity();

gl.glMatrixMode(GL10.GL_PROJECTION); 指明接下来的代码将影响 projection matrix (投影矩阵),投影矩阵负责为场景增加透视度。


 gl.glLoadIdentity(); 此方法相当于我们手机的重置功能,它将所选择的矩阵状态恢复成原始状态,调用  glLoadIdentity(); 之后为场景设置透视图。


gl.glMatrixMode(GL10.GL_MODELVIEW);   指明任何新的变换将会影响 modelview matrix (模型观察矩阵)。


gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10); 此方法,前面4个参数用于确定窗口的大小,而后面两个参数分别是在场景中所能绘制深度的起点和终点。


7、了解了上面两个重写方法的作用和功能之后,第三个方法 onDrawFrame 从字面上理解就知道此方法做绘制图操作的。嗯,没错。在绘图之前,需要将屏幕清除成前面所指定的颜色,清除尝试缓存并且重置场景,然后就可以绘图了, 代码如下:


// 清除屏幕和深度缓存


gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);


// 重置当前的模型观察矩阵


gl.glLoadIdentity();



 



8、Renderer 类在实现了上面的三个重写之后,在程序入口中只需要调用



Renderer render=new ThreeDGl(this); 

     /** Called when the activity is first created. */ 

     @Override 

     public void onCreate(Bundle savedInstanceState) { 

         super.onCreate(savedInstanceState); 

         GLSurfaceView gview=new GLSurfaceView(this); 

         gview.setRenderer(render); 

         setContentView(gview); 

     }



即可将我们绘制的图形显示出来。