OpenGL ES
Android包含高性能2D和3D图形开放图形库(OpenGL®的)。详细而言,OpenGL ES的API支持。 OpenGL是一个跨平台的图形API。用于指定的3D图形处理硬件标准的软件接口。 ES是用于嵌入式设备的OpenGL规范的味道。 Android支持OpenGL ES的API的几个版本号:
的OpenGL ES 1.0和1.1 - 本API规范是由Android 1.0及更高版本号支持。
OpenGL ES 2.0的 - 这个API规范由Android 2.2的(API 8级)或更高版本号支持。
的OpenGL ES 3.0 - 本API规范是由Android 4.3(API级别18)和更高的支持。
的OpenGL ES 3.1 - 这个API规范由是Android 5.0(API级别21)和更高的支持。
注意:在设备上的OpenGL ES 3.0 API的支持,须要由设备制造商提供了这个图形管线的实现。
执行Android 4.3或更高版本号的设备可能不支持的OpenGL ES 3.0 API。
有关检查在执行时支持哪些版本号的OpenGL ES的信息,请參阅检查OpenGL ES版本号。
注意:由Android框架所提供的特定的API是类似于J2ME JSR239 OpenGL ES的API。可是是不同样的。假设您熟悉J2ME JSR239规范。对变化的警报。
基础
Android的支持OpenGL既通过其框架API和原生开发套件(NDK)。本主题重点介绍了Android框架接口。
有关NDK的很多其它信息,请參阅的Android NDK。
有两个基础班在Android框架,让您创建和操纵符合OpenGL ES API的图形:GLSurfaceView和GLSurfaceView.Renderer。假设你的目标是使用OpenGL在你的Android应用程序,了解怎样实现一个活动,这些类应该是你的第一个目标。
GLSurfaceView
这个类是一个视图,你能够绘制和操作使用OpenGL API调用的对象。并在功能上SurfaceView类似。
您能够通过创建GLSurfaceView的实例,并添加你的渲染它使用这个类。可是,假设你想捕捉触摸屏事件,您应该扩展GLSurfaceView类来实现触摸监听器。如图OpenGL的训练课中,响应触摸事件。
GLSurfaceView.Renderer
此接口定义在GLSurfaceView绘制图形所须要的方法。
你必须提供这个接口作为一个单独的类的实现,并使用GLSurfaceView.setRenderer其附加到您GLSurfaceView实例()。
该GLSurfaceView.Renderer接口,您须要实现下面方法:
onSurfaceCreated():创建GLSurfaceView时,系统调用这种方法一次。使用此方法来运行仅仅须要发生一次的操作。如设置OpenGL的环境參数或初始化的OpenGL图形对象。
onDrawFrame()系统调用的GLSurfaceView每一个重绘此方法。使用此方法作为主要运行点绘制(并又一次绘制)图形对象。
onSurfaceChanged()系统调用此方法时。GLSurfaceView几何变化,包含在GLSurfaceView的大小或设备屏幕的方向变化。比如。当设备从纵向变为横向系统调用此方法。使用此方法能够在GLSurfaceView容器的变化做出反应。
OpenGL ES的包
一旦你建立了使用GLSurfaceView和GLSurfaceView.Renderer为OpenGL ES的容器视图,您能够開始使用以下的类中调用OpenGL的API:
的OpenGL ES 1.0 / 1.1 API包
android.opengl - 这个包提供了一个静态的界面比javax.microedition.khronos封装接口的OpenGL ES 1.0 / 1.1类和更好的性能。
GLES10
GLES10Ext
GLES11
GLES11Ext
javax.microedition.khronos.opengles - 此软件包提供了标准实施的OpenGL ES 1.0 / 1.1。
GL10
GL10Ext
GL11
GL11Ext
GL11ExtensionPack
的OpenGL ES 2.0 API类
android.opengl.GLES20 - 此软件包提供接口的OpenGL ES 2.0,并開始提供Android 2.2的(API级别8)。
的OpenGL ES 3.0 / 3.1 API包
android.opengl - 此软件包提供了接口的OpenGL ES 3.0 / 3.1类。
3.0版開始提供的Android 4.3(API等级18)。 3.1版開始提供的是Android 5.0(API等级21)。
GLES30
GLES31
GLES31Ext(Android的扩展包)
假设你想開始建设有OpenGL ES的应用程序向右走,遵循的OpenGL ES类显示图形。
声明要求的OpenGL
假设应用程序使用的OpenGL功能,这些功能并不是适用于全部的设备,你必须在你的AndroidManifest.xml文件这些要求。下面是最常见的OpenGL清单的声明:
OpenGL ES版本号的要求 - 假设你的应用须要OpenGL ES的特定版本号。您必须通过例如以下图所看到的加入下面设置你的清单声明要求。
对于OpenGL ES 2.0的:
<!-- Tell the system this app requires OpenGL ES 2.0. --> <uses-feature android:glEsVersion="0x00020000" android:required="true" />加入此声明将使谷歌播放从被安装在不支持OpenGL ES2.0标准的设备将应用程序限制。
假设应用程序是专为支持的OpenGL ES3.0的设备,你也能够在你的清单中指定的:
对于OpenGL ES的3.0:
<!-- Tell the system this app requires OpenGL ES 3.0. --> <uses-feature android:glEsVersion="0x00030000" android:required="true" />For OpenGL ES 3.1:
<!-- Tell the system this app requires OpenGL ES 3.1. --> <uses-feature android:glEsVersion="0x00030001" android:required="true" />注:的OpenGL ES API 3.X与2.0 API,这意味着你能够与你的应用程序中实现的OpenGL ES的更灵活的向后兼容。通过声明的OpenGL ES 2.0 API作为您清单的要求,您能够使用该API版本号作为默认,检查在执行时API 3.X的可用性,然后假设设备支持使用OpenGL ES 3.x的功能它。有关检查设备所支持的OpenGL ES版本号的很多其它信息,请參阅检查OpenGL ES版本号。
纹理压缩的要求 - 假设应用程序使用的纹理压缩格式,您必须使用<支持-GL纹理>声明应用程序支持的格式,在你的清单文件。有关可用纹理压缩格式的很多其它信息,请參阅纹理压缩支持。
在清单中声明纹理压缩需求隐藏您的用户不支持您的声明压缩类型的至少一个器件中的应用。
有关谷歌Play怎样过滤功能纹理压缩的很多其它信息。请參阅谷歌Play和<支撑-GL纹理>文件的纹理压缩过滤部分。
贴图坐标绘制的对象
当中一个在Android设备上显示图形的基本问题是,他们的屏幕能够在大小和形状各不同样。 OpenGL的承担方,统一坐标系统,默认情况下。兴致勃勃地绘制这些坐标到您的典型的非方形屏幕。就好像它是完美的正方形。
图1.默认OpenGL的坐标系(左)映射到一个典型Android装置画面(右)。
上面的图显示了统一协调如果左側一个OpenGL框架体系,以及怎样将这些坐标实际上映射到一个典型的设备屏幕在右側横向。为了解决问题,你能够申请OpenGL的投影模式和相机意见,使您的图形对象具有在不论什么显示器上以正确的比例转换坐标。
为了运用投影和相机视图,您创建一个投影矩阵,摄像机视图矩阵。并将其应用到OpenGL渲染管线。
使他们正确地映射到Android设备屏幕的投影矩阵又一次计算图形的坐标。摄像机视图矩阵创建从一个特定的眼睛位置渲染对象的变换。
在OpenGL ES 1.0投影和相机视图
在ES 1.0 API,通过创建每一个矩阵,然后将其加入到OpenGL的环境中应用投影和相机视图。
投影矩阵 - 为了又一次计算对象创建使用该设备屏幕的几何形状的投影矩阵坐标。以便他们绘制的正确比例。以下的演示样例代码演示了怎样改动GLSurfaceView.Renderer实施onSurfaceChanged()方法来创建基于屏幕的宽高比的投影矩阵。并将其应用到OpenGL渲染环境。
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 }相机变换矩阵 - 一旦你使用调整投影矩阵坐标系统,您还必须应用摄影机视图。以下的演示样例代码显示了怎样改动GLSurfaceView.Renderer实施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.0和3.0的API,则通过首先加入矩阵部件图形对象的顶点着色器应用于投影和相机视图。有了这个矩阵成员加入,你就能够生成和应用投影和镜头视角矩阵来你的对象。
加入矩阵顶点着色器 - 创建视图投影矩阵的变量,并把它作为着色器的位置的乘数。在以下的样例中顶点着色器代码中,包括的MVP矩阵构件同意你投影和相机的观看矩阵应用到使用此着色的物体的坐标。
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; " + "attribute vec4 vPosition; " + "void main(){ " + // The matrix must be included as part of gl_Position // Note that the uMVPMatrix factor *must be first* in order // for the matrix multiplication product to be correct. " gl_Position = uMVPMatrix * vPosition; " + "} ";注:上面的样例定义了一个变换矩阵成员在当中应用组合投影矩阵和摄像机视图矩阵顶点着色器。
依据您的应用需求。您可能要定义你的顶点着色器单独的投影矩阵和摄像机观察矩阵的成员。以便能够独立改变它们。
訪问着色器矩阵 - 在你的顶点着色器创建一个钩子应用投影和摄像头视图后,你就能够訪问该变量应用投影和摄像头观看矩阵。
以下的代码演示了怎样改动GLSurfaceView.Renderer实施onSurfaceCreated()方法来訪问在上面的顶点着色器中定义的矩阵变量。
public void onSurfaceCreated(GL10 unused, EGLConfig config) { ... muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix"); ... }创建投影和相机的观看矩阵 - 生成的投影和观察矩阵要应用的图形对象。以下的演示样例代码显示了怎样改动GLSurfaceView.Renderer实施onSurfaceCreated()和onSurfaceChanged()方法来创建摄像机视图矩阵,并依据设备的屏幕高宽比的投影矩阵。
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); }应用投影和镜头视角矩阵 - 要应用投影和相机视图变换,乘矩阵一起。然后将其设置到顶点着色器。
以下的演示样例代码显示了怎样改动GLSurfaceView.Renderer实施onDrawFrame()方法,在上面的代码创建的投影矩阵和摄像机视图结合起来。然后将其应用于通过的OpenGL渲染图形对象。
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 ... }有关怎样运用投影和相机视图与OpenGL ES 2.0的一个完整的演示样例。请參阅使用OpenGL ES的类显示图形。
外形面和绕线
在OpenGL,形状的面是由三个或很多其它个三维空间中定义的表面。
一组三个或很多其它个三维点(称为在OpenGL顶点)具有一个前表面和背面。你怎么知道它的脸前,这是回来了? 好问题。
答案与缠绕。或者。您在当中定义形状的点的方向去做。
图1.插图换算成逆时针顺序绘制坐标列表。
在本例中,三角形的点中,使得它们在反时针方向绘制的顺序进行定义。在这些坐标被绘制的顺序定义了形状的卷绕方向。默认情况下。在OpenGL。这是逆时针方向绘制面对的是前脸。在图1所看到的的三角形被定义。以便你正在寻找的形状的前表面(由OpenGL作为解释),而还有一側是背面。
为什么非常重要知道哪一个形状的脸是前面?答案与OpenGL的一个经常使用的功能。叫做脸扑杀做。
面剔除是用于OpenGL的环境。它同意渲染流水线忽略(未计算或绘制)的形状的背面。节省了时间。存储器和处理周期一个选项:
// enable face culling feature gl.glEnable(GL10.GL_CULL_FACE); // specify which faces to not draw gl.glCullFace(GL10.GL_BACK);假设您尝试使用面部特征扑杀不知道。你的形状,两側都是正面和背面,你的OpenGL图形要看看有点薄。或可能显示不出来的。所以,总是定义一个逆时针绘制顺序你的OpenGL图形的坐标。
注意:您能够设置一个OpenGL环境治疗顺时针脸的前脸,但这样做须要很多其它的代码。并有可能当你问他们帮忙来迷惑经验丰富的开发者的OpenGL。
所以。不要做。
OpenGL的版本号和设备兼容性
OpenGL ES的1.0和1.1 API规范因为Android 1.0已经支持。採用Android 2.2(API 8级)開始。该框架支持的OpenGL ES 2.0 API规范。
OpenGL ES 2.0的是大多数Android设备的支持。推荐用于新的应用程序正在使用OpenGL开发的。的OpenGL ES 3.0的支持与Android 4.3(API级别18)和更高,在提供OpenGL ES的3.0 API的实现设备。有关支持OpenGL ES的特定版本号的Android供电设备的相对数量的信息。请參阅OpenGL
ES版本号仪表板。
图形编程的OpenGL ES 1.0 / 1.1 API比使用2.0及更高版本号显著不同。 API的1.x的版本号有更方便的方法和固定图形管线。而的OpenGL ES 2.0和3.0 API提供了通过利用OpenGL着色器流水线的更直接的控制。
您应该慎重考虑显卡的要求并选择最适合您的应用程序API版本号。欲了解很多其它信息,请參阅选择一个OpenGL API版本号。
OpenGL ES的3.0 API提供了额外的功能,比2.0 API的性能更好。也向后兼容。
这意味着你可能会写你的应用程序针对的OpenGL ES 2.0和条件包括的OpenGL ES 3.0图形功能,假设他们都可用。有关检查为3.0 API的可用性的具体信息,请參阅检查OpenGL ES版本号
纹理压缩支持
纹理压缩能够通过降低存储需求的同一时候更有效地利用内存带宽添加显著OpenGL应用程序的性能。
Android框架提供了ETC1压缩格式作为标准功能,包含ETC1Util有用工具类和etc1tool压缩工具(位于Android SDK中的<SDK> /工具/)的支持。对于使用纹理压缩一个Android应用程序的演示样例,请參阅Android SDK中的CompressedTextureActivity代码演示样例(<SDK> /样本/ <版本号> / ApiDemos / src文件夹/ COM /样例/安卓/的API
/图形/)。
注意:ETC1格式是由大多数Android设备的支持。但它不能保证是可用的。要检查是否支持设备上的ETC1格式,调用ETC1Util.isETC1Supported()方法。
注:ETC1纹理压缩格式不支持的纹理与透明度(alpha通道)。假设应用程序须要使用透明纹理,您应该调查在目标设备上可用的其它的纹理压缩格式。
该ETC2 / EAC纹理压缩格式,保证使用的OpenGL ES 3.0 API时可用。这样的纹理格式提供良好的压缩比与高视觉质量和格式还支持透明度(Alpha通道)。
除了ETC格式,Android设备都依据自己的GPU芯片和OpenGL实现纹理压缩多样的支持。您应该调查你的目标来确定应用程序应该支持什么样的压缩类型的设备上的纹理压缩的支持。
为了确定哪些纹理格式都支持特定设备上,必须查询设备和审查OpenGL扩展名。当中确定哪些纹理压缩格式(和其它的OpenGL功能)的设备支持。
一些经常使用支持的纹理压缩格式例如以下:
ATITC(ATC) - ATI纹理压缩(ATITC或ATC)可在多种设备。并支持RGB纹理使用和不使用alpha通道固定利率压缩。这样的格式能够通过几种OpenGL扩展名,比如表示:
GL_AMD_compressed_ATC_texture
GL_ATI_texture_compression_atitc
PVRTC - PowerVR的纹理压缩(PVRTC)可在各种设备,并支持2位和每像素4位的纹理具有或不具有alpha通道。
这样的格式是由下面OpenGL扩展名来表示:
GL_IMG_texture_compression_pvrtc
S3TC(DXTn / DXTC) - S3纹理压缩(S3TC)有几个格式变化(DXT1到DXT5)和不太广泛使用。该格式支持RGB纹理与4位字母或8位Alpha通道。这样的格式能够通过几种OpenGL扩展名,比如表示:
GL_OES_texture_compression_S3TC
GL_EXT_texture_compression_s3tc
GL_EXT_texture_compression_dxt1
GL_EXT_texture_compression_dxt3
GL_EXT_texture_compression_dxt5
3DC - 3DC纹理压缩(3DC)是支持RGB纹理与alpha通道较少广泛使用的格式。这样的格式是由下面OpenGL扩展名来表示:
GL_AMD_compressed_3DC_texture
警告:这些纹理压缩格式不支持的全部设备。对这些格式的支持能够通过制造商和设备而异。有关怎样确定的格式是一个特定的设备上什么纹理压缩的信息,请參阅下一节。
注意:一旦你决定哪些纹理压缩格式的应用程序将支持,确保您在使用清单<支持-GL纹理>申报。
使用此声明同意通过外部服务。如谷歌播放过滤,从而仅安装在支持您的应用要求的格式设备上的应用程序。有关具体信息。请參阅OpenGL的舱单申报。
确定OpenGL扩展
的OpenGL的实现通过Android设备在扩展OpenGL ES的API所支持的方面有所不同。这些扩展包含纹理压缩,但通常还包含其它扩展到OpenGL的功能集。
要确定哪些纹理压缩格式。和其它OpenGL扩展,支持在特定设备上:
执行在目标设备上以下的代码。以确定支持哪些纹理压缩格式:
String extensions = javax.microedition.khronos.opengles.GL10.glGetString( GL10.GL_EXTENSIONS);
阅读本方法的输出,以确定哪些OpenGL扩展支持在设备上。
Android的扩展包(AEP)
该AEP确保您的应用程序支持一套标准化OpenGL扩展超出了OpenGL的3.1规范中描写叙述的一套核心。包装这些扩展一起鼓舞一套一致的跨设备的功能。同一时候同意开发者可以充分利用移动GPU设备的最新作物。
该AEP还改善了图像,渲染存储缓冲器,并在片段着色原子专柜的支持。
对于您的应用程序可以使用的AEP,该应用程序的清单必须声明的AEP是必需的。
此外,平台版本号必须支持它。
申报清单中的AEP要求例如以下:
<uses feature android:name="android.hardware.opengles.aep" android:required="true" />要验证平台版本号支持AEP。使用hasSystemFeature(String)方法。在FEATURE_OPENGLES_EXTENSION_PACK传递作为參数。以下的代码片段显示了怎样做到这一点的样例:
boolean deviceSupportsAEP = getPackageManager().hasSystemFeature (PackageManager.FEATURE_OPENGLES_EXTENSION_PACK);假设该方法返回true。AEP支持。
有关AEP的很多其它信息,请在Khronos的OpenGL ES的注冊表訪问其网页。
检查OpenGL ES版本号
有在Android设备上提供多个版本号的OpenGL ES的。你能够指定你的应用程序须要在你的清单API的最低版本号。但你也可能想利用功能的新的API在同一时间。
比如,对OpenGL ES 3.0 API与2.0版本号的API向后兼容,所以你可能须要编写你的应用程序。以便它使用的OpenGL ES 3.0的功能。但假设3.0 API不回落到2.0 API可用。
利用比你的应用程序清单所需的最低更高版本号的OpenGL ES功能之前,你的应用程序应检查设备上可用的API的版本号。
您能够通过下面两种方式之中的一个进行:
尝试建立更高级别的OpenGL ES上下文(GL上下文),并检查结果。
创建最小支持OpenGL ES的背景和检查版本号价值。
以下的演示样例代码演示了怎样通过创建一个EGLContext和检查结果,检查可用的OpenGL ES版本号。这个样例说明怎样检查的OpenGL ES 3.0的版本号:
private static double glVersion = 3.0; private static class ContextFactory implements GLSurfaceView.EGLContextFactory { private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098; public EGLContext createContext( EGL10 egl, EGLDisplay display, EGLConfig eglConfig) { Log.w(TAG, "creating OpenGL ES " + glVersion + " context"); int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, (int) glVersion, EGL10.EGL_NONE }; // attempt to create a OpenGL ES 3.0 context EGLContext context = egl.eglCreateContext( display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); return context; // returns null if 3.0 is not supported; } }假设上述的createContext()方法,显示返回null,你的代码应该创建一个OpenGL ES 2.0的范围内。而不是和回落到仅仅使用该API。
以下的代码演示样例演示怎样首先创建一个支持的最低上下文。然后检查版本号字符串检查OpenGL ES版本号:
// Create a minimum supported OpenGL ES context, then check: String version = javax.microedition.khronos.opengles.GL10.glGetString( GL10.GL_VERSION); Log.w(TAG, "Version: " + version ); // The version format is displayed as: "OpenGL ES <major>.<minor>" // followed by optional content provided by the implementation.
通过这样的方法,假设您发现该设备支持更高级别的API版本号。您必须销毁最小的OpenGL ES的背景下,并创建一个新的上下文具有较高可用的API版本号。
选择一个OpenGL API版本号
的OpenGL ES 1.0 API的版本号(和1.1扩展),2.0版和3.0版的全部用于创建3D游戏,可视化和用户界面,提供了高性能的图形界面。
图形编程的OpenGL ES 2.0和3.0在非常大程度上是相似的,与代表附加功能的2.0 API的超集3.0版本号。
为OpenGL ES的1.0 / 1.1 API与OpenGL ES的编程2.0和3.0不同显著。因此开发商应该细致考虑開始使用这些API开发之前下面因素:
性能 - 普通情况下。的OpenGL ES 2.0和3.0提供比ES 1.0 / 1.1版本号更快的图形性能。只是,性能差异能够依据您的OpenGL应用程序上,执行在Android设备上因为硬件制造商的实现的OpenGL ES图形管线的不同而有所差异。
设备的兼容性 - 开发人员应该考虑的设备类型,版本号的Android和可用到他们的客户的OpenGL ES版本号。
对于OpenGL的兼容性跨设备的具体信息,请參阅OpenGL的版本号和设备兼容性部分。
编码方便 - OpenGL ES的1.0 / 1.1 API提供了一个固定的功能管线和方便的功能,这是不是在OpenGL ES的2.0或3.0的API可用。
开发谁是新的OpenGL ES可能会发现编码版本号1.0 / 1.1更快,更方便。
图形控制 - 的OpenGL ES 2.0和3.0的API,通过使用着色器提供全然可编程管线提供更高程度的控制。与图形处理管线的更直接的控制,开发人员能够创建效果,将是很困难的使用1.0 / 1.1 API生成。
纹理支持 - 的OpenGL ES 3.0 API拥有纹理压缩了最好的支持。由于它保证了ETC2压缩格式,支持透明的可用性。
在1.x和2.0 API的实现通常包含支持ETC1,可是这纹理格式不支持透明度,所以你通常必须提供资源,通过你的目标设备支持的其它压缩格式。有关具体信息,请參阅纹理压缩支持。
尽管性能,兼容性,便利性,控制等因素都可能影响你的决定,你应该依据你的想法为你的用户提供最佳体验挑一个OpenGL API版本号。