【Android API指南】动画和图像(5) - OpenGL
Android包含了Open Graphics Library(OpenGL)支持高性能的2D和3D图像。特别是OpenGL ES API。OpenGL是一个跨平台图像API,为3D图像处理指定了标准的软件接口。OpenGL ES是为嵌入式设备提供的标准。Android1.0就开始支持OpenGL ES 1.0和1.1,从Android2.2开始支持OpenGL ES 2.0 API规格。
提示:Android框架提供的API类似J2ME JSR239 OpenGL ES API,但是不完全相同,要注意他们的区别。
基础Android通过框架API和NDK支持OpenGL。这里主要讲框架接口。
Android提供了两个基本类用来使用OpenGL ES API创建和操作图像:GLSurfaceView和GLSurfaceView.Renderer。知道怎么实现这两个类是首要目标。
GLSurfaceView
类似SurfaceView的View类,可以使用OpenGL API绘制和操作对象。你可以使用这个类创建一个实例,然后添加你的Renderer进去。如果你想捕捉屏幕触摸事件,你需要继承GLSurfaceView类,实现触摸监听。GLSurfaceView.Renderer
这个接口定义了绘制图像的方法。你需要用一个专门的类实现这个接口,然后使用GLSurfaceView.setRenderer()添加到你的GLSurfaceView实例中。OpenGL 包使用GLSurfaceView和GLSurfaceView.Renderer创建了视图容器后,你要开始调用下面这些OpenGL API:OpenGL ES 1.0/1.1 API 包
GLSurfaceView.Renderer接口需要实现下面这些方法:onSurfaceCreated():系统在创建GLSurfaceView时执行一次,一般用来设置OpenGL环境参数或者初始化OpenGL图像对象。onDrawFrame():每次重绘GLSurfaceView实现会执行,这个方法是绘制图像对象的主要执行点。onSurfaceChanged():当GLSurfaceView几何改变时被调用,包括它的尺寸或者屏幕方向。
<!-- Tell the system this app requires OpenGL ES 2.0. --> <uses-feature android:glEsVersion="0x00020000" android:required="true" />这样Google Play就会限制那些不支持2.0的设备安装你的程序。纹理压缩需求 - 如果程序使用纹理压缩格式,你需要使用<supports-gl-texture>声明程序支持的格式。
public void onSurfaceChanged(GL10 gl, int width, int height) { gl.glViewport(0, 0, width, height); // make adjustments for screen ratio float ratio = (float) width / height; gl.glMatrixMode(GL10.GL_PROJECTION); // set matrix to projection mode gl.glLoadIdentity(); // reset the matrix to its default state gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7); // apply the projection matrix }2. 摄像转换矩阵 - 一旦你已经使用投射矩阵调整了坐标系统,你也必须使用一个摄像视角。下面的例子展示了如何修改onDrawFrame()方法实现应用一个模式视图,然后使用GLU.gluLookAt()功能创建一个视角转换,类似一个拍摄点。
public void onDrawFrame(GL10 gl) { ... // Set GL_MODELVIEW transformation mode gl.glMatrixMode(GL10.GL_MODELVIEW); gl.glLoadIdentity(); // reset the matrix to its default state // When using GL_MODELVIEW, you must set the camera view GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f); ... }OpenGL ES 2.0中的投射和摄像视角在ES2.0API中,先要添加一个矩阵成员到图像对象的顶点着色器中。
private final String vertexShaderCode = // This matrix member variable provides a hook to manipulate // the coordinates of objects that use this vertex shader "uniform mat4 uMVPMatrix; \n" + "attribute vec4 vPosition; \n" + "void main(){ \n" + // the matrix must be included as part of gl_Position " gl_Position = uMVPMatrix * vPosition; \n" + "} \n";2. 访问着色器矩阵 - 在顶点着色器中创建了一个钩子后,我们可以访问顶点着色器中的矩阵变量了。
public void onSurfaceCreated(GL10 unused, EGLConfig config) { ... muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix"); ... }3. 创建投射和摄像视角矩阵。
public void onSurfaceCreated(GL10 unused, EGLConfig config) { ... // Create a camera view matrix Matrix.setLookAtM(mVMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f); } public void onSurfaceChanged(GL10 unused, int width, int height) { GLES20.glViewport(0, 0, width, height); float ratio = (float) width / height; // create a projection matrix from device screen geometry Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7); }4. 应用投射和摄像视角矩阵
public void onDrawFrame(GL10 unused) { ... // Combine the projection and camera view matrices Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0); // Apply the combined projection and camera view transformations GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0); // Draw objects ... }
// enable face culling featuregl.glEnable(GL10.GL_CULL_FACE);// specify which faces to not drawgl.glCullFace(GL10.GL_BACK);提示:可以设置顺时针为正面,但是需要更多代码,也会混淆给你提供帮助的开发者,所以不要这样做。
String extensions = javax.microedition.khronos.opengles.GL10.glGetString(GL10.GL_EXTENSIONS);警告:不同的设备得到的结果不一样,你需要在多种设备上运行,以确认一直普遍支持的格式。